diff --git a/.github/agents.md b/.github/agents.md index d404074..492533b 100644 --- a/.github/agents.md +++ b/.github/agents.md @@ -42,3 +42,7 @@ AI-generated changes should: - Follow repository naming and style conventions. - Include appropriate tests. - Keep documentation aligned with implementation. + +## Source Control Workflow +- Leave all changes local and uncommitted. Do not run `git commit`, `git push`, or open pull requests; the maintainer reviews the uncommitted diff first and then commits, pushes, and opens the PR. +- Do not create or switch branches unless asked. Summarize what changed so the diff can be reviewed. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c7af2b1..4a7e10c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -60,4 +60,8 @@ - Prefer Blazor components over raw HTML to enhance maintainability and reusability. - Implement SEO and GEO optimization support by using semantic headings (H1, H2) while minimizing direct HTML usage. - Prioritize root-cause fixes over brute-force styling overrides and adhere to global Blazor/Fluent UI conventions. Verify behavior against current component rendering. -- Use Blazor/Fluent component properties over CSS for layout/styling because CSS is harder and more brittle to maintain. \ No newline at end of file +- Use Blazor/Fluent component properties over CSS for layout/styling because CSS is harder and more brittle to maintain. + +## Source Control Workflow +- Leave all changes local and uncommitted. Do not run `git commit`, `git push`, or open pull requests; the maintainer reviews the uncommitted diff first and then commits, pushes, and opens the PR. +- Do not create or switch branches unless asked. Summarize what changed so the diff can be reviewed. diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9fc203f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.defaultSolution": "Goodtocode.AgentFramework.Web.slnx" +} \ No newline at end of file diff --git a/README.md b/README.md index ba4b83e..20c76f8 100644 --- a/README.md +++ b/README.md @@ -411,8 +411,11 @@ Execution") for the full entity model. ### Repeatability: Rerun / Recall / Replay -Every `Run*PlaybookCommand` accepts a `PlaybookReplayMode` (from -`Goodtocode.Agents.Playbook.Execution`) plus an optional `SourceExecutionId`: +Every `Run*PlaybookCommand` accepts a Governance `RepeatMode` (from +`Goodtocode.Agents.Governance.Domain`, available transitively through +`Goodtocode.Agents.Playbook`) plus an optional `SourceExecutionId`. The app references only +Playbook; it builds a `PlaybookExecutionRequest` directly, with no mappers. See +[feature-playbook-repeatability.md](./docs/product/features/feature-playbook-repeatability.md): - **Rerun** (default) — a fresh execution: Collect, Evaluate, and Record all run against new input. This is the only mode available on a Playbook's first execution. diff --git a/buildout.txt b/buildout.txt deleted file mode 100644 index b4f612f..0000000 --- a/buildout.txt +++ /dev/null @@ -1,6 +0,0 @@ - -Build succeeded. - 0 Warning(s) - 0 Error(s) - -Time Elapsed 00:00:03.24 diff --git a/buildout2.txt b/buildout2.txt deleted file mode 100644 index 326079a..0000000 --- a/buildout2.txt +++ /dev/null @@ -1,101 +0,0 @@ -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(109,71): warning CS8601: Possible null reference assignment. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(47,82): error CS1503: Argument 3: cannot convert from 'System.Threading.CancellationToken' to 'string?' [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(102,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(22,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(32,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(81,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(205,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsListAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(55,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(62,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(77,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(163,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(168,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(173,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(350,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.BuildActorSelectionMarkdown(Guid, IReadOnlyList)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(380,9): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.SelectActorAsync(Guid, Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(416,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsForSelectedActorAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(54,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(72,21): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(82,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(27,9): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(38,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(21,87): warning CA1068: Method 'Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution.PlaybookWorkflowGraphExecutor.ExecuteAsync(Goodtocode.Agents.Playbook.Execution.PlaybookIdentity, Goodtocode.Agents.Playbook.Steps.ICollectStepTool, Goodtocode.Agents.Playbook.Steps.IEvaluateStepTool, Goodtocode.Agents.Playbook.Steps.IRecordStepTool, TCollectInput, System.Threading.CancellationToken, Goodtocode.Agents.Playbook.Execution.IPlaybookStepActivityRecorder?)' should take CancellationToken as the last parameter (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1068) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(329,116): warning CA1859: Change type of parameter 'actors' from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.List' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\IntentTokenMatcher.cs(10,65): warning CA1859: Change type of field 'Aliases' from 'System.Collections.Generic.IReadOnlyDictionary' to 'System.Collections.Generic.Dictionary' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] - -Build FAILED. - -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(109,71): warning CS8601: Possible null reference assignment. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(102,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(22,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(32,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(81,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(205,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsListAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(55,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(62,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(77,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(163,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(168,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(173,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(350,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.BuildActorSelectionMarkdown(Guid, IReadOnlyList)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(380,9): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.SelectActorAsync(Guid, Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(416,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsForSelectedActorAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(54,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(72,21): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(82,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(27,9): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(38,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(21,87): warning CA1068: Method 'Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution.PlaybookWorkflowGraphExecutor.ExecuteAsync(Goodtocode.Agents.Playbook.Execution.PlaybookIdentity, Goodtocode.Agents.Playbook.Steps.ICollectStepTool, Goodtocode.Agents.Playbook.Steps.IEvaluateStepTool, Goodtocode.Agents.Playbook.Steps.IRecordStepTool, TCollectInput, System.Threading.CancellationToken, Goodtocode.Agents.Playbook.Execution.IPlaybookStepActivityRecorder?)' should take CancellationToken as the last parameter (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1068) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(329,116): warning CA1859: Change type of parameter 'actors' from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.List' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\IntentTokenMatcher.cs(10,65): warning CA1859: Change type of field 'Aliases' from 'System.Collections.Generic.IReadOnlyDictionary' to 'System.Collections.Generic.Dictionary' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(47,82): error CS1503: Argument 3: cannot convert from 'System.Threading.CancellationToken' to 'string?' [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] - 46 Warning(s) - 1 Error(s) - -Time Elapsed 00:00:02.66 diff --git a/buildout3.txt b/buildout3.txt deleted file mode 100644 index 473810b..0000000 --- a/buildout3.txt +++ /dev/null @@ -1,101 +0,0 @@ -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(47,37): warning CS8714: The type 'TCollectInput' cannot be used as type parameter 'TInput' in the generic type or method 'InProcessExecution.RunAsync(Workflow, TInput, string?, CancellationToken)'. Nullability of type argument 'TCollectInput' doesn't match 'notnull' constraint. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(109,71): warning CS8601: Possible null reference assignment. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(55,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(62,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(22,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(32,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(81,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(102,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(21,87): warning CA1068: Method 'Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution.PlaybookWorkflowGraphExecutor.ExecuteAsync(Goodtocode.Agents.Playbook.Execution.PlaybookIdentity, Goodtocode.Agents.Playbook.Steps.ICollectStepTool, Goodtocode.Agents.Playbook.Steps.IEvaluateStepTool, Goodtocode.Agents.Playbook.Steps.IRecordStepTool, TCollectInput, System.Threading.CancellationToken, Goodtocode.Agents.Playbook.Execution.IPlaybookStepActivityRecorder?)' should take CancellationToken as the last parameter (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1068) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(205,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsListAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(77,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(163,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(168,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(173,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(27,9): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(38,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(54,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(72,21): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(82,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(350,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.BuildActorSelectionMarkdown(Guid, IReadOnlyList)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(380,9): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.SelectActorAsync(Guid, Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\IntentTokenMatcher.cs(10,65): warning CA1859: Change type of field 'Aliases' from 'System.Collections.Generic.IReadOnlyDictionary' to 'System.Collections.Generic.Dictionary' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(416,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsForSelectedActorAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(329,116): warning CA1859: Change type of parameter 'actors' from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.List' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] - -Build succeeded. - -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(47,37): warning CS8714: The type 'TCollectInput' cannot be used as type parameter 'TInput' in the generic type or method 'InProcessExecution.RunAsync(Workflow, TInput, string?, CancellationToken)'. Nullability of type argument 'TCollectInput' doesn't match 'notnull' constraint. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(109,71): warning CS8601: Possible null reference assignment. [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(55,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(62,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(22,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(32,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(73,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\IntentEmbeddingInitializationService.cs(81,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(102,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Execution\PlaybookWorkflowGraphExecutor.cs(21,87): warning CA1068: Method 'Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution.PlaybookWorkflowGraphExecutor.ExecuteAsync(Goodtocode.Agents.Playbook.Execution.PlaybookIdentity, Goodtocode.Agents.Playbook.Steps.ICollectStepTool, Goodtocode.Agents.Playbook.Steps.IEvaluateStepTool, Goodtocode.Agents.Playbook.Steps.IRecordStepTool, TCollectInput, System.Threading.CancellationToken, Goodtocode.Agents.Playbook.Execution.IPlaybookStepActivityRecorder?)' should take CancellationToken as the last parameter (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1068) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(205,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsListAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(77,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(83,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(153,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(163,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(168,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Embeddings\AzureOpenAiEmbeddingGenerator.cs(173,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(27,9): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogDebug(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\HybridIntentClassifier.cs(38,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\SemanticIntentClassifier.cs(50,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(114,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(132,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(150,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(167,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ConfigureServices.cs(182,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\NoOpWebSearchProvider.cs(13,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1873: Evaluation of this argument may be expensive and unnecessary if logging is disabled (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(30,13): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(54,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, Exception?, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(72,21): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogWarning(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Providers\BingSearchProvider.cs(82,17): warning CA1848: For improved performance, use the LoggerMessage delegates instead of calling 'LoggerExtensions.LogError(ILogger, string?, params object?[])' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1848) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(350,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.BuildActorSelectionMarkdown(Guid, IReadOnlyList)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(380,9): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.SelectActorAsync(Guid, Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Intents\IntentTokenMatcher.cs(10,65): warning CA1859: Change type of field 'Aliases' from 'System.Collections.Generic.IReadOnlyDictionary' to 'System.Collections.Generic.Dictionary' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(416,13): warning CA1305: The behavior of 'StringBuilder.AppendLine(ref StringBuilder.AppendInterpolatedStringHandler)' could vary based on the current user's locale settings. Replace this call in 'ChatMessageIntentRouter.QueryChatSessionsForSelectedActorAsync(Guid, CancellationToken)' with a call to 'StringBuilder.AppendLine(IFormatProvider, ref StringBuilder.AppendInterpolatedStringHandler)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] -D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\ChatMessageIntentRouter.cs(329,116): warning CA1859: Change type of parameter 'actors' from 'System.Collections.Generic.IReadOnlyList' to 'System.Collections.Generic.List' for improved performance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1859) [D:\Source\goodtocode\agent-framework-quick-start\src\Infrastructure.AgentFramework\Infrastructure.AgentFramework.csproj] - 47 Warning(s) - 0 Error(s) - -Time Elapsed 00:00:03.21 diff --git a/docs/product/features/feature-playbook-repeatability.md b/docs/product/features/feature-playbook-repeatability.md new file mode 100644 index 0000000..32f3afe --- /dev/null +++ b/docs/product/features/feature-playbook-repeatability.md @@ -0,0 +1,19 @@ +# Feature: Playbook Repeatability (Rerun / Recall / Replay) + +## Overview +Every example playbook "run" endpoint can repeat a prior execution. Repeat semantics come from `Goodtocode.Agents.Governance`, executed through `Goodtocode.Agents.Playbook`. This app references only Playbook and uses both concepts directly, with no mappers. + +## Behavior +| Mode | What runs | Source needed | +|------|-----------|---------------| +| Rerun | Collect, Evaluate, Record against live data | no | +| Replay | Evaluate and Record on the recorded evidence | yes | +| Recall | Nothing; the recorded result is returned | yes | + +The source is the given `SourceExecutionId`, otherwise the user's latest execution of the playbook. A missing source returns Not Found; a source without recorded evidence/finding returns Conflict. + +## Where +`PlaybookRepeatCoordinator` resolves the source and builds the `PlaybookExecutionRequest`; `PlaybookWorkflowGraphExecutor` plans actions through `IRepeatPolicy`. + +## Tests +`src/Tests.Integration/Playbooks/PlaybookRepeatability.feature` (Reqnroll) and `PlaybookReplayTests.cs`. diff --git a/src/Core.Application/ConfigureServices.cs b/src/Core.Application/ConfigureServices.cs index 167ac6a..ddb929e 100644 --- a/src/Core.Application/ConfigureServices.cs +++ b/src/Core.Application/ConfigureServices.cs @@ -29,6 +29,8 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddSingleton(); services.AddSingleton(); + services.AddGovernanceRepeatability(); + services.AddScoped(); services.AddSingleton(); services.AddScoped(); services.AddScoped(); diff --git a/src/Core.Application/Core.Application.csproj b/src/Core.Application/Core.Application.csproj index 3517c3f..dc3b106 100644 --- a/src/Core.Application/Core.Application.csproj +++ b/src/Core.Application/Core.Application.csproj @@ -21,13 +21,12 @@ - - + - - - + + + diff --git a/src/Core.Application/Playbooks/Essay/EvaluateEssayCommand.cs b/src/Core.Application/Playbooks/Essay/EvaluateEssayCommand.cs index 4f42860..8b3d011 100644 --- a/src/Core.Application/Playbooks/Essay/EvaluateEssayCommand.cs +++ b/src/Core.Application/Playbooks/Essay/EvaluateEssayCommand.cs @@ -17,7 +17,7 @@ public interface IEssayEvaluationRunner Task> EvaluateAsync( string essayText, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null); + PlaybookExecutionRequest? request = null); } /// diff --git a/src/Core.Application/Playbooks/Essay/RunEssayPlaybookCommand.cs b/src/Core.Application/Playbooks/Essay/RunEssayPlaybookCommand.cs index 4c05675..4aec7a4 100644 --- a/src/Core.Application/Playbooks/Essay/RunEssayPlaybookCommand.cs +++ b/src/Core.Application/Playbooks/Essay/RunEssayPlaybookCommand.cs @@ -1,4 +1,6 @@ using Goodtocode.AgentFramework.Core.Application.Playbooks.Persistence; +using Goodtocode.AgentFramework.Core.Application.Playbooks.Repeatability; +using Goodtocode.Agents.Governance.Domain; using Goodtocode.Agents.Playbook.Execution; namespace Goodtocode.AgentFramework.Core.Application.Playbooks.Essay; @@ -16,13 +18,13 @@ namespace Goodtocode.AgentFramework.Core.Application.Playbooks.Essay; public sealed class RunEssayPlaybookCommand : UserScopedRequest, IRequest { public required string EssayText { get; init; } - public PlaybookReplayMode ReplayMode { get; init; } = PlaybookReplayMode.Rerun; + public RepeatMode ReplayMode { get; init; } = RepeatMode.Rerun; public string? SourceExecutionId { get; init; } } public sealed class RunEssayPlaybookCommandHandler( ISender sender, - IAgentFrameworkContext context, + PlaybookRepeatCoordinator repeats, IEssayEvaluationRunner runner, EssayStageSummarySelector summarySelector) : IRequestHandler @@ -31,28 +33,13 @@ public async Task Handle(RunEssayPlaybookCommand req { ArgumentNullException.ThrowIfNull(request); - string essayText; - PlaybookReplayContext? replayContext = null; + var repeat = await repeats.PrepareAsync( + "essay", request.UserContext, request.ReplayMode, request.SourceExecutionId, cancellationToken); + var essayText = repeat.SourceCollectInput ?? request.EssayText; - if (request.ReplayMode == PlaybookReplayMode.Rerun) - { - essayText = request.EssayText; - } - else - { - var source = await PlaybookReplaySourceResolver.ResolveAsync( - context, "essay", request.UserContext.OwnerId, request.UserContext.TenantId, - request.SourceExecutionId, cancellationToken); - - essayText = source.CollectInput; - var priorEvidence = System.Text.Json.JsonSerializer.Deserialize(source.EvidenceJson!)!; - var priorFinding = System.Text.Json.JsonSerializer.Deserialize(source.FindingJson!)!; - replayContext = new PlaybookReplayContext( - request.ReplayMode, source.Id.ToString(), priorEvidence, priorFinding); - } - - var result = await runner.EvaluateAsync(essayText, cancellationToken, replayContext); - var dto = PlaybookExecutionResultDtoFactory.CreateFrom(essayText, result, summarySelector); + var result = await runner.EvaluateAsync(essayText, cancellationToken, repeat.ExecutionRequest); + var dto = PlaybookExecutionResultDtoFactory.CreateFrom( + essayText, result, summarySelector, repeat.Request.Mode, repeat.SourceRecordSummary); dto.ExecutionId = await Persistence.PlaybookExecutionPersister.SaveAsync(sender, dto, cancellationToken); return dto; } diff --git a/src/Core.Application/Playbooks/PlaybookExecutionResultDto.cs b/src/Core.Application/Playbooks/PlaybookExecutionResultDto.cs index 8ff4bb4..1d18ed7 100644 --- a/src/Core.Application/Playbooks/PlaybookExecutionResultDto.cs +++ b/src/Core.Application/Playbooks/PlaybookExecutionResultDto.cs @@ -99,23 +99,30 @@ public static PlaybookExecutionResultDto CreateFrom(Core.Domain.Playbooks.Playbo public static PlaybookExecutionResultDto CreateFrom( string collectInput, PlaybookExecutionResult result, - IPlaybookStageSummarySelector summarySelector) + IPlaybookStageSummarySelector summarySelector, + Goodtocode.Agents.Governance.Domain.RepeatMode repeatMode = Goodtocode.Agents.Governance.Domain.RepeatMode.Rerun, + string? sourceRecordSummary = null) { ArgumentNullException.ThrowIfNull(result); ArgumentNullException.ThrowIfNull(summarySelector); + // A skipped Record leaves no materialization, so Recall shows the source's stored record output. + var recordSummary = result.ActionsExecuted.HasFlag(Goodtocode.Agents.Governance.Domain.ActionType.Record) + ? summarySelector.SummarizeMaterialization(result.Materialization) + : sourceRecordSummary ?? string.Empty; + return new PlaybookExecutionResultDto { PlaybookKey = result.Metadata.PlaybookKey, Version = result.Metadata.Version, StartedUtc = result.Metadata.StartedUtc, CompletedUtc = result.Metadata.CompletedUtc, - ReplayMode = result.Metadata.ReplayMode.ToString(), + ReplayMode = repeatMode.ToString(), SourceExecutionId = result.Metadata.SourceExecutionId, CollectInput = collectInput, CollectSummary = summarySelector.SummarizeEvidence(result.Evidence), EvaluateSummary = summarySelector.SummarizeFinding(result.Finding), - RecordSummary = summarySelector.SummarizeMaterialization(result.Materialization), + RecordSummary = recordSummary, EvidenceJson = System.Text.Json.JsonSerializer.Serialize(result.Evidence), FindingJson = System.Text.Json.JsonSerializer.Serialize(result.Finding) }; diff --git a/src/Core.Application/Playbooks/Repeatability/PlaybookRepeatCoordinator.cs b/src/Core.Application/Playbooks/Repeatability/PlaybookRepeatCoordinator.cs new file mode 100644 index 0000000..043be77 --- /dev/null +++ b/src/Core.Application/Playbooks/Repeatability/PlaybookRepeatCoordinator.cs @@ -0,0 +1,49 @@ +using Goodtocode.AgentFramework.Core.Application.Playbooks.Persistence; +using Goodtocode.Agents.Governance.Domain; +using Goodtocode.Agents.Playbook.Execution; + +namespace Goodtocode.AgentFramework.Core.Application.Playbooks.Repeatability; + +/// +/// Everything a Run*PlaybookCommand handler needs to execute a repeat: the Governance request, the Playbook +/// execution request carrying it and the prior state, and the source's collect input and record summary. +/// +public sealed record PreparedRepeat( + RepeatRequest Request, + PlaybookExecutionRequest ExecutionRequest, + string? SourceCollectInput, + string? SourceRecordSummary); + +/// +/// Resolves the source execution for a repeat and builds the Playbook execution request. Which stages run is +/// decided by the Governance policy inside the Playbook executor, not here. +/// +public sealed class PlaybookRepeatCoordinator(IAgentFrameworkContext context) +{ + public async Task> PrepareAsync( + string playbookKey, + IUserContext user, + RepeatMode mode, + string? sourceExecutionId, + CancellationToken cancellationToken) + { + if (mode == RepeatMode.Rerun) + { + return new(RepeatRequest.Rerun(), PlaybookExecutionRequest.Default, null, null); + } + + // Quick-start convention: an omitted source means "the user's latest execution". + var source = await PlaybookReplaySourceResolver.ResolveAsync( + context, playbookKey, user.OwnerId, user.TenantId, sourceExecutionId, cancellationToken); + + var request = RepeatRequest.Create(mode, source.Id.ToString()); + var executionRequest = new PlaybookExecutionRequest + { + Repeat = request, + SeedEvidence = System.Text.Json.JsonSerializer.Deserialize(source.EvidenceJson!), + SeedFinding = System.Text.Json.JsonSerializer.Deserialize(source.FindingJson!) + }; + + return new(request, executionRequest, source.CollectInput, source.RecordOutput); + } +} diff --git a/src/Core.Application/Playbooks/SqlStatistics/RunSqlStatisticsPlaybookCommand.cs b/src/Core.Application/Playbooks/SqlStatistics/RunSqlStatisticsPlaybookCommand.cs index 21739d3..d723bae 100644 --- a/src/Core.Application/Playbooks/SqlStatistics/RunSqlStatisticsPlaybookCommand.cs +++ b/src/Core.Application/Playbooks/SqlStatistics/RunSqlStatisticsPlaybookCommand.cs @@ -1,4 +1,6 @@ using Goodtocode.AgentFramework.Core.Application.Playbooks.Persistence; +using Goodtocode.AgentFramework.Core.Application.Playbooks.Repeatability; +using Goodtocode.Agents.Governance.Domain; using Goodtocode.Agents.Playbook.Execution; namespace Goodtocode.AgentFramework.Core.Application.Playbooks.SqlStatistics; @@ -14,13 +16,13 @@ namespace Goodtocode.AgentFramework.Core.Application.Playbooks.SqlStatistics; public sealed class RunSqlStatisticsPlaybookCommand : UserScopedRequest, IRequest { public required string DatabaseName { get; init; } - public PlaybookReplayMode ReplayMode { get; init; } = PlaybookReplayMode.Rerun; + public RepeatMode ReplayMode { get; init; } = RepeatMode.Rerun; public string? SourceExecutionId { get; init; } } public sealed class RunSqlStatisticsPlaybookCommandHandler( ISender sender, - IAgentFrameworkContext context, + PlaybookRepeatCoordinator repeats, ISqlStatisticsClassificationRunner runner, SqlStatisticsStageSummarySelector summarySelector) : IRequestHandler @@ -29,28 +31,13 @@ public async Task Handle(RunSqlStatisticsPlaybookCom { ArgumentNullException.ThrowIfNull(request); - string databaseName; - PlaybookReplayContext? replayContext = null; + var repeat = await repeats.PrepareAsync( + "sql-statistics", request.UserContext, request.ReplayMode, request.SourceExecutionId, cancellationToken); + var databaseName = repeat.SourceCollectInput ?? request.DatabaseName; - if (request.ReplayMode == PlaybookReplayMode.Rerun) - { - databaseName = request.DatabaseName; - } - else - { - var source = await PlaybookReplaySourceResolver.ResolveAsync( - context, "sql-statistics", request.UserContext.OwnerId, request.UserContext.TenantId, - request.SourceExecutionId, cancellationToken); - - databaseName = source.CollectInput; - var priorEvidence = System.Text.Json.JsonSerializer.Deserialize(source.EvidenceJson!)!; - var priorFinding = System.Text.Json.JsonSerializer.Deserialize(source.FindingJson!)!; - replayContext = new PlaybookReplayContext( - request.ReplayMode, source.Id.ToString(), priorEvidence, priorFinding); - } - - var result = await runner.ClassifyAsync(databaseName, cancellationToken, replayContext); - var dto = PlaybookExecutionResultDtoFactory.CreateFrom(databaseName, result, summarySelector); + var result = await runner.ClassifyAsync(databaseName, cancellationToken, repeat.ExecutionRequest); + var dto = PlaybookExecutionResultDtoFactory.CreateFrom( + databaseName, result, summarySelector, repeat.Request.Mode, repeat.SourceRecordSummary); dto.ExecutionId = await Persistence.PlaybookExecutionPersister.SaveAsync(sender, dto, cancellationToken); return dto; } diff --git a/src/Core.Application/Playbooks/SqlStatistics/SqlStatisticsClassificationRunner.cs b/src/Core.Application/Playbooks/SqlStatistics/SqlStatisticsClassificationRunner.cs index 7be1582..4b20b7a 100644 --- a/src/Core.Application/Playbooks/SqlStatistics/SqlStatisticsClassificationRunner.cs +++ b/src/Core.Application/Playbooks/SqlStatistics/SqlStatisticsClassificationRunner.cs @@ -15,7 +15,7 @@ public interface ISqlStatisticsClassificationRunner Task> ClassifyAsync( string databaseName, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null); + PlaybookExecutionRequest? request = null); } public sealed class SqlStatisticsClassificationRunner( @@ -27,12 +27,12 @@ public sealed class SqlStatisticsClassificationRunner( public Task> ClassifyAsync( string databaseName, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null) + PlaybookExecutionRequest? request = null) { ArgumentException.ThrowIfNullOrWhiteSpace(databaseName); - return replayContext is null - ? executor.ExecuteAsync(definition, databaseName, cancellationToken, activityRecorder: recorder) - : executor.ExecuteAsync(definition, databaseName, replayContext, cancellationToken, activityRecorder: recorder); + return executor.ExecuteAsync( + definition, databaseName, request ?? PlaybookExecutionRequest.Default, + cancellationToken, activityRecorder: recorder); } } diff --git a/src/Core.Application/Playbooks/Taxonomy/ClassifyTaxonomyCommand.cs b/src/Core.Application/Playbooks/Taxonomy/ClassifyTaxonomyCommand.cs index df8b517..657d37b 100644 --- a/src/Core.Application/Playbooks/Taxonomy/ClassifyTaxonomyCommand.cs +++ b/src/Core.Application/Playbooks/Taxonomy/ClassifyTaxonomyCommand.cs @@ -14,7 +14,7 @@ public interface ITaxonomyClassificationRunner Task> ClassifyAsync( string text, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null); + PlaybookExecutionRequest? request = null); } public sealed class ClassifyTaxonomyCommand : IRequest> diff --git a/src/Core.Application/Playbooks/Taxonomy/RunTaxonomyPlaybookCommand.cs b/src/Core.Application/Playbooks/Taxonomy/RunTaxonomyPlaybookCommand.cs index d39515d..bf92902 100644 --- a/src/Core.Application/Playbooks/Taxonomy/RunTaxonomyPlaybookCommand.cs +++ b/src/Core.Application/Playbooks/Taxonomy/RunTaxonomyPlaybookCommand.cs @@ -1,4 +1,6 @@ using Goodtocode.AgentFramework.Core.Application.Playbooks.Persistence; +using Goodtocode.AgentFramework.Core.Application.Playbooks.Repeatability; +using Goodtocode.Agents.Governance.Domain; using Goodtocode.Agents.Playbook.Execution; namespace Goodtocode.AgentFramework.Core.Application.Playbooks.Taxonomy; @@ -16,13 +18,13 @@ namespace Goodtocode.AgentFramework.Core.Application.Playbooks.Taxonomy; public sealed class RunTaxonomyPlaybookCommand : UserScopedRequest, IRequest { public required string Text { get; init; } - public PlaybookReplayMode ReplayMode { get; init; } = PlaybookReplayMode.Rerun; + public RepeatMode ReplayMode { get; init; } = RepeatMode.Rerun; public string? SourceExecutionId { get; init; } } public sealed class RunTaxonomyPlaybookCommandHandler( ISender sender, - IAgentFrameworkContext context, + PlaybookRepeatCoordinator repeats, ITaxonomyClassificationRunner runner, TaxonomyStageSummarySelector summarySelector) : IRequestHandler @@ -31,28 +33,13 @@ public async Task Handle(RunTaxonomyPlaybookCommand { ArgumentNullException.ThrowIfNull(request); - string text; - PlaybookReplayContext? replayContext = null; + var repeat = await repeats.PrepareAsync( + "taxonomy", request.UserContext, request.ReplayMode, request.SourceExecutionId, cancellationToken); + var text = repeat.SourceCollectInput ?? request.Text; - if (request.ReplayMode == PlaybookReplayMode.Rerun) - { - text = request.Text; - } - else - { - var source = await PlaybookReplaySourceResolver.ResolveAsync( - context, "taxonomy", request.UserContext.OwnerId, request.UserContext.TenantId, - request.SourceExecutionId, cancellationToken); - - text = source.CollectInput; - var priorEvidence = System.Text.Json.JsonSerializer.Deserialize(source.EvidenceJson!)!; - var priorFinding = System.Text.Json.JsonSerializer.Deserialize(source.FindingJson!)!; - replayContext = new PlaybookReplayContext( - request.ReplayMode, source.Id.ToString(), priorEvidence, priorFinding); - } - - var result = await runner.ClassifyAsync(text, cancellationToken, replayContext); - var dto = PlaybookExecutionResultDtoFactory.CreateFrom(text, result, summarySelector); + var result = await runner.ClassifyAsync(text, cancellationToken, repeat.ExecutionRequest); + var dto = PlaybookExecutionResultDtoFactory.CreateFrom( + text, result, summarySelector, repeat.Request.Mode, repeat.SourceRecordSummary); dto.ExecutionId = await Persistence.PlaybookExecutionPersister.SaveAsync(sender, dto, cancellationToken); return dto; } diff --git a/src/Infrastructure.AgentFramework/AgentInstructionsComposer.cs b/src/Infrastructure.AgentFramework/AgentInstructionsComposer.cs index bc30e7c..8a78e29 100644 --- a/src/Infrastructure.AgentFramework/AgentInstructionsComposer.cs +++ b/src/Infrastructure.AgentFramework/AgentInstructionsComposer.cs @@ -17,9 +17,12 @@ public interface IAgentInstructionsComposer /// /// Reads the current options snapshot whenever agent instructions are composed. /// -public sealed class AgentInstructionsComposer(IOptionsMonitor optionsMonitor) : IAgentInstructionsComposer +public sealed class AgentInstructionsComposer( + IOptionsMonitor optionsMonitor, + IOptions searchOptions) : IAgentInstructionsComposer { private readonly IOptionsMonitor _optionsMonitor = optionsMonitor; + private readonly SearchProviderOptions _searchOptions = searchOptions.Value; /// public string Compose() @@ -27,8 +30,14 @@ public string Compose() var options = _optionsMonitor.CurrentValue; var instructions = new StringBuilder(); + instructions.AppendLine(ToolRoutingInstructions.NoFutureTensePreamble.Trim()); + instructions.AppendLine(); instructions.AppendLine(ToolRoutingInstructions.AntiAnnouncementGuidance.Trim()); instructions.AppendLine(); + instructions.AppendLine((_searchOptions.IsAvailable + ? ToolRoutingInstructions.WebSearchGuidance + : ToolRoutingInstructions.WebSearchUnavailableGuidance).Trim()); + instructions.AppendLine(); if (!string.IsNullOrWhiteSpace(options.GlobalPreamble)) { diff --git a/src/Infrastructure.AgentFramework/ChatMessageIntentRouter.cs b/src/Infrastructure.AgentFramework/ChatMessageIntentRouter.cs index 7957722..4e213ac 100644 --- a/src/Infrastructure.AgentFramework/ChatMessageIntentRouter.cs +++ b/src/Infrastructure.AgentFramework/ChatMessageIntentRouter.cs @@ -74,14 +74,15 @@ public async Task ResolveReplyAsync( var forcedToolReply = await TryResolveViaForcedToolInferenceAsync(chatHistory, cancellationToken); if (!string.IsNullOrWhiteSpace(forcedToolReply)) { - return forcedToolReply; + return await GuardReplyAsync(forcedToolReply, chatHistory, cancellationToken); } } var agentResponse = await _agent.RunAsync(chatHistory, cancellationToken: cancellationToken); var response = agentResponse.Messages.LastOrDefault(); ChatGuard.GuardAgainstNullAgentResponse(response); - return response!.Contents.LastOrDefault()?.ToString() ?? string.Empty; + var reply = response!.Contents.LastOrDefault()?.ToString() ?? string.Empty; + return await GuardReplyAsync(reply, chatHistory, cancellationToken); } finally { @@ -89,6 +90,44 @@ public async Task ResolveReplyAsync( } } + /// + /// Single exit validation for every model-generated reply. A reply containing future tense or an + /// announced intent is regenerated once with a corrective instruction; whatever still violates is + /// stripped, so such text never reaches the user. + /// + private async Task GuardReplyAsync( + string reply, + List chatHistory, + CancellationToken cancellationToken) + { + if (!FutureTenseGuard.ContainsFutureTense(reply)) + { + return reply; + } + + _logger.LogWarning("Model reply contained future tense or an announced intent; regenerating once."); + try + { + var retryHistory = new List(chatHistory) + { + new(ChatRole.System, ToolRoutingInstructions.NoFutureTensePreamble), + new(ChatRole.System, "The previous reply violated the rule above. Produce the final answer now, using only past or present tense and containing results rather than announcements.") + }; + var retryResponse = await _agent.RunAsync(retryHistory, cancellationToken: cancellationToken); + var retryReply = retryResponse.Messages.LastOrDefault()?.Contents.LastOrDefault()?.ToString(); + if (!string.IsNullOrWhiteSpace(retryReply)) + { + return FutureTenseGuard.Enforce(retryReply); + } + } + catch (Exception exception) when (exception is not OperationCanceledException) + { + _logger.LogWarning(exception, "Regeneration after a future-tense reply failed; stripping the reply instead."); + } + + return FutureTenseGuard.Enforce(reply); + } + private async Task TryResolveViaForcedToolInferenceAsync( List chatHistory, CancellationToken cancellationToken) @@ -128,6 +167,7 @@ private async Task> BuildChatHistoryAsync( var chatHistory = new List { new(ChatRole.System, governed.PromptContext.SystemInstruction), + new(ChatRole.System, ToolRoutingInstructions.NoFutureTensePreamble), BuildSelectionContextMessage(chatSessionId) }; diff --git a/src/Infrastructure.AgentFramework/ConfigureServices.cs b/src/Infrastructure.AgentFramework/ConfigureServices.cs index c033b88..30ea910 100644 --- a/src/Infrastructure.AgentFramework/ConfigureServices.cs +++ b/src/Infrastructure.AgentFramework/ConfigureServices.cs @@ -86,7 +86,9 @@ public static IServiceCollection AddAgentFrameworkOpenAIServices(this IServiceCo services.AddScoped(); - services.AddSingleton(DefaultIntentCatalogFactory.Create()); + var searchProviderOptions = configuration.GetSection(SearchProviderOptions.SectionName).Get() + ?? new SearchProviderOptions(); + services.AddSingleton(DefaultIntentCatalogFactory.Create(searchProviderOptions.IsAvailable)); services.AddSingleton(); services.AddScoped(); services.AddScoped(); @@ -202,14 +204,19 @@ public static IServiceCollection AddAgentFrameworkOpenAIServices(this IServiceCo var chatClient = provider.GetRequiredService(); var loggerFactory = provider.GetRequiredService(); var instructionsComposer = provider.GetRequiredService(); + var searchOptions = provider.GetRequiredService>().Value; var tools = new List { provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService(), - provider.GetRequiredService() + provider.GetRequiredService() }; + if (searchOptions.IsAvailable) + { + tools.Add(provider.GetRequiredService()); + } + var agentOptions = new ChatClientAgentOptions { Name = "CopilotAgent", @@ -258,8 +265,7 @@ public static IServiceCollection AddWebSearchProviders(this IServiceCollection s services.AddScoped(provider => { var options = provider.GetRequiredService>().Value; - if (options.Provider.Equals("Bing", StringComparison.OrdinalIgnoreCase) - && IsBingConfigured(options)) + if (options.IsAvailable) { return provider.GetRequiredService(); } @@ -355,18 +361,6 @@ private static bool HasRequiredSearchProviderOptions(SearchProviderOptions optio return false; } - private static bool IsBingConfigured(SearchProviderOptions options) - { - var apiKey = options.ApiKey ?? string.Empty; - if (!HasValue(apiKey) - || apiKey.Equals("", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return HasUri(options.Endpoint ?? string.Empty); - } - private static bool HasValue(string value) => !string.IsNullOrWhiteSpace(value); diff --git a/src/Infrastructure.AgentFramework/Execution/PlaybookWorkflowGraphExecutor.cs b/src/Infrastructure.AgentFramework/Execution/PlaybookWorkflowGraphExecutor.cs index 73df5d9..bdfc260 100644 --- a/src/Infrastructure.AgentFramework/Execution/PlaybookWorkflowGraphExecutor.cs +++ b/src/Infrastructure.AgentFramework/Execution/PlaybookWorkflowGraphExecutor.cs @@ -1,3 +1,5 @@ +using Goodtocode.Agents.Governance.Application; +using Goodtocode.Agents.Governance.Domain; using Goodtocode.Agents.Playbook.Execution; using Goodtocode.Agents.Playbook.Steps; using Microsoft.Agents.AI.Workflows; @@ -15,12 +17,11 @@ namespace Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution; /// PipelineWorkflowStepExecutor. Each node calls the shared /// after its /// stage completes, so governance capture is identical regardless of orchestration model. When an -/// optional is supplied, the full graph is -/// bypassed in favor of direct, in-order tool calls for just the stages that mode requires - -/// Record only for Recall, Evaluate+Record for Replay - mirroring the same repeatability pillar -/// the package's own PlaybookExecutor implements for the non-MAF SQL Statistics playbook. +/// optional skips any stage, the full +/// graph is bypassed in favor of direct, in-order tool calls with the same skip semantics as the +/// package's own PlaybookExecutor. /// -public sealed class PlaybookWorkflowGraphExecutor +public sealed class PlaybookWorkflowGraphExecutor(IRepeatPolicy repeatPolicy) { public async Task> ExecuteAsync( PlaybookIdentity identity, @@ -30,22 +31,22 @@ public async Task TCollectInput input, CancellationToken cancellationToken = default, IPlaybookStepActivityRecorder? activityRecorder = null, - PlaybookReplayContext? replayContext = null) + PlaybookExecutionRequest? request = null) { ArgumentNullException.ThrowIfNull(collectTool); ArgumentNullException.ThrowIfNull(evaluateTool); ArgumentNullException.ThrowIfNull(recordTool); - replayContext?.Validate(); + request ??= PlaybookExecutionRequest.Default; + var plan = repeatPolicy.Plan(request.Repeat); + request.Validate(plan); var startedUtc = DateTimeOffset.UtcNow; - return replayContext?.Mode switch - { - PlaybookReplayMode.Recall => await ExecuteRecallAsync(identity, recordTool, replayContext, activityRecorder, startedUtc, cancellationToken).ConfigureAwait(false), - PlaybookReplayMode.Replay => await ExecuteReplayAsync(identity, evaluateTool, recordTool, replayContext, activityRecorder, startedUtc, cancellationToken).ConfigureAwait(false), - _ => await ExecuteRerunAsync(identity, collectTool, evaluateTool, recordTool, input, activityRecorder, startedUtc, cancellationToken).ConfigureAwait(false) - }; + // The graph only models a full run; any skipped stage uses the same skip semantics as PlaybookExecutor. + return plan.Run == ActionType.All + ? await ExecuteRerunAsync(identity, collectTool, evaluateTool, recordTool, input, activityRecorder, startedUtc, cancellationToken).ConfigureAwait(false) + : await ExecuteSkippingAsync(identity, collectTool, evaluateTool, recordTool, input, request, plan, activityRecorder, startedUtc, cancellationToken).ConfigureAwait(false); } /// @@ -84,8 +85,7 @@ private async Task( collectNode.Evidence!, @@ -100,65 +100,67 @@ private async Task - /// Recall: rehydrates the prior execution's evidence and finding and runs only the Record - /// stage, bypassing the Collect/Evaluate nodes entirely so materialization can be re-rendered - /// from the recalled finding without any new tool calls. + /// Runs the stages the request leaves enabled as direct tool calls, in order. Skipped stages + /// are not invoked, not recorded, and take their seed instead, so Recall is a pure read. /// - private static async Task> ExecuteRecallAsync( + private static async Task> ExecuteSkippingAsync( PlaybookIdentity identity, + ICollectStepTool collectTool, + IEvaluateStepTool evaluateTool, IRecordStepTool recordTool, - PlaybookReplayContext replayContext, + TCollectInput input, + PlaybookExecutionRequest request, + RepeatPlan plan, IPlaybookStepActivityRecorder? activityRecorder, DateTimeOffset startedUtc, CancellationToken cancellationToken) { - var materialization = await recordTool.RecordAsync(replayContext.PriorFinding, cancellationToken).ConfigureAwait(false); - - if (activityRecorder is not null) + TEvidence evidence; + if (!plan.Runs(ActionType.Collect)) { - await activityRecorder.OnRecordedAsync(identity, materialization, recordTool.ToolName, cancellationToken).ConfigureAwait(false); + evidence = request.SeedEvidence!; + } + else + { + evidence = await collectTool.ExecuteAsync(input, cancellationToken).ConfigureAwait(false); + if (activityRecorder is not null) + { + await activityRecorder.OnCollectedAsync(identity, evidence, collectTool.ToolName, cancellationToken).ConfigureAwait(false); + } } - var metadata = new PlaybookExecutionMetadata( - identity.PlaybookKey, identity.Version, startedUtc, DateTimeOffset.UtcNow, - PlaybookReplayMode.Recall, replayContext.SourceExecutionId); - - return new PlaybookExecutionResult( - replayContext.PriorEvidence, replayContext.PriorFinding, materialization, metadata); - } - - /// - /// Replay: reuses the prior execution's Collect-stage evidence (skipping Collect) and re-runs - /// Evaluate and Record against it, to verify exact reproduction of a governed result. - /// - private static async Task> ExecuteReplayAsync( - PlaybookIdentity identity, - IEvaluateStepTool evaluateTool, - IRecordStepTool recordTool, - PlaybookReplayContext replayContext, - IPlaybookStepActivityRecorder? activityRecorder, - DateTimeOffset startedUtc, - CancellationToken cancellationToken) - { - var evidence = replayContext.PriorEvidence; - - var finding = await evaluateTool.EvaluateAsync(evidence, cancellationToken).ConfigureAwait(false); - if (activityRecorder is not null) + TFinding finding; + if (!plan.Runs(ActionType.Evaluate)) + { + finding = request.SeedFinding!; + } + else { - await activityRecorder.OnEvaluatedAsync(identity, finding, evaluateTool.ToolName, cancellationToken).ConfigureAwait(false); + finding = await evaluateTool.EvaluateAsync(evidence, cancellationToken).ConfigureAwait(false); + if (activityRecorder is not null) + { + await activityRecorder.OnEvaluatedAsync(identity, finding, evaluateTool.ToolName, cancellationToken).ConfigureAwait(false); + } } - var materialization = await recordTool.RecordAsync(finding, cancellationToken).ConfigureAwait(false); - if (activityRecorder is not null) + TMaterialization materialization = default!; + if (plan.Runs(ActionType.Record)) { - await activityRecorder.OnRecordedAsync(identity, materialization, recordTool.ToolName, cancellationToken).ConfigureAwait(false); + materialization = await recordTool.RecordAsync(finding, cancellationToken).ConfigureAwait(false); + if (activityRecorder is not null) + { + await activityRecorder.OnRecordedAsync(identity, materialization, recordTool.ToolName, cancellationToken).ConfigureAwait(false); + } } var metadata = new PlaybookExecutionMetadata( identity.PlaybookKey, identity.Version, startedUtc, DateTimeOffset.UtcNow, - PlaybookReplayMode.Replay, replayContext.SourceExecutionId); + SourceExecutionId: request.Repeat.SourceExecutionId); - return new PlaybookExecutionResult(evidence, finding, materialization, metadata); + return new PlaybookExecutionResult(evidence, finding, materialization, metadata) + { + ActionsExecuted = plan.Run + }; } private sealed class CollectNode( diff --git a/src/Infrastructure.AgentFramework/Infrastructure.AgentFramework.csproj b/src/Infrastructure.AgentFramework/Infrastructure.AgentFramework.csproj index 207ada4..0be4c83 100644 --- a/src/Infrastructure.AgentFramework/Infrastructure.AgentFramework.csproj +++ b/src/Infrastructure.AgentFramework/Infrastructure.AgentFramework.csproj @@ -12,15 +12,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/Infrastructure.AgentFramework/Intents/DefaultIntentCatalogFactory.cs b/src/Infrastructure.AgentFramework/Intents/DefaultIntentCatalogFactory.cs index e977328..cd7e0b6 100644 --- a/src/Infrastructure.AgentFramework/Intents/DefaultIntentCatalogFactory.cs +++ b/src/Infrastructure.AgentFramework/Intents/DefaultIntentCatalogFactory.cs @@ -7,7 +7,7 @@ namespace Goodtocode.AgentFramework.Infrastructure.AgentFramework.Intents; /// public static class DefaultIntentCatalogFactory { - public static IntentCatalog Create() => new( + public static IntentCatalog Create(bool includeWebSearch = true) => new( [ // Parameterized selection intents evaluated first (RuleIntentClassifier checks Captures // before Examples across all intents, so ordering here only affects tie-breaks among captures). @@ -161,7 +161,10 @@ public static class DefaultIntentCatalogFactory // Level 4 deterministic routing for web search: guarantee the "search the web for [query]" // phrasing never falls through to the LLM's own tool-selection. The Capture extracts the // query part so it can be passed to the search tool. - new IntentDefinition(IntentNames.SearchWeb, Examples: [], - Captures: [new PhraseCapture("search the web for", "query", CaptureKind.Rest)]) + // Included only when web search is available (feature switch on and provider configured). + .. includeWebSearch + ? (IntentDefinition[])[new IntentDefinition(IntentNames.SearchWeb, Examples: [], + Captures: [new PhraseCapture("search the web for", "query", CaptureKind.Rest)])] + : [] ]); } diff --git a/src/Infrastructure.AgentFramework/Intents/FutureTenseGuard.cs b/src/Infrastructure.AgentFramework/Intents/FutureTenseGuard.cs new file mode 100644 index 0000000..01eac6e --- /dev/null +++ b/src/Infrastructure.AgentFramework/Intents/FutureTenseGuard.cs @@ -0,0 +1,77 @@ +using System.Text; +using System.Text.RegularExpressions; + +namespace Goodtocode.AgentFramework.Infrastructure.AgentFramework.Intents; + +/// +/// Validates model-generated replies against the no-future-tense rule: a reply may only report what is +/// done or state that the request cannot be completed. Promises of later work never reach the user +/// because an action not performed within the reply will never be performed. +/// +public static partial class FutureTenseGuard +{ + public const string FallbackReply = "The request was not completed. No result was produced."; + + [GeneratedRegex( + @"\bI\s*(?:will|shall|['’]ll)\b" + + @"|\b(?:I|we)\s*(?:am|are|['’]m|['’]re)\s+(?:going\s+to|about\s+to|gonna)\b" + + @"|\bwe\s*(?:will|shall|['’]ll)\b" + + @"|\bI\s+(?:plan|intend|aim|propose)\s+to\b" + + @"|\b(?:let\s+me|allow\s+me|permit\s+me)\b" + + @"|\bgive\s+me\s+(?:a\s+)?(?:moment|second|minute|sec)\b" + + @"|\b(?:one|just\s+a)\s+(?:moment|second|minute)\b" + + @"|\b(?:please\s+wait|hold\s+on|stand\s+by|stay\s+tuned|bear\s+with\s+me)\b" + + @"|\bnext,?\s+I\b" + + @"|\b(?:in|within)\s+a\s+(?:moment|few\s+moments|few\s+seconds)\b" + + @"|\bwill\s+(?:now\s+)?(?:search|look|fetch|query|check|find|retrieve|run|get|proceed|begin|start)\b" + + @"|\bgoing\s+to\s+(?:search|look|fetch|query|check|find|retrieve|run|get)\b", + RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, + matchTimeoutMilliseconds: 1000)] + private static partial Regex FutureTensePattern(); + + [GeneratedRegex(@"(?<=[.!?])\s+", RegexOptions.CultureInvariant, matchTimeoutMilliseconds: 1000)] + private static partial Regex SentenceBoundary(); + + public static bool ContainsFutureTense(string? reply) + => !string.IsNullOrWhiteSpace(reply) && FutureTensePattern().IsMatch(reply); + + /// + /// Returns the reply unchanged when compliant. Otherwise removes every violating sentence (table rows + /// and selection chips are data and are kept as-is) and returns when nothing remains. + /// + public static string Enforce(string? reply) + { + if (string.IsNullOrWhiteSpace(reply)) + { + return reply ?? string.Empty; + } + + if (!ContainsFutureTense(reply)) + { + return reply; + } + + var result = new StringBuilder(); + foreach (var line in reply.Split('\n')) + { + var trimmed = line.TrimStart(); + if (trimmed.StartsWith('|') || trimmed.StartsWith("[selection|", StringComparison.Ordinal)) + { + result.Append(line.TrimEnd('\r')).Append('\n'); + continue; + } + + var kept = SentenceBoundary() + .Split(line.TrimEnd('\r')) + .Where(sentence => !FutureTensePattern().IsMatch(sentence)); + var rebuilt = string.Join(' ', kept).TrimEnd(); + if (rebuilt.Length > 0 || line.Trim().Length == 0) + { + result.Append(rebuilt).Append('\n'); + } + } + + var cleaned = result.ToString().Trim(); + return cleaned.Length == 0 ? FallbackReply : cleaned; + } +} diff --git a/src/Infrastructure.AgentFramework/Intents/ToolRoutingInstructions.cs b/src/Infrastructure.AgentFramework/Intents/ToolRoutingInstructions.cs index 294aef2..dda83a9 100644 --- a/src/Infrastructure.AgentFramework/Intents/ToolRoutingInstructions.cs +++ b/src/Infrastructure.AgentFramework/Intents/ToolRoutingInstructions.cs @@ -13,13 +13,42 @@ public static class ToolRoutingInstructions /// immediately and returning results in the same turn. /// public const string AntiAnnouncementGuidance = """ - For every request that a registered tool can answer (chat sessions, chat messages, actors, - or web search), call that tool immediately and deliver its result in this same reply. + For every request that a registered tool can answer (chat sessions, chat messages, or + actors), call that tool immediately and deliver its result in this same reply. Never reply with only an announcement of intent such as "I will look that up", "Let me get that for you", "Querying...", or "One moment" - the user cannot see a follow-up turn, so an announcement without a delivered result is a failed response. - Do not answer from memory or guess at data a tool would provide. Read-only queries execute + Do not answer from memory or guess at data a registered tool would provide (the user's chat + sessions, chat messages, or actors). When no registered tool applies to a request, answer it + directly and helpfully from your general knowledge instead of declining. Read-only queries execute immediately without confirmation. Ask for explicit confirmation only before a command that creates, changes, or deletes data. """; + + /// Added only when web search is available (feature switch on and provider configured). + public const string WebSearchGuidance = """ + For requests to search the web, current news, or current public documentation, call the web + search tool immediately and deliver its results in this same reply. + """; + + /// Added only when web search is unavailable. + public const string WebSearchUnavailableGuidance = """ + Live web search is not available. When a request needs public-web information, never refuse + and never stop at saying search is unavailable. In the present tense, note once in a single + short sentence that live results could not be retrieved and the answer comes from general + knowledge that may be out of date, then give the most helpful complete answer you can from + that knowledge. + """; + + /// + /// Mandatory preamble for every model inference. Mirrored by , which + /// validates every returned reply. + /// + public const string NoFutureTensePreamble = """ + ABSOLUTE RULE: Never use future tense or announce intended actions. Never write "I will", "I'll", + "I am going to", "I'm going to", "let me", "allow me", "one moment", "please wait", "stand by", + "I plan to", "I intend to", "next I", or any promise of later work. An action that has not + already happened in this reply will never happen. Report only what is done, using past or + present tense, or state plainly that the request cannot be completed. + """; } diff --git a/src/Infrastructure.AgentFramework/Options/SearchProviderOptions.cs b/src/Infrastructure.AgentFramework/Options/SearchProviderOptions.cs index 9bfd291..bf29926 100644 --- a/src/Infrastructure.AgentFramework/Options/SearchProviderOptions.cs +++ b/src/Infrastructure.AgentFramework/Options/SearchProviderOptions.cs @@ -6,6 +6,11 @@ public sealed class SearchProviderOptions { public const string SectionName = "SearchProvider"; + private const string SecretPlaceholder = ""; + + /// Hard feature switch. When false, web search is unavailable regardless of other settings. + public bool Enabled { get; set; } = true; + [Required] [RegularExpression("^(Bing|None)$")] public string Provider { get; set; } = "None"; @@ -16,4 +21,16 @@ public sealed class SearchProviderOptions [Range(1, 50)] public int DefaultResultCount { get; set; } = 5; + + /// + /// True only when the feature switch is on and the selected provider has a real endpoint and API key. + /// Web search tools, intents, and instructions are exposed only when this is true. + /// + public bool IsAvailable => Enabled && IsBingConfigured; + + public bool IsBingConfigured => + Provider.Equals("Bing", StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrWhiteSpace(ApiKey) + && !ApiKey.Equals(SecretPlaceholder, StringComparison.OrdinalIgnoreCase) + && Uri.TryCreate(Endpoint, UriKind.Absolute, out _); } diff --git a/src/Infrastructure.AgentFramework/Playbooks/Essay/EssayEvaluationRunner.cs b/src/Infrastructure.AgentFramework/Playbooks/Essay/EssayEvaluationRunner.cs index f9062d6..18bdc31 100644 --- a/src/Infrastructure.AgentFramework/Playbooks/Essay/EssayEvaluationRunner.cs +++ b/src/Infrastructure.AgentFramework/Playbooks/Essay/EssayEvaluationRunner.cs @@ -1,5 +1,6 @@ using Goodtocode.AgentFramework.Core.Application.Playbooks.Essay; using Goodtocode.AgentFramework.Infrastructure.AgentFramework.Execution; +using Goodtocode.Agents.Governance.Application; using Goodtocode.Agents.Playbook.Execution; using Goodtocode.Agents.Playbook.Tools; @@ -13,9 +14,10 @@ namespace Goodtocode.AgentFramework.Infrastructure.AgentFramework.Playbooks.Essa /// public sealed class EssayEvaluationRunner( IPlaybookStepToolResolver resolver, - EssayGovernanceActivityRecorder recorder) : IEssayEvaluationRunner + EssayGovernanceActivityRecorder recorder, + IRepeatPolicy repeatPolicy) : IEssayEvaluationRunner { - private static readonly PlaybookWorkflowGraphExecutor GraphExecutor = new(); + private readonly PlaybookWorkflowGraphExecutor GraphExecutor = new(repeatPolicy); private readonly IPlaybookStepToolResolver _resolver = resolver; private readonly EssayGovernanceActivityRecorder _recorder = recorder; @@ -23,7 +25,7 @@ public sealed class EssayEvaluationRunner( public Task> EvaluateAsync( string essayText, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null) + PlaybookExecutionRequest? request = null) { ArgumentException.ThrowIfNullOrWhiteSpace(essayText); @@ -37,6 +39,6 @@ public Task public sealed class TaxonomyClassificationRunner( IPlaybookStepToolResolver resolver, - TaxonomyGovernanceActivityRecorder recorder) : ITaxonomyClassificationRunner + TaxonomyGovernanceActivityRecorder recorder, + IRepeatPolicy repeatPolicy) : ITaxonomyClassificationRunner { - private static readonly PlaybookWorkflowGraphExecutor GraphExecutor = new(); + private readonly PlaybookWorkflowGraphExecutor GraphExecutor = new(repeatPolicy); private readonly IPlaybookStepToolResolver _resolver = resolver; private readonly TaxonomyGovernanceActivityRecorder _recorder = recorder; @@ -23,7 +25,7 @@ public sealed class TaxonomyClassificationRunner( public Task> ClassifyAsync( string text, CancellationToken cancellationToken, - PlaybookReplayContext? replayContext = null) + PlaybookExecutionRequest? request = null) { ArgumentException.ThrowIfNullOrWhiteSpace(text); @@ -37,6 +39,6 @@ public Task - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + + + + + diff --git a/src/Presentation.Api/Presentation.Api.csproj b/src/Presentation.Api/Presentation.Api.csproj index 45dff01..bd9b0d7 100644 --- a/src/Presentation.Api/Presentation.Api.csproj +++ b/src/Presentation.Api/Presentation.Api.csproj @@ -23,22 +23,22 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/src/Presentation.Api/appsettings.Development.json b/src/Presentation.Api/appsettings.Development.json index 5139310..d150857 100644 --- a/src/Presentation.Api/appsettings.Development.json +++ b/src/Presentation.Api/appsettings.Development.json @@ -20,6 +20,7 @@ "ValidateAuthority": true }, "SearchProvider": { + "Enabled": true, "Provider": "Bing", "Endpoint": "https://api.bing.microsoft.com", "ApiKey": "", diff --git a/src/Presentation.Api/appsettings.Production.json b/src/Presentation.Api/appsettings.Production.json index a9bc0f1..de9d73e 100644 --- a/src/Presentation.Api/appsettings.Production.json +++ b/src/Presentation.Api/appsettings.Production.json @@ -20,6 +20,7 @@ "ValidateAuthority": true }, "SearchProvider": { + "Enabled": true, "Provider": "Bing", "Endpoint": "https://api.bing.microsoft.com", "ApiKey": "", diff --git a/src/Presentation.Api/appsettings.local.json b/src/Presentation.Api/appsettings.local.json index d9421be..25b3a4c 100644 --- a/src/Presentation.Api/appsettings.local.json +++ b/src/Presentation.Api/appsettings.local.json @@ -20,6 +20,7 @@ "ValidateAuthority": true }, "SearchProvider": { + "Enabled": true, "Provider": "Bing", "Endpoint": "https://api.bing.microsoft.com", "ApiKey": "", diff --git a/src/Presentation.Web/Features/Playbooks/Components/PlaybookReplayControls.razor b/src/Presentation.Web/Features/Playbooks/Components/PlaybookReplayControls.razor index 0b1dd2c..772f147 100644 --- a/src/Presentation.Web/Features/Playbooks/Components/PlaybookReplayControls.razor +++ b/src/Presentation.Web/Features/Playbooks/Components/PlaybookReplayControls.razor @@ -31,9 +31,9 @@ changes against current live data. - Recall: re-render the already-recorded finding with no new - Collect or Evaluate work at all. Use this to view exactly what happened last - time, at zero cost, even if live data has since changed. + Recall: read back exactly what was recorded last time. A pure + read: nothing is collected, evaluated, or recorded again, so it costs nothing and + is unaffected by later changes to live data. Replay: reuse the recorded evidence (skip Collect) and re-run diff --git a/src/Presentation.Web/Features/Playbooks/Components/PlaybookResultPanel.razor b/src/Presentation.Web/Features/Playbooks/Components/PlaybookResultPanel.razor index 9a92b82..2dd2595 100644 --- a/src/Presentation.Web/Features/Playbooks/Components/PlaybookResultPanel.razor +++ b/src/Presentation.Web/Features/Playbooks/Components/PlaybookResultPanel.razor @@ -2,6 +2,7 @@ + diff --git a/src/Presentation.Web/Features/Playbooks/Components/PlaybookStagesOverview.razor b/src/Presentation.Web/Features/Playbooks/Components/PlaybookStagesOverview.razor new file mode 100644 index 0000000..aba243d --- /dev/null +++ b/src/Presentation.Web/Features/Playbooks/Components/PlaybookStagesOverview.razor @@ -0,0 +1,23 @@ + + + How this Playbook works + + Every Playbook runs three governed stages in order. Use the tabs below to inspect + each stage's input, processing, and output. + + + + 1. Collect: gathers the raw evidence. See what input was given, + what action ran, and what data came back. + + + 2. Evaluate: judges the collected evidence against the rules or + rubric. See how the evidence was interpreted. + + + 3. Record: persists the final governed finding. See the result + that is stored for audit, recall, and replay. + + + + diff --git a/src/Presentation.Web/Features/Playbooks/Components/PlaybookStepDetail.razor b/src/Presentation.Web/Features/Playbooks/Components/PlaybookStepDetail.razor index 44c291a..ca15232 100644 --- a/src/Presentation.Web/Features/Playbooks/Components/PlaybookStepDetail.razor +++ b/src/Presentation.Web/Features/Playbooks/Components/PlaybookStepDetail.razor @@ -1,3 +1,4 @@ +@using Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Formatting @using Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Models @@ -7,7 +8,7 @@ case PlaybookCerStep.Collect: Collect Input - @Result.CollectInput + @Result.CollectInput.FormatForPlaybookDisplay() Processing / Action @GetProcessingDescription(PlaybookCerStep.Collect, "Gather evidence from the submitted input using deterministic queries or tool calls.") @@ -19,15 +20,16 @@ Output @foreach (var item in GetDisplayItems(Result.CollectSummary)) { - • @item + • @item.FormatForPlaybookDisplay() } break; + case PlaybookCerStep.Evaluate: Evaluate Input @foreach (var item in GetDisplayItems(Result.CollectSummary)) { - • @item + • @item.FormatForPlaybookDisplay() } Processing / Action @@ -40,15 +42,16 @@ Output @foreach (var item in GetDisplayItems(Result.EvaluateSummary)) { - • @item + • @item.FormatForPlaybookDisplay() } break; + case PlaybookCerStep.Record: Record Input @foreach (var item in GetDisplayItems(Result.EvaluateSummary)) { - • @item + • @item.FormatForPlaybookDisplay() } Processing / Action @@ -61,7 +64,7 @@ Output @foreach (var item in GetDisplayItems(Result.RecordSummary)) { - • @item + • @item.FormatForPlaybookDisplay() } break; } @@ -69,21 +72,10 @@ @code { - /// - /// The completed playbook execution whose Collect/Evaluate/Record detail is rendered. - /// [Parameter, EditorRequired] public PlaybookExecutionResultModel Result { get; set; } = null!; - /// - /// Which CER step's detail to show, driven by . - /// [Parameter] public PlaybookCerStep Step { get; set; } = PlaybookCerStep.Collect; - /// - /// The persisted catalog definition for this Playbook, supplying each CER step's real - /// Name/Description and processing/action text (query, rubric, or template). Optional: may - /// still be loading, in which case a generic processing description is shown instead. - /// [Parameter] public PlaybookCatalogModel? Catalog { get; set; } private string GetProcessingDescription(PlaybookCerStep step, string fallback) => diff --git a/src/Presentation.Web/Features/Playbooks/Formatting/PlaybookDisplayTextFormatter.cs b/src/Presentation.Web/Features/Playbooks/Formatting/PlaybookDisplayTextFormatter.cs new file mode 100644 index 0000000..8929e30 --- /dev/null +++ b/src/Presentation.Web/Features/Playbooks/Formatting/PlaybookDisplayTextFormatter.cs @@ -0,0 +1,49 @@ +using System.Text.RegularExpressions; + +namespace Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Formatting; + +public static partial class PlaybookDisplayTextFormatter +{ + private static readonly Regex SentenceBoundaryRegex = new(@"(?<=[.!?;])\s+(?=[A-Z])", RegexOptions.Compiled); + private static readonly Regex BulletBoundaryRegex = new(@"(?<=[.!?])\s+(?=-\s|\*\s)", RegexOptions.Compiled); + private static readonly Regex WhitespaceCollapseRegex = new(@"[ \t]{2,}", RegexOptions.Compiled); + + public static string Format(string? text) + { + if (string.IsNullOrWhiteSpace(text)) + return string.Empty; + + var normalized = text + .Replace("\r\n", "\n") + .Replace('\r', '\n'); + + if (normalized.Contains('\n')) + { + return CollapseWhitespacePreservingNewlines(normalized) + .Trim(); + } + + var withSentenceBreaks = SentenceBoundaryRegex.Replace(normalized, "\n"); + var withBulletBreaks = BulletBoundaryRegex.Replace(withSentenceBreaks, "\n"); + + return CollapseWhitespacePreservingNewlines(withBulletBreaks) + .Trim(); + } + + private static string CollapseWhitespacePreservingNewlines(string text) + { + var lines = text.Split('\n'); + for (var i = 0; i < lines.Length; i++) + { + lines[i] = WhitespaceCollapseRegex.Replace(lines[i], " ").Trim(); + } + + return string.Join("\n", lines); + } +} + +public static class PlaybookDisplayTextFormattingExtensions +{ + public static string FormatForPlaybookDisplay(this string? text) => + PlaybookDisplayTextFormatter.Format(text); +} diff --git a/src/Presentation.Web/Features/Playbooks/Models/PlaybookReplayMode.cs b/src/Presentation.Web/Features/Playbooks/Models/PlaybookReplayMode.cs index fd8bd10..7b2a1f1 100644 --- a/src/Presentation.Web/Features/Playbooks/Models/PlaybookReplayMode.cs +++ b/src/Presentation.Web/Features/Playbooks/Models/PlaybookReplayMode.cs @@ -17,8 +17,7 @@ public enum PlaybookReplayMode Rerun = 0, /// - /// Rehydrate a prior execution's evidence and finding without running Collect or Evaluate; - /// Record still runs so materialization can be re-rendered from the recalled finding. + /// Rehydrate a prior execution's recorded result as a pure read: no stage runs again. /// Recall = 1, diff --git a/src/Presentation.Web/Features/Playbooks/Services/PlaybookService.cs b/src/Presentation.Web/Features/Playbooks/Services/PlaybookService.cs index 32ca56e..739631f 100644 --- a/src/Presentation.Web/Features/Playbooks/Services/PlaybookService.cs +++ b/src/Presentation.Web/Features/Playbooks/Services/PlaybookService.cs @@ -1,6 +1,6 @@ using Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Models; using Goodtocode.AgentFramework.Presentation.Web.Infrastructure.Http; -using ClientReplayMode = Goodtocode.AgentFramework.Api.Clients.PlaybookReplayMode; +using ClientReplayMode = Goodtocode.AgentFramework.Api.Clients.RepeatMode; using UiReplayMode = Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Models.PlaybookReplayMode; namespace Goodtocode.AgentFramework.Presentation.Web.Features.Playbooks.Services; diff --git a/src/Presentation.Web/Infrastructure/Clients/BackendApiClient.g.cs b/src/Presentation.Web/Infrastructure/Clients/BackendApiClient.g.cs index fb5d46c..00dcae9 100644 --- a/src/Presentation.Web/Infrastructure/Clients/BackendApiClient.g.cs +++ b/src/Presentation.Web/Infrastructure/Clients/BackendApiClient.g.cs @@ -2837,18 +2837,6 @@ public partial class PlaybookExecutionResultDto } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.3.0 (NJsonSchema v11.5.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum PlaybookReplayMode - { - - _0 = 0, - - _1 = 1, - - _2 = 2, - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.3.0 (NJsonSchema v11.5.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class PlaybookStepDto { @@ -2903,6 +2891,18 @@ public enum PlaybookStepType } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.3.0 (NJsonSchema v11.5.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum RepeatMode + { + + _0 = 0, + + _1 = 1, + + _2 = 2, + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.3.0 (NJsonSchema v11.5.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RunEssayPlaybookCommand { @@ -2914,7 +2914,7 @@ public partial class RunEssayPlaybookCommand public string EssayText { get; set; } [System.Text.Json.Serialization.JsonPropertyName("replayMode")] - public PlaybookReplayMode ReplayMode { get; set; } + public RepeatMode ReplayMode { get; set; } [System.Text.Json.Serialization.JsonPropertyName("sourceExecutionId")] public string SourceExecutionId { get; set; } @@ -2932,7 +2932,7 @@ public partial class RunSqlStatisticsPlaybookCommand public string DatabaseName { get; set; } [System.Text.Json.Serialization.JsonPropertyName("replayMode")] - public PlaybookReplayMode ReplayMode { get; set; } + public RepeatMode ReplayMode { get; set; } [System.Text.Json.Serialization.JsonPropertyName("sourceExecutionId")] public string SourceExecutionId { get; set; } @@ -2950,7 +2950,7 @@ public partial class RunTaxonomyPlaybookCommand public string Text { get; set; } [System.Text.Json.Serialization.JsonPropertyName("replayMode")] - public PlaybookReplayMode ReplayMode { get; set; } + public RepeatMode ReplayMode { get; set; } [System.Text.Json.Serialization.JsonPropertyName("sourceExecutionId")] public string SourceExecutionId { get; set; } diff --git a/src/Presentation.Web/Presentation.Web.csproj b/src/Presentation.Web/Presentation.Web.csproj index 507e48c..de7e91c 100644 --- a/src/Presentation.Web/Presentation.Web.csproj +++ b/src/Presentation.Web/Presentation.Web.csproj @@ -22,15 +22,15 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/Presentation.Web/Shell/App.razor b/src/Presentation.Web/Shell/App.razor index 89e8dc8..6bbe70b 100644 --- a/src/Presentation.Web/Shell/App.razor +++ b/src/Presentation.Web/Shell/App.razor @@ -17,13 +17,13 @@ - + - + diff --git a/src/Presentation.Web/Shell/Layout/MainLayout.razor b/src/Presentation.Web/Shell/Layout/MainLayout.razor index 0236eeb..a098e5d 100644 --- a/src/Presentation.Web/Shell/Layout/MainLayout.razor +++ b/src/Presentation.Web/Shell/Layout/MainLayout.razor @@ -24,7 +24,7 @@ Shape="ButtonShape.Rounded" Size="ButtonSize.Small" Title="Go to home page"> - GoodToCode + GoodToCode + + + + + + diff --git a/src/Tests.Integration/AgentFramework/AgentInstructionsComposerTests.cs b/src/Tests.Integration/AgentFramework/AgentInstructionsComposerTests.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests.Integration/AgentFramework/ChatMessageRouterTests.cs b/src/Tests.Integration/AgentFramework/ChatMessageRouterTests.cs index 5f5547a..c11db48 100644 --- a/src/Tests.Integration/AgentFramework/ChatMessageRouterTests.cs +++ b/src/Tests.Integration/AgentFramework/ChatMessageRouterTests.cs @@ -1,5 +1,7 @@ using Goodtocode.AgentFramework.Core.Application.Abstractions; +using Goodtocode.AgentFramework.Infrastructure.AgentFramework.Intents; using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; namespace Goodtocode.AgentFramework.Tests.Integration.AgentFramework; @@ -59,4 +61,42 @@ public async Task ResolveReplyAsyncDirectModeSkipsTheFirstTwoTiers() Assert.AreEqual(1, agent.RunCount); Assert.IsNull(agent.RunOptions[0]); } + + [TestMethod] + public async Task ResolveReplyAsyncAnnouncedWebSearchIsRegeneratedWithoutFutureTense() + { + agent.QueuedResponseTexts.Enqueue("forced-tool-no-call"); + agent.QueuedResponseTexts.Enqueue("I will perform a web search to find the latest information on .NET."); + agent.QueuedResponseTexts.Enqueue("Web search is not available."); + var router = ServiceProvider.GetRequiredService(); + + var reply = await router.ResolveReplyAsync(Guid.NewGuid(), "Tell me about the latest information on .NET", CancellationToken.None); + + Assert.AreEqual("Web search is not available.", reply); + Assert.IsFalse(FutureTenseGuard.ContainsFutureTense(reply), $"Future tense reached the user: {reply}"); + } + + [TestMethod] + public async Task ResolveReplyAsyncPersistentFutureTenseNeverReachesTheUser() + { + agent.ResponseText = "I will perform a web search to find the latest information on .NET."; + var router = ServiceProvider.GetRequiredService(); + + var reply = await router.ResolveReplyAsync(Guid.NewGuid(), "Tell me about the latest information on .NET", CancellationToken.None); + + Assert.AreEqual(FutureTenseGuard.FallbackReply, reply); + Assert.IsFalse(FutureTenseGuard.ContainsFutureTense(reply), $"Future tense reached the user: {reply}"); + } + + [TestMethod] + public async Task ResolveReplyAsyncEveryInferenceCarriesTheNoFutureTensePreamble() + { + var router = ServiceProvider.GetRequiredService(); + + await router.ResolveReplyAsync(Guid.NewGuid(), "Tell me about the latest information on .NET", CancellationToken.None); + + Assert.IsTrue(agent.LastMessages.Any(message => + message.Role == ChatRole.System + && message.Text == ToolRoutingInstructions.NoFutureTensePreamble)); + } } \ No newline at end of file diff --git a/src/Tests.Integration/AgentFramework/FutureTenseGuardTests.cs b/src/Tests.Integration/AgentFramework/FutureTenseGuardTests.cs new file mode 100644 index 0000000..1d42ab6 --- /dev/null +++ b/src/Tests.Integration/AgentFramework/FutureTenseGuardTests.cs @@ -0,0 +1,54 @@ +using Goodtocode.AgentFramework.Infrastructure.AgentFramework.Intents; + +namespace Goodtocode.AgentFramework.Tests.Integration.AgentFramework; + +[TestClass] +public sealed class FutureTenseGuardTests +{ + [TestMethod] + [DataRow("I will perform a web search to find the latest information on .NET.")] + [DataRow("I'll look that up for you.")] + [DataRow("I’ll check now.")] + [DataRow("I am going to search for that.")] + [DataRow("Let me get that for you.")] + [DataRow("One moment please.")] + [DataRow("Please wait while the data is retrieved.")] + [DataRow("We will review the results.")] + [DataRow("I plan to query the actors.")] + [DataRow("Next, I query the sessions.")] + [DataRow("The tool will now search the index.")] + public void ContainsFutureTenseDetectsAnnouncements(string reply) + { + Assert.IsTrue(FutureTenseGuard.ContainsFutureTense(reply)); + Assert.IsFalse(FutureTenseGuard.ContainsFutureTense(FutureTenseGuard.Enforce(reply))); + } + + [TestMethod] + [DataRow("Web search is not available.")] + [DataRow("You have no chat sessions yet.")] + [DataRow("I searched the actors and found 3 matches.")] + [DataRow("The request was not completed.")] + public void ContainsFutureTenseAllowsPastAndPresentTense(string reply) + { + Assert.IsFalse(FutureTenseGuard.ContainsFutureTense(reply)); + Assert.AreEqual(reply, FutureTenseGuard.Enforce(reply)); + } + + [TestMethod] + public void EnforceKeepsCompliantSentencesAndTableRows() + { + var reply = "Found 1 actor. I will fetch more.\n| # | Name |\n| 1 | Ada |"; + + var result = FutureTenseGuard.Enforce(reply); + + Assert.IsFalse(FutureTenseGuard.ContainsFutureTense(result)); + StringAssert.Contains(result, "Found 1 actor."); + StringAssert.Contains(result, "| 1 | Ada |"); + } + + [TestMethod] + public void EnforceReturnsFallbackWhenNothingCompliantRemains() + { + Assert.AreEqual(FutureTenseGuard.FallbackReply, FutureTenseGuard.Enforce("I will look into it. Let me check.")); + } +} diff --git a/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature b/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature new file mode 100644 index 0000000..07060a5 --- /dev/null +++ b/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature @@ -0,0 +1,32 @@ +@playbookRepeatability +Feature: Playbook repeatability (Rerun, Recall, Replay) +As a playbook host +I repeat a previous SQL Statistics execution in a chosen mode +Then Governance decides which stages run and Playbook runs only those, so the result matches the mode's contract + +Scenario Outline: Repeat a prior execution after the live database changed + Given a SQL statistics playbook is registered + And the connected database reports a size of GB + And I have rerun the SQL statistics playbook for database "" + And the connected database then reports a size of GB + When I repeat the SQL statistics playbook in "" mode + Then the repeat reports mode "" + And the repeat evaluation reports "" + And the repeat is linked to its source "" + And the repeat reuses the recorded collect input "" "" + +Examples: + | database | originalGb | liveGb | mode | classification | linked | reusesInput | + | Contoso | 50 | 500 | Rerun | Large | false | false | + | Contoso | 50 | 500 | Replay | Medium | true | true | + | Contoso | 50 | 500 | Recall | Medium | true | true | + +Scenario Outline: Repeat without a prior execution is rejected + Given a SQL statistics playbook is registered + When I repeat the SQL statistics playbook in "" mode + Then the repeat is rejected as "" + +Examples: + | mode | rejection | + | Recall | NotFound | + | Replay | NotFound | diff --git a/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature.cs b/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature.cs new file mode 100644 index 0000000..7802a55 --- /dev/null +++ b/src/Tests.Integration/Playbooks/PlaybookRepeatability.feature.cs @@ -0,0 +1,233 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by Reqnroll (https://reqnroll.net/). +// Reqnroll Version:3.0.0.0 +// Reqnroll Generator Version:3.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +using Reqnroll; +namespace Goodtocode.AgentFramework.Tests.Integration.Playbooks +{ + + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Reqnroll", "3.0.0.0")] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute()] + public partial class PlaybookRepeatabilityRerunRecallReplayFeature + { + + private global::Reqnroll.ITestRunner testRunner; + + private Microsoft.VisualStudio.TestTools.UnitTesting.TestContext _testContext; + + private static string[] featureTags = new string[] { + "playbookRepeatability"}; + + private static global::Reqnroll.FeatureInfo featureInfo = new global::Reqnroll.FeatureInfo(new global::System.Globalization.CultureInfo("en-US"), "Playbooks", "Playbook repeatability (Rerun, Recall, Replay)", "As a playbook host\r\nI repeat a previous SQL Statistics execution in a chosen mode" + + "\r\nThen Governance decides which stages run and Playbook runs only those, so the " + + "result matches the mode\'s contract", global::Reqnroll.ProgrammingLanguage.CSharp, featureTags, InitializeCucumberMessages()); + +#line 1 "PlaybookRepeatability.feature" +#line hidden + + public virtual Microsoft.VisualStudio.TestTools.UnitTesting.TestContext TestContext + { + get + { + return this._testContext; + } + set + { + this._testContext = value; + } + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.ClassInitializeAttribute()] + public static async global::System.Threading.Tasks.Task FeatureSetupAsync(Microsoft.VisualStudio.TestTools.UnitTesting.TestContext testContext) + { + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.ClassCleanupAttribute()] + public static async global::System.Threading.Tasks.Task FeatureTearDownAsync() + { + await global::Reqnroll.TestRunnerManager.ReleaseFeatureAsync(featureInfo); + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute()] + public async global::System.Threading.Tasks.Task TestInitializeAsync() + { + testRunner = global::Reqnroll.TestRunnerManager.GetTestRunnerForAssembly(featureHint: featureInfo); + try + { + if (((testRunner.FeatureContext != null) + && (testRunner.FeatureContext.FeatureInfo.Equals(featureInfo) == false))) + { + await testRunner.OnFeatureEndAsync(); + } + } + finally + { + if (((testRunner.FeatureContext != null) + && testRunner.FeatureContext.BeforeFeatureHookFailed)) + { + throw new global::Reqnroll.ReqnrollException("Scenario skipped because of previous before feature hook error"); + } + if ((testRunner.FeatureContext == null)) + { + await testRunner.OnFeatureStartAsync(featureInfo); + } + } + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute()] + public async global::System.Threading.Tasks.Task TestTearDownAsync() + { + if ((testRunner == null)) + { + return; + } + try + { + await testRunner.OnScenarioEndAsync(); + } + finally + { + global::Reqnroll.TestRunnerManager.ReleaseTestRunner(testRunner); + testRunner = null; + } + } + + public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, global::Reqnroll.RuleInfo ruleInfo) + { + testRunner.OnScenarioInitialize(scenarioInfo, ruleInfo); + testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(_testContext); + } + + public async global::System.Threading.Tasks.Task ScenarioStartAsync() + { + await testRunner.OnScenarioStartAsync(); + } + + public async global::System.Threading.Tasks.Task ScenarioCleanupAsync() + { + await testRunner.CollectScenarioErrorsAsync(); + } + + private static global::Reqnroll.Formatters.RuntimeSupport.FeatureLevelCucumberMessages InitializeCucumberMessages() + { + return new global::Reqnroll.Formatters.RuntimeSupport.FeatureLevelCucumberMessages("Playbooks/PlaybookRepeatability.feature.ndjson", 7); + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute(callerLineNumber: 7, DisplayName="Repeat a prior execution after the live database changed")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Repeat a prior execution after the live database changed")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "Playbook repeatability (Rerun, Recall, Replay)")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("playbookRepeatability")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute("Contoso", "50", "500", "Rerun", "Large", "false", "false", "0", null, DisplayName="Repeat a prior execution after the live database changed(Contoso,50,500,Rerun,Lar" + + "ge,false,false,0)")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute("Contoso", "50", "500", "Replay", "Medium", "true", "true", "1", null, DisplayName="Repeat a prior execution after the live database changed(Contoso,50,500,Replay,Me" + + "dium,true,true,1)")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute("Contoso", "50", "500", "Recall", "Medium", "true", "true", "2", null, DisplayName="Repeat a prior execution after the live database changed(Contoso,50,500,Recall,Me" + + "dium,true,true,2)")] + public async global::System.Threading.Tasks.Task RepeatAPriorExecutionAfterTheLiveDatabaseChanged(string database, string originalGb, string liveGb, string mode, string classification, string linked, string reusesInput, string @__pickleIndex, string[] exampleTags) + { + string[] tagsOfScenario = exampleTags; + global::System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new global::System.Collections.Specialized.OrderedDictionary(); + argumentsOfScenario.Add("database", database); + argumentsOfScenario.Add("originalGb", originalGb); + argumentsOfScenario.Add("liveGb", liveGb); + argumentsOfScenario.Add("mode", mode); + argumentsOfScenario.Add("classification", classification); + argumentsOfScenario.Add("linked", linked); + argumentsOfScenario.Add("reusesInput", reusesInput); + string pickleIndex = @__pickleIndex; + global::Reqnroll.ScenarioInfo scenarioInfo = new global::Reqnroll.ScenarioInfo("Repeat a prior execution after the live database changed", null, tagsOfScenario, argumentsOfScenario, featureTags, pickleIndex); + string[] tagsOfRule = ((string[])(null)); + global::Reqnroll.RuleInfo ruleInfo = null; +#line 7 +this.ScenarioInitialize(scenarioInfo, ruleInfo); +#line hidden + if ((global::Reqnroll.TagHelper.ContainsIgnoreTag(scenarioInfo.CombinedTags) || global::Reqnroll.TagHelper.ContainsIgnoreTag(featureTags))) + { + await testRunner.SkipScenarioAsync(); + } + else + { + await this.ScenarioStartAsync(); +#line 8 + await testRunner.GivenAsync("a SQL statistics playbook is registered", ((string)(null)), ((global::Reqnroll.Table)(null)), "Given "); +#line hidden +#line 9 + await testRunner.AndAsync(string.Format("the connected database reports a size of {0} GB", originalGb), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden +#line 10 + await testRunner.AndAsync(string.Format("I have rerun the SQL statistics playbook for database \"{0}\"", database), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden +#line 11 + await testRunner.AndAsync(string.Format("the connected database then reports a size of {0} GB", liveGb), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden +#line 12 + await testRunner.WhenAsync(string.Format("I repeat the SQL statistics playbook in \"{0}\" mode", mode), ((string)(null)), ((global::Reqnroll.Table)(null)), "When "); +#line hidden +#line 13 + await testRunner.ThenAsync(string.Format("the repeat reports mode \"{0}\"", mode), ((string)(null)), ((global::Reqnroll.Table)(null)), "Then "); +#line hidden +#line 14 + await testRunner.AndAsync(string.Format("the repeat evaluation reports \"{0}\"", classification), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden +#line 15 + await testRunner.AndAsync(string.Format("the repeat is linked to its source \"{0}\"", linked), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden +#line 16 + await testRunner.AndAsync(string.Format("the repeat reuses the recorded collect input \"{0}\" \"{1}\"", database, reusesInput), ((string)(null)), ((global::Reqnroll.Table)(null)), "And "); +#line hidden + } + await this.ScenarioCleanupAsync(); + } + + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute(callerLineNumber: 24, DisplayName="Repeat without a prior execution is rejected")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Repeat without a prior execution is rejected")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "Playbook repeatability (Rerun, Recall, Replay)")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryAttribute("playbookRepeatability")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute("Recall", "NotFound", "3", null, DisplayName="Repeat without a prior execution is rejected(Recall,NotFound,3)")] + [global::Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute("Replay", "NotFound", "4", null, DisplayName="Repeat without a prior execution is rejected(Replay,NotFound,4)")] + public async global::System.Threading.Tasks.Task RepeatWithoutAPriorExecutionIsRejected(string mode, string rejection, string @__pickleIndex, string[] exampleTags) + { + string[] tagsOfScenario = exampleTags; + global::System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new global::System.Collections.Specialized.OrderedDictionary(); + argumentsOfScenario.Add("mode", mode); + argumentsOfScenario.Add("rejection", rejection); + string pickleIndex = @__pickleIndex; + global::Reqnroll.ScenarioInfo scenarioInfo = new global::Reqnroll.ScenarioInfo("Repeat without a prior execution is rejected", null, tagsOfScenario, argumentsOfScenario, featureTags, pickleIndex); + string[] tagsOfRule = ((string[])(null)); + global::Reqnroll.RuleInfo ruleInfo = null; +#line 24 +this.ScenarioInitialize(scenarioInfo, ruleInfo); +#line hidden + if ((global::Reqnroll.TagHelper.ContainsIgnoreTag(scenarioInfo.CombinedTags) || global::Reqnroll.TagHelper.ContainsIgnoreTag(featureTags))) + { + await testRunner.SkipScenarioAsync(); + } + else + { + await this.ScenarioStartAsync(); +#line 25 + await testRunner.GivenAsync("a SQL statistics playbook is registered", ((string)(null)), ((global::Reqnroll.Table)(null)), "Given "); +#line hidden +#line 26 + await testRunner.WhenAsync(string.Format("I repeat the SQL statistics playbook in \"{0}\" mode", mode), ((string)(null)), ((global::Reqnroll.Table)(null)), "When "); +#line hidden +#line 27 + await testRunner.ThenAsync(string.Format("the repeat is rejected as \"{0}\"", rejection), ((string)(null)), ((global::Reqnroll.Table)(null)), "Then "); +#line hidden + } + await this.ScenarioCleanupAsync(); + } + } +} +#pragma warning restore +#endregion diff --git a/src/Tests.Integration/Playbooks/PlaybookRepeatabilityStepDefinitions.cs b/src/Tests.Integration/Playbooks/PlaybookRepeatabilityStepDefinitions.cs new file mode 100644 index 0000000..efc6bf6 --- /dev/null +++ b/src/Tests.Integration/Playbooks/PlaybookRepeatabilityStepDefinitions.cs @@ -0,0 +1,116 @@ +using Goodtocode.AgentFramework.Core.Application.Common.Exceptions; +using Goodtocode.AgentFramework.Core.Application.Playbooks; +using Goodtocode.AgentFramework.Core.Application.Playbooks.SqlStatistics; +using Goodtocode.AgentFramework.Core.Domain.Playbooks; +using Goodtocode.Agents.Governance.Domain; + +namespace Goodtocode.AgentFramework.Tests.Integration.Playbooks; + +[Binding] +[Scope(Tag = "playbookRepeatability")] +public sealed class PlaybookRepeatabilityStepDefinitions : TestBase +{ + private PlaybookExecutionResultDto? _original; + private PlaybookExecutionResultDto? _repeat; + private Exception? _rejection; + + [Given("a SQL statistics playbook is registered")] + public async Task GivenASqlStatisticsPlaybookIsRegistered() + { + await Sender.Send(new CreatePlaybookCommand + { + Key = "sql-statistics", + Name = "SQL Statistics Classification", + Description = "Deterministic CER workflow for repeatability tests.", + WorkflowType = "Deterministic", + Version = "v1", + Collect = Step("Collect database statistics", PlaybookActionFormat.SqlQuery, "SELECT 1;"), + Evaluate = Step("Classify database size", PlaybookActionFormat.Rubric, "Small: 0-20 GB; Medium: 20-100 GB; Large: 100+ GB."), + Record = Step("Record classification", PlaybookActionFormat.Template, "{DatabaseName} is {Classification} at {SizeGb} GB.") + }, CancellationToken.None); + } + + [Given("the connected database reports a size of (.*) GB")] + [Given("the connected database then reports a size of (.*) GB")] + public void GivenTheConnectedDatabaseReportsASizeOfGb(double sizeGb) + { + sqlDatabaseStatisticsProvider.SizeGb = sizeGb; + } + + [Given("I have rerun the SQL statistics playbook for database \"(.*)\"")] + public async Task GivenIHaveRerunTheSqlStatisticsPlaybookForDatabase(string database) + { + _original = await Sender.Send(new RunSqlStatisticsPlaybookCommand { DatabaseName = database }, CancellationToken.None); + } + + [When("I repeat the SQL statistics playbook in \"(.*)\" mode")] + public async Task WhenIRepeatTheSqlStatisticsPlaybookInMode(string mode) + { + var command = new RunSqlStatisticsPlaybookCommand + { + DatabaseName = "Contoso", + ReplayMode = Enum.Parse(mode), + SourceExecutionId = _original?.ExecutionId.ToString() + }; + + try + { + _repeat = await Sender.Send(command, CancellationToken.None); + } + catch (Exception ex) + { + _rejection = ex; + } + } + + [Then("the repeat reports mode \"(.*)\"")] + public void ThenTheRepeatReportsMode(string mode) + { + _repeat.ShouldNotBeNull(); + _repeat!.ReplayMode.ShouldBe(mode); + } + + [Then("the repeat evaluation reports \"(.*)\"")] + public void ThenTheRepeatEvaluationReports(string classification) + { + _repeat.ShouldNotBeNull(); + _repeat!.EvaluateSummary.Contains(classification, StringComparison.OrdinalIgnoreCase).ShouldBeTrue(); + } + + [Then("the repeat is linked to its source \"(.*)\"")] + public void ThenTheRepeatIsLinkedToItsSource(bool linked) + { + _repeat.ShouldNotBeNull(); + if (linked) + { + _repeat!.SourceExecutionId.ShouldBe(_original!.ExecutionId.ToString()); + } + else + { + _repeat!.SourceExecutionId.ShouldBeNull(); + } + } + + [Then("the repeat reuses the recorded collect input \"(.*)\" \"(.*)\"")] + public void ThenTheRepeatReusesTheRecordedCollectInput(string database, bool reuses) + { + _repeat.ShouldNotBeNull(); + _repeat!.CollectInput.ShouldBe(database); + (_repeat.SourceExecutionId is not null).ShouldBe(reuses); + } + + [Then("the repeat is rejected as \"(.*)\"")] + public void ThenTheRepeatIsRejectedAs(string rejection) + { + _rejection.ShouldNotBeNull(); + _rejection!.GetType().Name.ShouldBe($"Custom{rejection}Exception"); + } + + private static PlaybookStepInput Step(string name, PlaybookActionFormat format, string definition) => new() + { + Name = name, + Description = name, + ActionFormat = format, + ActionDefinition = definition + }; +} diff --git a/src/Tests.Integration/Playbooks/PlaybookReplayTests.cs b/src/Tests.Integration/Playbooks/PlaybookReplayTests.cs index a8115d9..748b04d 100644 --- a/src/Tests.Integration/Playbooks/PlaybookReplayTests.cs +++ b/src/Tests.Integration/Playbooks/PlaybookReplayTests.cs @@ -2,7 +2,7 @@ using Goodtocode.AgentFramework.Core.Application.Playbooks.SqlStatistics; using Goodtocode.AgentFramework.Core.Application.Playbooks.Taxonomy; using Goodtocode.AgentFramework.Core.Domain.Playbooks; -using Goodtocode.Agents.Playbook.Execution; +using Goodtocode.Agents.Governance.Domain; namespace Goodtocode.AgentFramework.Tests.Integration.Playbooks; @@ -92,7 +92,7 @@ public async Task RerunPersistsEvidenceAndFindingForLaterReplay() var dto = await Sender.Send(new RunSqlStatisticsPlaybookCommand { DatabaseName = "Contoso" }, CancellationToken.None); - dto.ReplayMode.ShouldBe(nameof(PlaybookReplayMode.Rerun)); + dto.ReplayMode.ShouldBe(nameof(RepeatMode.Rerun)); dto.ExecutionId.ShouldNotBeEmpty(); string.IsNullOrWhiteSpace(dto.EvidenceJson).ShouldBeFalse(); string.IsNullOrWhiteSpace(dto.FindingJson).ShouldBeFalse(); @@ -118,11 +118,11 @@ public async Task RecallReusesPriorEvidenceAndFindingWithoutRecollecting() var recalled = await Sender.Send(new RunSqlStatisticsPlaybookCommand { DatabaseName = "ignored-for-recall", - ReplayMode = PlaybookReplayMode.Recall, + ReplayMode = RepeatMode.Recall, SourceExecutionId = original.ExecutionId.ToString() }, CancellationToken.None); - recalled.ReplayMode.ShouldBe(nameof(PlaybookReplayMode.Recall)); + recalled.ReplayMode.ShouldBe(nameof(RepeatMode.Recall)); recalled.SourceExecutionId.ShouldBe(original.ExecutionId.ToString()); recalled.CollectInput.ShouldBe("Contoso"); recalled.EvaluateSummary.ShouldBe(original.EvaluateSummary); @@ -143,18 +143,18 @@ public async Task ReplayReusesPriorEvidenceButReEvaluates() var replayed = await Sender.Send(new RunSqlStatisticsPlaybookCommand { DatabaseName = "ignored-for-replay", - ReplayMode = PlaybookReplayMode.Replay, + ReplayMode = RepeatMode.Replay, SourceExecutionId = original.ExecutionId.ToString() }, CancellationToken.None); - replayed.ReplayMode.ShouldBe(nameof(PlaybookReplayMode.Replay)); + replayed.ReplayMode.ShouldBe(nameof(RepeatMode.Replay)); replayed.SourceExecutionId.ShouldBe(original.ExecutionId.ToString()); replayed.CollectInput.ShouldBe("Contoso"); replayed.EvaluateSummary.ShouldBe(original.EvaluateSummary); } [TestMethod] - public async Task TaxonomyRecallSkipsCollectAndEvaluateAgentCalls() + public async Task TaxonomyRecallMakesNoAgentCallsAndReturnsStoredRecord() { await SeedTaxonomyPlaybookAsync(); @@ -164,19 +164,19 @@ public async Task TaxonomyRecallSkipsCollectAndEvaluateAgentCalls() var original = await Sender.Send(new RunTaxonomyPlaybookCommand { Text = "Quarterly budget forecast" }, CancellationToken.None); - // Only the Record stage's agent call is queued; Recall must not invoke Collect or - // Evaluate, so no extra queued responses are needed for those stages. - agent.QueuedResponseTexts.Enqueue("""{"summary": "Recalled: Classified as Finance with high confidence."}"""); + // Recall is a pure read: if any stage called the agent it would consume this sentinel. + agent.QueuedResponseTexts.Enqueue("""{"summary": "sentinel: must not be consumed"}"""); var recalled = await Sender.Send(new RunTaxonomyPlaybookCommand { Text = "ignored-for-recall", - ReplayMode = PlaybookReplayMode.Recall, + ReplayMode = RepeatMode.Recall, SourceExecutionId = original.ExecutionId.ToString() }, CancellationToken.None); - recalled.ReplayMode.ShouldBe(nameof(PlaybookReplayMode.Recall)); + recalled.ReplayMode.ShouldBe(nameof(RepeatMode.Recall)); recalled.EvaluateSummary.ShouldBe(original.EvaluateSummary); - agent.QueuedResponseTexts.Count.ShouldBe(0); + recalled.RecordSummary.ShouldBe(original.RecordSummary); + agent.QueuedResponseTexts.Count.ShouldBe(1); } } diff --git a/src/Tests.Integration/Tests.Integration.csproj b/src/Tests.Integration/Tests.Integration.csproj index 9e3139e..d8893d8 100644 --- a/src/Tests.Integration/Tests.Integration.csproj +++ b/src/Tests.Integration/Tests.Integration.csproj @@ -27,12 +27,12 @@ - + - + @@ -49,4 +49,4 @@ - + \ No newline at end of file