.NET: [BREAKING] Move AgentSession.Serialize to AIAgent (#3650)

* Move AgentSession.Serialize to AIAgent

* Address PR comments.

* Improve code and fix unit test

* Update test agents to return a default json element instead of throwing where the the result of the serialization is never used.

* Update further tests to actually serialize the session
This commit is contained in:
westey
2026-02-04 15:52:15 +00:00
committed by GitHub
parent d742364d81
commit 6255abd687
52 changed files with 295 additions and 46 deletions
@@ -31,6 +31,16 @@ namespace SampleApp
public override ValueTask<AgentSession> CreateSessionAsync(CancellationToken cancellationToken = default)
=> new(new CustomAgentSession());
public override JsonElement SerializeSession(AgentSession session, JsonSerializerOptions? jsonSerializerOptions = null)
{
if (session is not CustomAgentSession typedSession)
{
throw new ArgumentException($"The provided session is not of type {nameof(CustomAgentSession)}.", nameof(session));
}
return typedSession.Serialize(jsonSerializerOptions);
}
public override ValueTask<AgentSession> DeserializeSessionAsync(JsonElement serializedSession, JsonSerializerOptions? jsonSerializerOptions = null, CancellationToken cancellationToken = default)
=> new(new CustomAgentSession(serializedSession, jsonSerializerOptions));
@@ -136,6 +146,9 @@ namespace SampleApp
internal CustomAgentSession(JsonElement serializedSessionState, JsonSerializerOptions? jsonSerializerOptions = null)
: base(serializedSessionState, jsonSerializerOptions) { }
internal new JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null)
=> base.Serialize(jsonSerializerOptions);
}
}
}
@@ -55,7 +55,7 @@ await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(await agent.RunAsync("What do you already know about my upcoming trip?", session));
Console.WriteLine("\n>> Serialize and deserialize the session to demonstrate persisted state\n");
JsonElement serializedSession = session.Serialize();
JsonElement serializedSession = agent.SerializeSession(session);
AgentSession restoredSession = await agent.DeserializeSessionAsync(serializedSession);
Console.WriteLine(await agent.RunAsync("Can you recap the personal details you remember?", restoredSession));
@@ -47,7 +47,7 @@ Console.WriteLine(await agent.RunAsync("My name is Ruaidhrí", session));
Console.WriteLine(await agent.RunAsync("I am 20 years old", session));
// We can serialize the session. The serialized state will include the state of the memory component.
var sesionElement = session.Serialize();
JsonElement sesionElement = agent.SerializeSession(session);
Console.WriteLine("\n>> Use deserialized session with previously created memories\n");
@@ -25,7 +25,7 @@ AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Serialize the session state to a JsonElement, so it can be stored for later use.
JsonElement serializedSession = session.Serialize();
JsonElement serializedSession = agent.SerializeSession(session);
// Save the serialized session to a temporary file (for demonstration purposes).
string tempFilePath = Path.GetTempFileName();
@@ -47,7 +47,7 @@ Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session
// Serialize the session state, so it can be stored for later use.
// Since the chat history is stored in the vector store, the serialized session
// only contains the guid that the messages are stored under in the vector store.
JsonElement serializedSession = session.Serialize();
JsonElement serializedSession = agent.SerializeSession(session);
Console.WriteLine("\n--- Serialized session ---\n");
Console.WriteLine(JsonSerializer.Serialize(serializedSession, new JsonSerializerOptions { WriteIndented = true }));
@@ -40,7 +40,7 @@ AgentResponse response = await agent.RunAsync("Write a very long novel about a t
// Poll for background responses until complete.
while (response.ContinuationToken is not null)
{
PersistAgentState(session, response.ContinuationToken);
PersistAgentState(agent, session, response.ContinuationToken);
await Task.Delay(TimeSpan.FromSeconds(10));
@@ -52,9 +52,9 @@ while (response.ContinuationToken is not null)
Console.WriteLine(response.Text);
void PersistAgentState(AgentSession? session, ResponseContinuationToken? continuationToken)
void PersistAgentState(AIAgent agent, AgentSession? session, ResponseContinuationToken? continuationToken)
{
stateStore["session"] = session!.Serialize();
stateStore["session"] = agent.SerializeSession(session!);
stateStore["continuationToken"] = JsonSerializer.SerializeToElement(continuationToken, AgentAbstractionsJsonUtilities.DefaultOptions.GetTypeInfo(typeof(ResponseContinuationToken)));
}
@@ -65,7 +65,7 @@ Console.WriteLine(await agent.RunAsync("I need to make a dentist appointment for
Console.WriteLine(await agent.RunAsync("I've taken Sally to soccer practice.", session) + "\n");
// We can serialize the session, and it will contain both the chat history and the data that each AI context provider serialized.
JsonElement serializedSession = session.Serialize();
JsonElement serializedSession = agent.SerializeSession(session);
// Let's print it to console to show the contents.
Console.WriteLine(JsonSerializer.Serialize(serializedSession, options: new JsonSerializerOptions() { WriteIndented = true, IndentSize = 2 }) + "\n");
// The serialized session can be stored long term in a persistent store, but in this case we will just deserialize again and continue the conversation.
@@ -25,7 +25,7 @@ AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// Serialize the session state to a JsonElement, so it can be stored for later use.
JsonElement serializedSession = session.Serialize();
JsonElement serializedSession = agent.SerializeSession(session);
// Save the serialized session to a temporary file (for demonstration purposes).
string tempFilePath = Path.GetTempFileName();