Skip to content

Python: .NET: Fix .NET conversation memory in DevUI (#3484)#4294

Open
victordibia wants to merge 5 commits intomainfrom
devui_dot_net_memory
Open

Python: .NET: Fix .NET conversation memory in DevUI (#3484)#4294
victordibia wants to merge 5 commits intomainfrom
devui_dot_net_memory

Conversation

@victordibia
Copy link
Contributor

@victordibia victordibia commented Feb 26, 2026

Fix .NET conversation memory in DevUI (#3484)

Agents hosted via the .NET DevUI couldn't remember prior messages across turns. The root cause: InMemoryResponsesService stored conversation items after each execution but never loaded them before the next one, so agents always received only the current message with no history.

What changed

  • New: ItemResourceConversions.ToChatMessages() — converts stored ItemResource objects back to ChatMessage for history injection
  • Modified: InMemoryResponsesService now loads prior conversation items from storage, converts them to ChatMessage list, and passes them to the executor before each run
  • Modified: IResponseExecutor.ExecuteAsync and both implementations (AIAgentResponseExecutor, HostedAgentResponseExecutor) accept an optional conversationHistory parameter and prepend it to the current input

Test plan

  • New test: CreateResponse_WithConversation_SecondRequestIncludesPriorMessagesAsync — sends two messages in the same conversation, asserts the agent receives all 3 messages (prior user + prior assistant + new user) on the second call
  • Full suite: 375/375 passed, zero regressions

Other Changes

Contribution Checklist

Closes #3484

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@github-actions github-actions bot changed the title Fix .NET conversation memory in DevUI (#3484) .NET: Fix .NET conversation memory in DevUI (#3484) Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a critical bug in the .NET DevUI where agents couldn't remember prior messages across conversation turns. The root cause was that InMemoryResponsesService stored conversation items after each execution but never loaded them before the next one, resulting in agents receiving only the current message with no history context.

Changes:

  • Added ItemResourceConversions.ToChatMessages() to convert stored conversation items back to ChatMessage objects for history injection
  • Modified InMemoryResponsesService to load prior conversation items from storage and pass them to executors before each run
  • Updated IResponseExecutor interface and both implementations (AIAgentResponseExecutor, HostedAgentResponseExecutor) to accept an optional conversationHistory parameter

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemResourceConversions.cs New converter that transforms stored ItemResource objects back to ChatMessage objects, handling messages, function calls, and function results
dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/InMemoryResponsesService.cs Added conversation history loading logic that retrieves up to 100 prior items in ascending order and passes them to the executor
dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/IResponseExecutor.cs Extended interface to accept optional conversationHistory parameter
dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/AIAgentResponseExecutor.cs Prepends conversation history to input messages before agent execution
dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/HostedAgentResponseExecutor.cs Prepends conversation history to input messages before agent execution
dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/TestHelpers.cs Added ConversationMemoryMockChatClient that captures full message lists for testing conversation history
dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/OpenAIResponsesIntegrationTests.cs Added comprehensive test verifying conversation history is passed correctly on subsequent requests

…ent type on both objects (.type) and dicts (.get("type")). Replaced all 4 bare event.type accesses in _executor.py (lines 267, 477, 499, 523).

Root cause: PR #3690 changed event.__class__.__name__ == "RequestInfoEvent" (safe) to event.type == "request_info" (crashes on dicts), but _execute_workflow still yields raw dicts on error paths.

Test: test_workflow_error_yields_dict_event_without_crash — mocks a workflow that raises, verifies execute_entity consumes the dict error events without crashing.
@github-actions github-actions bot changed the title .NET: Fix .NET conversation memory in DevUI (#3484) Python: .NET: Fix .NET conversation memory in DevUI (#3484) Feb 26, 2026
@markwallace-microsoft
Copy link
Member

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
TOTAL22174276287% 
report-only-changed-files is enabled. No files were changed during this commit :)

Python Unit Test Overview

Tests Skipped Failures Errors Time
4672 247 💤 0 ❌ 0 🔥 1m 19s ⏱️

public async IAsyncEnumerable<StreamingResponseEvent> ExecuteAsync(
AgentInvocationContext context,
CreateResponse request,
IReadOnlyList<ChatMessage>? conversationHistory = null,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to add conversationHistory to AgentInvocationContext?
History sounds like an essential part of the conversation.

@DeagleGross DeagleGross requested a review from westey-m February 26, 2026 09:53
var context = new AgentInvocationContext(new IdGenerator(responseId: responseId, conversationId: state.Response?.Conversation?.Id));

// Load conversation history if a conversation ID is provided
IReadOnlyList<Extensions.AI.ChatMessage>? conversationHistory = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this change does fix loading of chat history, the code is still broken for other scenarios.
We should really be storing and loading the AgentSession based on the request conversation id. We can then attach a custom per-run ChatHistoryProvider which loads chat history for the session from _conversationStorage and persists new messages into _conversationStorage. If we don't store the session, memory scenarios are broken for all agents exposed via this host.

Happy to work with you get this fixed for all memory scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devui DevUI-related items .NET python

Projects

None yet

5 participants