setup.py

import os BASE = "TriggerAgent" dirs_and_files = { # Api "src/TriggerAgent.Api/Controllers": [ "SessionController.cs", "StepController.cs", "UploadController.cs", "ResultController.cs" ], "src/TriggerAgent.Api/Middleware": [ "SessionValidationMiddleware.cs", "StepGuardMiddleware.cs", "ExceptionHandlingMiddleware.cs" ], "src/TriggerAgent.Api/Filters": [ "FileUploadValidationFilter.cs" ], "src/TriggerAgent.Api": [ "Program.cs", "appsettings.json", "TriggerAgent.Api.csproj" ], "src/TriggerAgent.Api/wwwroot": ["index.html"], # Domain "src/TriggerAgent.Domain": ["TriggerAgent.Domain.csproj"], "src/TriggerAgent.Domain/Entities": [ "AuditSession.cs", "TriggerSet.cs", "TriggerDefinition.cs", "ParsedDocument.cs", "StepArtifact.cs", ], "src/TriggerAgent.Domain/Tables": [ "RegulatoryCheckRow.cs", "CreditProtocolRow.cs", "FinancialAnalysisRow.cs", "ConsolidatedReport.cs", ], "src/TriggerAgent.Domain/Enums": [ "StepNumber.cs", "ComplianceStatus.cs", "TriggerStatus.cs", "TriggerType.cs", ], "src/TriggerAgent.Domain/ValueObjects": [ "Kommentar.cs", "RegulatorySource.cs", "FileReference.cs", ], "src/TriggerAgent.Domain/Provenance": [ "Citation.cs", "SnippetHash.cs", "SourceParagraph.cs", "ProvenanceChain.cs", "CitableEntity.cs", ], "src/TriggerAgent.Domain/Contracts": [ "IStepInput.cs", "IStepOutput.cs", "StepContext.cs", ], "src/TriggerAgent.Domain/TaskGraph": [ "TaskNode.cs", "TaskEdge.cs", "TaskGraph.cs", "TaskResult.cs", "TaskStatus.cs", ], "src/TriggerAgent.Domain/Exceptions": [ "StepSequenceViolationException.cs", "SchemaValidationException.cs", "ProvenanceNotFoundException.cs", "DeterminismViolationException.cs", "TaskGraphCycleException.cs", ], # Execution Engine "src/TriggerAgent.ExecutionEngine/Orchestrator": [ "IStepOrchestrator.cs", "StepOrchestrator.cs", "OrchestratorConfig.cs", ], "src/TriggerAgent.ExecutionEngine/DagRunner": [ "IDagRunner.cs", "DagRunner.cs", "DagScheduler.cs", "TaskExecutor.cs", "DagExecutionReport.cs", ], "src/TriggerAgent.ExecutionEngine/TaskHandlers": [ "ITaskHandler.cs", "LlmCallHandler.cs", "DocumentParseHandler.cs", "KnowledgeBaseQueryHandler.cs", "SchemaValidationHandler.cs", "TableConstructionHandler.cs", "ProvenanceAttachmentHandler.cs", "MergeHandler.cs", "PassthroughHandler.cs", ], "src/TriggerAgent.ExecutionEngine/Determinism": [ "IDeterminismGuard.cs", "DeterminismGuard.cs", "RequestFingerprint.cs", "ResponseCache.cs", ], "src/TriggerAgent.ExecutionEngine/Behaviors": [ "ITaskBehavior.cs", "TaskLoggingBehavior.cs", "TaskRetryBehavior.cs", "TaskTimeoutBehavior.cs", "TaskProvenanceBehavior.cs", ], "src/TriggerAgent.ExecutionEngine/StepRegistry": [ "IStepRegistry.cs", "StepRegistry.cs", ], "src/TriggerAgent.ExecutionEngine": [ "ServiceCollectionExtensions.cs", "TriggerAgent.ExecutionEngine.csproj" ], # Knowledge Base "src/TriggerAgent.KnowledgeBase/Corpus": [ "ICorpusStore.cs", "InMemoryCorpusStore.cs", "CorpusLoader.cs", ], "src/TriggerAgent.KnowledgeBase/Documents/EBA_GL_2018_06": [ "full_text.md", "paragraphs.json", "metadata.json", ], "src/TriggerAgent.KnowledgeBase/Documents/CRR_Art178": [ "full_text.md", "paragraphs.json", "metadata.json", ], "src/TriggerAgent.KnowledgeBase/Documents/MaRisk_AT432_BTO12": [ "full_text.md", "paragraphs.json", "metadata.json", ], "src/TriggerAgent.KnowledgeBase/Documents/EBA_GL_2020_06": [ "full_text.md", "paragraphs.json", "metadata.json", ], "src/TriggerAgent.KnowledgeBase/Indexing": [ "IKbIndex.cs", "KeywordIndex.cs", "SectionIndex.cs", "RequirementMapper.cs", ], "src/TriggerAgent.KnowledgeBase/Citation": [ "ICitationBuilder.cs", "CitationBuilder.cs", "CitationFormatter.cs", ], "src/TriggerAgent.KnowledgeBase/Proof": [ "IProofAssembler.cs", "ProofAssembler.cs", "ProofPacket.cs", "ProofValidator.cs", ], "src/TriggerAgent.KnowledgeBase": [ "ServiceCollectionExtensions.cs", "TriggerAgent.KnowledgeBase.csproj" ], # Steps "src/TriggerAgent.Steps": ["TriggerAgent.Steps.csproj"], "src/TriggerAgent.Steps/Step1_Greeting": [ "GreetingStep.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step2_TriggerIntake": [ "TriggerIntakeStep.cs", "TriggerIntakeInput.cs", "TriggerIntakeOutput.cs", "GraphDefinition.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step2_TriggerIntake/Config": [ "TriggerIntakeConfig.cs", ], "src/TriggerAgent.Steps/Step2_TriggerIntake/Adapters": [ "IOcrAdapter.cs", "OcrAdapter.cs", "IDocReaderAdapter.cs", "DocReaderAdapter.cs", ], "src/TriggerAgent.Steps/Step2_TriggerIntake/Tasks": [ "ParseDocumentTask.cs", "ExtractTriggersTask.cs", "ClassifyTriggersTask.cs", "ValidateStructureTask.cs", "PersistTriggerSetTask.cs", ], "src/TriggerAgent.Steps/Step2_TriggerIntake/Prompts": [ "ExtractTriggersPrompt.cs", "ClassifyTriggersPrompt.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck": [ "RegulatoryCheckStep.cs", "RegulatoryCheckInput.cs", "RegulatoryCheckOutput.cs", "GraphDefinition.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck/Config": [ "RegulatoryCheckConfig.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck/Adapters": [ "ILlmAdapter.cs", "LlmAdapter.cs", "IKbAdapter.cs", "KbAdapter.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck/Tasks": [ "LoadTriggerSetTask.cs", "QueryKb_EBA2018Task.cs", "QueryKb_CRR178Task.cs", "QueryKb_MaRiskTask.cs", "QueryKb_EBA2020Task.cs", "MergeKbResultsTask.cs", "CheckCompliance_EBA2018Task.cs", "CheckCompliance_CRR178Task.cs", "CheckCompliance_MaRiskTask.cs", "CheckCompliance_EBA2020Task.cs", "MergeComplianceResultsTask.cs", "AttachProvenanceTask.cs", "ValidateTable1Task.cs", "BuildTable1OutputTask.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck/Prompts": [ "BaseComplianceCheckPrompt.cs", "EBA2018CompliancePrompt.cs", "CRR178CompliancePrompt.cs", "MaRiskCompliancePrompt.cs", "EBA2020CompliancePrompt.cs", ], "src/TriggerAgent.Steps/Step3_RegulatoryCheck/Validation": [ "Table1SchemaValidator.cs", "Table1RowValidator.cs", "Table1ProvenanceValidator.cs", ], "src/TriggerAgent.Steps/Step4_RequestCreditProtocol": [ "RequestCreditProtocolStep.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis": [ "CreditProtocolAnalysisStep.cs", "CreditProtocolInput.cs", "CreditProtocolOutput.cs", "GraphDefinition.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis/Config": [ "CreditProtocolConfig.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis/Adapters": [ "IOcrAdapter.cs", "OcrAdapter.cs", "ILlmAdapter.cs", "LlmAdapter.cs", "IKbAdapter.cs", "KbAdapter.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis/Tasks": [ "LoadTriggerSetTask.cs", "ParseCreditProtocolTask.cs", "ExtractPaymentDelaysTask.cs", "ExtractRatingChangesTask.cs", "ExtractForbearanceMeasuresTask.cs", "ExtractCovenantsTask.cs", "ExtractUnlikelyToPayTask.cs", "MergeExtractionsTask.cs", "MapToTriggerSetTask.cs", "ClassifyActiveInactiveTask.cs", "AttachProvenanceTask.cs", "ValidateTable2Task.cs", "BuildTable2OutputTask.cs", "GenerateBulletSummaryTask.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis/Prompts": [ "BaseIndicatorExtractionPrompt.cs", "PaymentDelayPrompt.cs", "RatingChangePrompt.cs", "ForbearancePrompt.cs", "CovenantPrompt.cs", "UnlikelyToPayPrompt.cs", "TriggerMappingPrompt.cs", "ActiveClassificationPrompt.cs", "BulletSummaryPrompt.cs", ], "src/TriggerAgent.Steps/Step5_CreditProtocolAnalysis/Validation": [ "Table2SchemaValidator.cs", "Table2RowValidator.cs", "TriggerCrossReferenceValidator.cs", "Table2ProvenanceValidator.cs", ], "src/TriggerAgent.Steps/Step6_RequestFinancialStatements": [ "RequestFinancialStatementsStep.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis": [ "FinancialAnalysisStep.cs", "FinancialAnalysisInput.cs", "FinancialAnalysisOutput.cs", "GraphDefinition.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis/Config": [ "FinancialAnalysisConfig.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis/Adapters": [ "IOcrAdapter.cs", "OcrAdapter.cs", "ILlmAdapter.cs", "LlmAdapter.cs", "IKbAdapter.cs", "KbAdapter.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis/Tasks": [ "LoadTriggerSetTask.cs", "ParseFinancialStatementsTask.cs", "ExtractEbitdaTask.cs", "ExtractEquityRatioTask.cs", "ExtractLiquidityTask.cs", "ExtractDebtServiceTask.cs", "ExtractRevenueTask.cs", "MergeFinancialExtractionsTask.cs", "MapToTriggerSetTask.cs", "ClassifyActiveInactiveTask.cs", "AttachProvenanceTask.cs", "ValidateTable3Task.cs", "BuildTable3OutputTask.cs", "GenerateBulletSummaryTask.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis/Prompts": [ "BaseFinancialExtractionPrompt.cs", "EbitdaPrompt.cs", "EquityRatioPrompt.cs", "LiquidityPrompt.cs", "DebtServicePrompt.cs", "RevenuePrompt.cs", "TriggerMappingPrompt.cs", "ActiveClassificationPrompt.cs", "BulletSummaryPrompt.cs", ], "src/TriggerAgent.Steps/Step7_FinancialAnalysis/Validation": [ "Table3SchemaValidator.cs", "Table3RowValidator.cs", "TriggerCrossReferenceValidator.cs", "Table3ProvenanceValidator.cs", ], "src/TriggerAgent.Steps/Step8_ConsolidatedReport": [ "ConsolidatedReportStep.cs", "ConsolidatedInput.cs", "ConsolidatedOutput.cs", "GraphDefinition.cs", "DependencyInjection.cs", ], "src/TriggerAgent.Steps/Step8_ConsolidatedReport/Config": [ "ConsolidatedConfig.cs", ], "src/TriggerAgent.Steps/Step8_ConsolidatedReport/Adapters": [ "ILlmAdapter.cs", "LlmAdapter.cs", ], "src/TriggerAgent.Steps/Step8_ConsolidatedReport/Tasks": [ "LoadAllTablesTask.cs", "LoadBulletSummariesTask.cs", "AssessRegulatoryFulfillmentTask.cs", "AssessTriggerCoverageTask.cs", "AssessImplementationGapsTask.cs", "MergeAssessmentsTask.cs", "AttachAllProvenanceTask.cs", "AssembleReportTask.cs", "ValidateReportTask.cs", ], "src/TriggerAgent.Steps/Step8_ConsolidatedReport/Prompts": [ "RegulatoryFulfillmentPrompt.cs", "TriggerCoveragePrompt.cs", "ImplementationGapPrompt.cs", ], # Infrastructure "src/TriggerAgent.Infrastructure/Ocr": [ "IronOcrEngine.cs", "TesseractOcrEngine.cs", "OcrEngineFactory.cs", ], "src/TriggerAgent.Infrastructure/DocumentReading": [ "PdfDocumentReader.cs", "DocxDocumentReader.cs", "XlsxDocumentReader.cs", "TextDocumentReader.cs", "DocumentReaderFactory.cs", ], "src/TriggerAgent.Infrastructure/Llm": [ "AnthropicLlmClient.cs", "LlmConfig.cs", "LlmResponseParser.cs", "LlmRetryPolicy.cs", ], "src/TriggerAgent.Infrastructure/Storage": [ "InMemorySessionStore.cs", "InMemoryArtifactStore.cs", "FileSystemTempStore.cs", ], "src/TriggerAgent.Infrastructure": [ "ServiceCollectionExtensions.cs", "TriggerAgent.Infrastructure.csproj" ], # Shared Kernel "src/TriggerAgent.SharedKernel/Interfaces": [ "IOcrEngine.cs", "IDocumentReader.cs", "ILlmClient.cs", "ISessionStore.cs", "IArtifactStore.cs", "IRegulatoryKb.cs", "ICitationBuilder.cs", "IProofAssembler.cs", ], "src/TriggerAgent.SharedKernel": [ "LlmParams.cs", "TriggerAgent.SharedKernel.csproj" ], "src/TriggerAgent.SharedKernel/Extensions": [ "StringExtensions.cs", "JsonExtensions.cs", "HashExtensions.cs", ], "src/TriggerAgent.SharedKernel/Guards": ["Guard.cs"], # Tests "tests/TriggerAgent.Domain.Tests": [ "TriggerAgent.Domain.Tests.csproj" ], "tests/TriggerAgent.ExecutionEngine.Tests": [ "DagRunnerTests.cs", "DeterminismGuardTests.cs", "TaskHandlerTests.cs", "TriggerAgent.ExecutionEngine.Tests.csproj" ], "tests/TriggerAgent.KnowledgeBase.Tests": [ "CorpusLoaderTests.cs", "KeywordIndexTests.cs", "CitationBuilderTests.cs", "ProofValidatorTests.cs", "TriggerAgent.KnowledgeBase.Tests.csproj" ], "tests/TriggerAgent.Steps.Tests": [ "TriggerAgent.Steps.Tests.csproj" ], "tests/TriggerAgent.Steps.Tests/Step2": [ "GraphDefinitionTests.cs", "ExtractTriggersTaskTests.cs", ], "tests/TriggerAgent.Steps.Tests/Step2/Fixtures": [], "tests/TriggerAgent.Steps.Tests/Step3": [ "GraphDefinitionTests.cs", "ComplianceCheckTaskTests.cs", "ProvenanceAttachmentTests.cs", ], "tests/TriggerAgent.Steps.Tests/Step3/Fixtures": [], "tests/TriggerAgent.Steps.Tests/Step5": [], "tests/TriggerAgent.Steps.Tests/Step7": [], "tests/TriggerAgent.Steps.Tests/Step8": [], "tests/TriggerAgent.Integration.Tests": [ "FullPipelineTests.cs", "DeterminismTests.cs", "TriggerAgent.Integration.Tests.csproj" ], } root_files = [ "TriggerAgent.sln", "Directory.Build.props", "Directory.Packages.props", ".editorconfig", ".gitignore" ] def build(): os.makedirs(BASE, exist_ok=True) for f in root_files: open(os.path.join(BASE, f), "a").close() for dir_path, files in dirs_and_files.items(): full_dir = os.path.join(BASE, dir_path) os.makedirs(full_dir, exist_ok=True) for f in files: open(os.path.join(full_dir, f), "a").close() if __name__ == "__main__": build() total_dirs = 0 total_files = 0 for root, dirs, files in os.walk(BASE): total_dirs += len(dirs) total_files += len(files) print(f"Created {total_dirs} directories and {total_files} files under {BASE}/")

1. src/TriggerAgent.Domain/TriggerAgent.Domain.csproj

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>

2. src/TriggerAgent.Domain/Enums/StepNumber.cs

namespace TriggerAgent.Domain.Enums; public enum StepNumber { Step1_Greeting = 1, Step2_TriggerIntake = 2, Step3_RegulatoryCheck = 3, Step4_RequestCreditProtocol = 4, Step5_CreditProtocolAnalysis = 5, Step6_RequestFinancialStatements = 6, Step7_FinancialAnalysis = 7, Step8_ConsolidatedReport = 8 }

3. src/TriggerAgent.Domain/Entities/AuditSession.cs

namespace TriggerAgent.Domain.Entities; using TriggerAgent.Domain.Enums; using TriggerAgent.Domain.Exceptions; public class AuditSession { public Guid SessionId { get; private set; } public StepNumber CurrentStep { get; private set; } public DateTime CreatedAt { get; private set; } public bool IsComplete { get; private set; } private readonly Dictionary<string, object> _artifacts = new(); public AuditSession() { SessionId = Guid.NewGuid(); CurrentStep = StepNumber.Step1_Greeting; CreatedAt = DateTime.UtcNow; IsComplete = false; } public void AdvanceTo(StepNumber next) { if (IsComplete) throw new StepSequenceViolationException(CurrentStep, next, "Session already complete."); int expected = (int)CurrentStep + 1; if ((int)next != expected) throw new StepSequenceViolationException(CurrentStep, next, $"Expected step {expected}, got {(int)next}."); CurrentStep = next; if (next == StepNumber.Step8_ConsolidatedReport) IsComplete = true; } public void StoreArtifact(string key, object value) => _artifacts[key] = value; public T? GetArtifact<T>(string key) where T : class => _artifacts.TryGetValue(key, out var val) ? val as T : null; public bool HasArtifact(string key) => _artifacts.ContainsKey(key); }

4. src/TriggerAgent.Domain/Exceptions/StepSequenceViolationException.cs

namespace TriggerAgent.Domain.Exceptions; using TriggerAgent.Domain.Enums; public class StepSequenceViolationException : Exception { public StepNumber FromStep { get; } public StepNumber ToStep { get; } public StepSequenceViolationException(StepNumber from, StepNumber to, string reason) : base($"Invalid transition from {from} to {to}: {reason}") { FromStep = from; ToStep = to; } }

5. src/TriggerAgent.Domain/Contracts/IStepInput.cs

namespace TriggerAgent.Domain.Contracts; public interface IStepInput { } public sealed class EmptyInput : IStepInput { public static readonly EmptyInput Instance = new(); }

6. src/TriggerAgent.Domain/Contracts/IStepOutput.cs

namespace TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public interface IStepOutput { StepNumber Step { get; } string DisplayPayload { get; } }

7. src/TriggerAgent.Domain/Contracts/IStep.cs

namespace TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public interface IStep { StepNumber StepNumber { get; } Task<IStepOutput> ExecuteAsync(StepContext context); }

8. src/TriggerAgent.Domain/Contracts/StepContext.cs

namespace TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Entities; public sealed class StepContext { public AuditSession Session { get; } public IStepInput Input { get; } public StepContext(AuditSession session, IStepInput input) { Session = session ?? throw new ArgumentNullException(nameof(session)); Input = input ?? throw new ArgumentNullException(nameof(input)); } }

9. src/TriggerAgent.SharedKernel/TriggerAgent.SharedKernel.csproj

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TriggerAgent.Domain\TriggerAgent.Domain.csproj" /> </ItemGroup> </Project>

10. src/TriggerAgent.SharedKernel/Interfaces/ISessionStore.cs

namespace TriggerAgent.SharedKernel.Interfaces; using TriggerAgent.Domain.Entities; public interface ISessionStore { Task<AuditSession> CreateAsync(); Task<AuditSession?> GetAsync(Guid sessionId); Task SaveAsync(AuditSession session); }

11. src/TriggerAgent.ExecutionEngine/TriggerAgent.ExecutionEngine.csproj

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TriggerAgent.Domain\TriggerAgent.Domain.csproj" /> <ProjectReference Include="..\TriggerAgent.SharedKernel\TriggerAgent.SharedKernel.csproj" /> </ItemGroup> </Project>

12. src/TriggerAgent.ExecutionEngine/StepRegistry/IStepRegistry.cs

namespace TriggerAgent.ExecutionEngine.StepRegistry; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public interface IStepRegistry { void Register(IStep step); IStep Resolve(StepNumber stepNumber); }

13. src/TriggerAgent.ExecutionEngine/StepRegistry/StepRegistry.cs

namespace TriggerAgent.ExecutionEngine.StepRegistry; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public sealed class StepRegistry : IStepRegistry { private readonly Dictionary<StepNumber, IStep> _steps = new(); public void Register(IStep step) { if (_steps.ContainsKey(step.StepNumber)) throw new InvalidOperationException($"Step {step.StepNumber} already registered."); _steps[step.StepNumber] = step; } public IStep Resolve(StepNumber stepNumber) { if (!_steps.TryGetValue(stepNumber, out var step)) throw new KeyNotFoundException($"No step registered for {stepNumber}."); return step; } }

14. src/TriggerAgent.ExecutionEngine/Orchestrator/IStepOrchestrator.cs

namespace TriggerAgent.ExecutionEngine.Orchestrator; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public interface IStepOrchestrator { Task<IStepOutput> ExecuteAsync(Guid sessionId, StepNumber step, IStepInput input); }

15. src/TriggerAgent.ExecutionEngine/Orchestrator/StepOrchestrator.cs

namespace TriggerAgent.ExecutionEngine.Orchestrator; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; using TriggerAgent.ExecutionEngine.StepRegistry; using TriggerAgent.SharedKernel.Interfaces; public sealed class StepOrchestrator : IStepOrchestrator { private readonly IStepRegistry _registry; private readonly ISessionStore _sessionStore; public StepOrchestrator(IStepRegistry registry, ISessionStore sessionStore) { _registry = registry; _sessionStore = sessionStore; } public async Task<IStepOutput> ExecuteAsync(Guid sessionId, StepNumber step, IStepInput input) { var session = await _sessionStore.GetAsync(sessionId) ?? throw new KeyNotFoundException($"Session {sessionId} not found."); if (session.CurrentStep != step) throw new InvalidOperationException( $"Session is at {session.CurrentStep}, cannot execute {step}."); var handler = _registry.Resolve(step); var context = new StepContext(session, input); var output = await handler.ExecuteAsync(context); await _sessionStore.SaveAsync(session); return output; } }

16. src/TriggerAgent.Infrastructure/TriggerAgent.Infrastructure.csproj

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TriggerAgent.Domain\TriggerAgent.Domain.csproj" /> <ProjectReference Include="..\TriggerAgent.SharedKernel\TriggerAgent.SharedKernel.csproj" /> </ItemGroup> </Project>

17. src/TriggerAgent.Infrastructure/Storage/InMemorySessionStore.cs

namespace TriggerAgent.Infrastructure.Storage; using System.Collections.Concurrent; using TriggerAgent.Domain.Entities; using TriggerAgent.SharedKernel.Interfaces; public sealed class InMemorySessionStore : ISessionStore { private readonly ConcurrentDictionary<Guid, AuditSession> _store = new(); public Task<AuditSession> CreateAsync() { var session = new AuditSession(); _store[session.SessionId] = session; return Task.FromResult(session); } public Task<AuditSession?> GetAsync(Guid sessionId) { _store.TryGetValue(sessionId, out var session); return Task.FromResult(session); } public Task SaveAsync(AuditSession session) { _store[session.SessionId] = session; return Task.CompletedTask; } }

18. src/TriggerAgent.Steps/TriggerAgent.Steps.csproj

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TriggerAgent.Domain\TriggerAgent.Domain.csproj" /> <ProjectReference Include="..\TriggerAgent.ExecutionEngine\TriggerAgent.ExecutionEngine.csproj" /> <ProjectReference Include="..\TriggerAgent.SharedKernel\TriggerAgent.SharedKernel.csproj" /> </ItemGroup> </Project>

19. src/TriggerAgent.Steps/Step1_Greeting/GreetingStep.cs

namespace TriggerAgent.Steps.Step1_Greeting; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; public sealed class GreetingOutput : IStepOutput { public StepNumber Step => StepNumber.Step1_Greeting; public string DisplayPayload { get; } public string NextAction { get; } public GreetingOutput(string payload, string nextAction) { DisplayPayload = payload; NextAction = nextAction; } } public sealed class GreetingStep : IStep { private const string Greeting = "Willkommen beim Trigger-Set Check Agent. " + "Bitte laden Sie Ihr Trigger-Set hoch (PDF, Word, Excel oder Text)."; private const string Action = "UPLOAD_TRIGGER_SET"; public StepNumber StepNumber => StepNumber.Step1_Greeting; public Task<IStepOutput> ExecuteAsync(StepContext context) { var output = new GreetingOutput(Greeting, Action); return Task.FromResult<IStepOutput>(output); } }

20. src/TriggerAgent.Api/TriggerAgent.Api.csproj

<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TriggerAgent.Domain\TriggerAgent.Domain.csproj" /> <ProjectReference Include="..\TriggerAgent.SharedKernel\TriggerAgent.SharedKernel.csproj" /> <ProjectReference Include="..\TriggerAgent.ExecutionEngine\TriggerAgent.ExecutionEngine.csproj" /> <ProjectReference Include="..\TriggerAgent.Infrastructure\TriggerAgent.Infrastructure.csproj" /> <ProjectReference Include="..\TriggerAgent.Steps\TriggerAgent.Steps.csproj" /> </ItemGroup> </Project>

21. src/TriggerAgent.Api/Controllers/Dto/ApiResponse.cs

namespace TriggerAgent.Api.Controllers.Dto; using TriggerAgent.Domain.Enums; public sealed class ApiResponse<T> { public bool Success { get; init; } public T? Data { get; init; } public string? Error { get; init; } public StepNumber CurrentStep { get; init; } public Guid SessionId { get; init; } public static ApiResponse<T> Ok(T data, Guid sessionId, StepNumber step) => new() { Success = true, Data = data, SessionId = sessionId, CurrentStep = step }; public static ApiResponse<T> Fail(string error, Guid sessionId, StepNumber step) => new() { Success = false, Error = error, SessionId = sessionId, CurrentStep = step }; } public sealed class StepPayload { public string Message { get; init; } = string.Empty; public string NextAction { get; init; } = string.Empty; }

22. src/TriggerAgent.Api/Controllers/SessionController.cs

namespace TriggerAgent.Api.Controllers; using Microsoft.AspNetCore.Mvc; using TriggerAgent.Api.Controllers.Dto; using TriggerAgent.Domain.Contracts; using TriggerAgent.Domain.Enums; using TriggerAgent.ExecutionEngine.Orchestrator; using TriggerAgent.SharedKernel.Interfaces; using TriggerAgent.Steps.Step1_Greeting; [ApiController] [Route("api/[controller]")] public sealed class SessionController : ControllerBase { private readonly ISessionStore _sessionStore; private readonly IStepOrchestrator _orchestrator; public SessionController(ISessionStore sessionStore, IStepOrchestrator orchestrator) { _sessionStore = sessionStore; _orchestrator = orchestrator; } [HttpPost("start")] public async Task<IActionResult> StartSession() { var session = await _sessionStore.CreateAsync(); var output = await _orchestrator.ExecuteAsync( session.SessionId, StepNumber.Step1_Greeting, EmptyInput.Instance); var greeting = output as GreetingOutput; var payload = new StepPayload { Message = greeting?.DisplayPayload ?? output.DisplayPayload, NextAction = greeting?.NextAction ?? string.Empty }; return Ok(ApiResponse<StepPayload>.Ok(payload, session.SessionId, output.Step)); } [HttpGet("{sessionId:guid}")] public async Task<IActionResult> GetSession(Guid sessionId) { var session = await _sessionStore.GetAsync(sessionId); if (session is null) return NotFound(ApiResponse<object>.Fail("Session not found.", sessionId, 0)); var payload = new StepPayload { Message = $"Session active at {session.CurrentStep}.", NextAction = session.IsComplete ? "NONE" : "CONTINUE" }; return Ok(ApiResponse<StepPayload>.Ok(payload, session.SessionId, session.CurrentStep)); } }

23. src/TriggerAgent.Api/Program.cs

using TriggerAgent.Domain.Contracts; using TriggerAgent.ExecutionEngine.Orchestrator; using TriggerAgent.ExecutionEngine.StepRegistry; using TriggerAgent.Infrastructure.Storage; using TriggerAgent.SharedKernel.Interfaces; using TriggerAgent.Steps.Step1_Greeting; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddSingleton<ISessionStore, InMemorySessionStore>(); var registry = new StepRegistry(); registry.Register(new GreetingStep()); builder.Services.AddSingleton<IStepRegistry>(registry); builder.Services.AddSingleton<IStepOrchestrator>(new StepOrchestrator(registry, builder.Services.BuildServiceProvider().GetRequiredService<ISessionStore>())); builder.Services.AddCors(opts => opts.AddDefaultPolicy(p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader())); var app = builder.Build(); app.UseCors(); app.UseStaticFiles(); app.MapControllers(); app.MapFallbackToFile("index.html"); app.Run();

24. src/TriggerAgent.Api/wwwroot/index.html

<!DOCTYPE html><html lang="de"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Trigger-Set Check Agent</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, sans-serif; background: #0f1117; color: #e1e3e8; } .app { max-width: 860px; margin: 0 auto; padding: 24px; } .header { padding: 16px 0; border-bottom: 1px solid #2a2d35; margin-bottom: 24px; } .header h1 { font-size: 18px; font-weight: 600; } .step-badge { display: inline-block; background: #1e3a5f; color: #6cb4ee; padding: 4px 12px; border-radius: 4px; font-size: 13px; margin-top: 8px; } .chat-area { min-height: 200px; } .message { background: #1a1d24; border: 1px solid #2a2d35; border-radius: 8px; padding: 16px; margin-bottom: 12px; } .message .role { font-size: 12px; color: #6c7280; margin-bottom: 6px; text-transform: uppercase; } .message .text { font-size: 15px; line-height: 1.6; } .upload-zone { border: 2px dashed #2a2d35; border-radius: 8px; padding: 32px; text-align: center; color: #6c7280; margin-top: 16px; display: none; } .upload-zone.visible { display: block; } .status-bar { margin-top: 16px; font-size: 12px; color: #4a4d55; } .error { color: #f87171; background: #1a1d24; padding: 12px; border-radius: 8px; margin-top: 12px; display: none; } </style></head><body> <div class="app"> <div class="header"> <h1>Trigger-Set Check Agent</h1> <div class="step-badge" id="stepBadge">Initialisierung...</div> </div> <div class="chat-area" id="chatArea"></div> <div class="upload-zone" id="uploadZone"> Trigger-Set hier hochladen (PDF, Word, Excel, Text) </div> <div class="error" id="errorBox"></div> <div class="status-bar" id="statusBar"></div> </div> <script> const API_BASE = '/api/session'; const state = { sessionId: null, currentStep: null }; function addMessage(role, text) { const area = document.getElementById('chatArea'); const msg = document.createElement('div'); msg.className = 'message'; msg.innerHTML = `<div class="role">${role}</div><div class="text">${text}</div>`; area.appendChild(msg); } function updateBadge(step) { document.getElementById('stepBadge').textContent = `Schritt ${step}`; } function showUpload(visible) { document.getElementById('uploadZone').classList.toggle('visible', visible); } function showError(msg) { const box = document.getElementById('errorBox'); box.textContent = msg; box.style.display = msg ? 'block' : 'none'; } function updateStatus(msg) { document.getElementById('statusBar').textContent = msg; } async function startSession() { try { updateStatus('Verbindung wird hergestellt...'); const res = await fetch(`${API_BASE}/start`, { method: 'POST' }); const json = await res.json(); if (!json.success) { showError(json.error); return; } state.sessionId = json.sessionId; state.currentStep = json.currentStep; updateBadge(json.currentStep); addMessage('Agent', json.data.message); if (json.data.nextAction === 'UPLOAD_TRIGGER_SET') showUpload(true); updateStatus(`Session: ${json.sessionId.substring(0, 8)}...`); } catch (e) { showError(`Verbindungsfehler: ${e.message}`); } } startSession(); </script></body></html>

25. TriggerAgent.sln (root)

Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.Domain", "src\TriggerAgent.Domain\TriggerAgent.Domain.csproj", "{A1111111-1111-1111-1111-111111111111}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.SharedKernel", "src\TriggerAgent.SharedKernel\TriggerAgent.SharedKernel.csproj", "{B2222222-2222-2222-2222-222222222222}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.ExecutionEngine", "src\TriggerAgent.ExecutionEngine\TriggerAgent.ExecutionEngine.csproj", "{C3333333-3333-3333-3333-333333333333}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.Infrastructure", "src\TriggerAgent.Infrastructure\TriggerAgent.Infrastructure.csproj", "{D4444444-4444-4444-4444-444444444444}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.Steps", "src\TriggerAgent.Steps\TriggerAgent.Steps.csproj", "{E5555555-5555-5555-5555-555555555555}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriggerAgent.Api", "src\TriggerAgent.Api\TriggerAgent.Api.csproj", "{F6666666-6666-6666-6666-666666666666}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A1111111-1111-1111-1111-111111111111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A1111111-1111-1111-1111-111111111111}.Debug|Any CPU.Build.0 = Debug|Any CPU {B2222222-2222-2222-2222-222222222222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B2222222-2222-2222-2222-222222222222}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3333333-3333-3333-3333-333333333333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3333333-3333-3333-3333-333333333333}.Debug|Any CPU.Build.0 = Debug|Any CPU {D4444444-4444-4444-4444-444444444444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D4444444-4444-4444-4444-444444444444}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5555555-5555-5555-5555-555555555555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5555555-5555-5555-5555-555555555555}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6666666-6666-6666-6666-666666666666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6666666-6666-6666-6666-666666666666}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection EndGlobal