microsoft / microsoft/agent-framework
.NET: [Bug]: DevUI always sends new session
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 2.3k
- Avg merge
- 2d 45m
- Merged PRs (30d)
- 358
Description
### Description
Hi everyone,
I'm trying to save conversation messages to a database using ChatHistoryProvider. However, InvokeContext.Session.StateBag seems to reset with every new message, creating a fresh session context each time. As a result, I can't track or associate incoming messages with their parent conversation.
Is DevUI designed to spawn a new session per message, or is there a specific way I should be passing/maintaining the conversation ID across requests?
Thanks for any insights!
The conversationId is red in image below because it has been recreated
### Code Sample
```markdown
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.DevUI;
using Microsoft.Agents.AI.Hosting;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Chat;
using System.ClientModel;
using TestChatHistoryProvider;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var apiKey = builder.Configuration["ApiKey"]
?? throw new InvalidOperationException("Configuration value 'ApiKey' is missing.");
var openAIClient = new ChatClient(
model: "gpt-5-mini",
credential: new ApiKeyCredential(apiKey),
options: new OpenAIClientOptions()
{
Endpoint = new Uri("myendpoind")
}
).AsIChatClient();
var agentBuilder = builder.AddAIAgent("Alex", (sp, key) =>
{
return openAIClient.AsAIAgent(new ChatClientAgentOptions()
{
Name = "Alex",
ChatOptions = new ChatOptions()
{
Instructions = "You are a helpful assistant.",
},
ChatHistoryProvider = new CosmosChatHistoryProvider()
})
.AsBuilder()
.UseToolApproval(new ToolApprovalAgentOptions
{
AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})
.Build()
;
});
builder.Services.AddOpenAIResponses();
builder.Services.AddOpenAIConversations();
builder.AddDevUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapOpenAIResponses();
app.MapOpenAIConversations();
app.MapDevUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
namespace TestChatHistoryProvider
{
public class DummyChatHistoryProvider : ChatHistoryProvider, IAsyncDisposable
{
private readonly ProviderSessionState _sessionState;
public DummyChatHistoryProvider()
{
_sessionState = new ProviderSessionState((_ => new State(Guid.NewGuid().ToString("N"))), this.GetType().Name);
}
protected override ValueTask> ProvideChatHistoryAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
//context.Session.StateBag here is recreated with new incoming messages
var state = _sessionState.GetOrInitializeState(context.Session);
return base.ProvideChatHistoryAsync(context, cancellationToken);
}
public ValueTask DisposeAsync()
{
return ValueTask.CompletedTask;
}
public sealed class State
{
public State(string conversationId)
{
this.ConversationId = conversationId ?? throw new ArgumentNullException(nameof(conversationId));
}
public string ConversationId { get; set; }
}
}
}
```
### Error Messages / Stack Traces
```markdown
```
### Package Versions
### .NET Version
.NET 10
### Additional Context
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.