diff --git a/EssentialCSharp.Chat.Shared/Services/AIChatService.cs b/EssentialCSharp.Chat.Shared/Services/AIChatService.cs index 984cb455..481a5711 100644 --- a/EssentialCSharp.Chat.Shared/Services/AIChatService.cs +++ b/EssentialCSharp.Chat.Shared/Services/AIChatService.cs @@ -54,9 +54,9 @@ public AIChatService(IOptions options, AISearchService searchService, bool enableContextualSearch = false, CancellationToken cancellationToken = default) { - var responseOptions = await CreateResponseOptionsAsync(previousResponseId, tools, reasoningEffortLevel, mcpClient: mcpClient, cancellationToken: cancellationToken); + var responseOptions = await CreateResponseOptionsAsync(systemPrompt, previousResponseId, tools, reasoningEffortLevel, mcpClient: mcpClient, cancellationToken: cancellationToken); var enrichedPrompt = await EnrichPromptWithContext(prompt, enableContextualSearch, cancellationToken); - return await GetChatCompletionCore(enrichedPrompt, responseOptions, systemPrompt, mcpClient, cancellationToken); + return await GetChatCompletionCore(enrichedPrompt, responseOptions, mcpClient, cancellationToken); } /// @@ -82,17 +82,12 @@ public AIChatService(IOptions options, AISearchService searchService, bool enableContextualSearch = false, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) { - var responseOptions = await CreateResponseOptionsAsync(previousResponseId, tools, reasoningEffortLevel, mcpClient: mcpClient, cancellationToken: cancellationToken); + var responseOptions = await CreateResponseOptionsAsync(systemPrompt, previousResponseId, tools, reasoningEffortLevel, mcpClient: mcpClient, cancellationToken: cancellationToken); var enrichedPrompt = await EnrichPromptWithContext(prompt, enableContextualSearch, cancellationToken); - // Construct the user input with system context if provided - var systemContext = !string.IsNullOrWhiteSpace(systemPrompt) ? systemPrompt : _Options.SystemPrompt; - // Create the streaming response using the Responses API #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - List responseItems = systemContext is not null - ? [ResponseItem.CreateSystemMessageItem(systemContext), ResponseItem.CreateUserMessageItem(enrichedPrompt)] - : [ResponseItem.CreateUserMessageItem(enrichedPrompt)]; + List responseItems = [ResponseItem.CreateUserMessageItem(enrichedPrompt)]; #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. var streamingUpdates = _ResponseClient.CreateResponseStreamingAsync( responseItems, @@ -259,7 +254,8 @@ private async Task EnrichPromptWithContext(string prompt, bool enableCon /// Creates response options with optional features /// #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - private static async Task CreateResponseOptionsAsync( + private async Task CreateResponseOptionsAsync( + string? systemPrompt = null, string? previousResponseId = null, IEnumerable? tools = null, ResponseReasoningEffortLevel? reasoningEffortLevel = null, @@ -270,6 +266,14 @@ private static async Task CreateResponseOptionsAsync( var options = new ResponseCreationOptions(); #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // Set the system prompt via Instructions — this is stateless across turns when using previous_response_id, + // preventing accumulation of system messages in the conversation context. + var resolvedSystemPrompt = !string.IsNullOrWhiteSpace(systemPrompt) ? systemPrompt : _Options.SystemPrompt; + if (!string.IsNullOrWhiteSpace(resolvedSystemPrompt)) + { + options.Instructions = resolvedSystemPrompt; + } + // Add conversation context if available if (!string.IsNullOrEmpty(previousResponseId)) { @@ -318,17 +322,12 @@ private static async Task CreateResponseOptionsAsync( #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. ResponseCreationOptions responseOptions, #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - string? systemPrompt = null, McpClient? mcpClient = null, CancellationToken cancellationToken = default) { - // Construct the user input with system context if provided - var systemContext = !string.IsNullOrWhiteSpace(systemPrompt) ? systemPrompt : _Options.SystemPrompt; - + // Create the response using the Responses API #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - List responseItems = systemContext is not null - ? [ResponseItem.CreateSystemMessageItem(systemContext), ResponseItem.CreateUserMessageItem(prompt)] - : [ResponseItem.CreateUserMessageItem(prompt)]; + List responseItems = [ResponseItem.CreateUserMessageItem(prompt)]; #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. const int MaxToolCallIterations = 10;