Skip to content

Commit 6b09a4b

Browse files
committed
Update with main
2 parents f2860f2 + 21e00c0 commit 6b09a4b

File tree

65 files changed

+3218
-1223
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3218
-1223
lines changed

.github/copilot-instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Here are some general guidelines that apply to all code.
1414

1515
- The top of all *.cs files should have a copyright notice: `// Copyright (c) Microsoft. All rights reserved.`
1616
- All public methods and classes should have XML documentation comments.
17+
- After adding, modifying or deleting code, run `dotnet build`, and then fix any reported build errors.
18+
- After adding or modifying code, run `dotnet format` to automatically fix any formatting errors.
1719

1820
### C# Sample Code Guidelines
1921

dotnet/samples/GettingStarted/AgentProviders/Agent_With_CustomImplementation/Program.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,18 @@ protected override async Task<AgentResponse> RunCoreAsync(IEnumerable<ChatMessag
4545
}
4646

4747
// Get existing messages from the store
48-
var invokingContext = new ChatMessageStore.InvokingContext(messages);
49-
var storeMessages = await typedThread.MessageStore.InvokingAsync(invokingContext, cancellationToken);
48+
var invokingContext = new ChatHistoryProvider.InvokingContext(messages);
49+
var storeMessages = await typedThread.ChatHistoryProvider.InvokingAsync(invokingContext, cancellationToken);
5050

5151
// Clone the input messages and turn them into response messages with upper case text.
5252
List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.Name).ToList();
5353

5454
// Notify the thread of the input and output messages.
55-
var invokedContext = new ChatMessageStore.InvokedContext(messages, storeMessages)
55+
var invokedContext = new ChatHistoryProvider.InvokedContext(messages, storeMessages)
5656
{
5757
ResponseMessages = responseMessages
5858
};
59-
await typedThread.MessageStore.InvokedAsync(invokedContext, cancellationToken);
59+
await typedThread.ChatHistoryProvider.InvokedAsync(invokedContext, cancellationToken);
6060

6161
return new AgentResponse
6262
{
@@ -77,18 +77,18 @@ protected override async IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingA
7777
}
7878

7979
// Get existing messages from the store
80-
var invokingContext = new ChatMessageStore.InvokingContext(messages);
81-
var storeMessages = await typedThread.MessageStore.InvokingAsync(invokingContext, cancellationToken);
80+
var invokingContext = new ChatHistoryProvider.InvokingContext(messages);
81+
var storeMessages = await typedThread.ChatHistoryProvider.InvokingAsync(invokingContext, cancellationToken);
8282

8383
// Clone the input messages and turn them into response messages with upper case text.
8484
List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.Name).ToList();
8585

8686
// Notify the thread of the input and output messages.
87-
var invokedContext = new ChatMessageStore.InvokedContext(messages, storeMessages)
87+
var invokedContext = new ChatHistoryProvider.InvokedContext(messages, storeMessages)
8888
{
8989
ResponseMessages = responseMessages
9090
};
91-
await typedThread.MessageStore.InvokedAsync(invokedContext, cancellationToken);
91+
await typedThread.ChatHistoryProvider.InvokedAsync(invokedContext, cancellationToken);
9292

9393
foreach (var message in responseMessages)
9494
{

dotnet/samples/GettingStarted/AgentWithRAG/AgentWithRAG_Step01_BasicTextRAG/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
// Since we are using ChatCompletion which stores chat history locally, we can also add a message removal policy
6767
// that removes messages produced by the TextSearchProvider before they are added to the chat history, so that
6868
// we don't bloat chat history with all the search result messages.
69-
ChatMessageStoreFactory = (ctx, ct) => new ValueTask<ChatMessageStore>(new InMemoryChatMessageStore(ctx.SerializedState, ctx.JsonSerializerOptions)
69+
ChatHistoryProviderFactory = (ctx, ct) => new ValueTask<ChatHistoryProvider>(new InMemoryChatHistoryProvider(ctx.SerializedState, ctx.JsonSerializerOptions)
7070
.WithAIContextProviderMessageRemoval()),
7171
});
7272

dotnet/samples/GettingStarted/Agents/Agent_Step07_3rdPartyThreadStorage/Program.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@
3131
{
3232
ChatOptions = new() { Instructions = "You are good at telling jokes." },
3333
Name = "Joker",
34-
ChatMessageStoreFactory = (ctx, ct) => new ValueTask<ChatMessageStore>(
35-
// Create a new chat message store for this agent that stores the messages in a vector store.
36-
// Each thread must get its own copy of the VectorChatMessageStore, since the store
37-
// also contains the id that the thread is stored under.
38-
new VectorChatMessageStore(vectorStore, ctx.SerializedState, ctx.JsonSerializerOptions))
34+
ChatHistoryProviderFactory = (ctx, ct) => new ValueTask<ChatHistoryProvider>(
35+
// Create a new ChatHistoryProvider for this agent that stores chat history in a vector store.
36+
// Each thread must get its own copy of the VectorChatHistoryProvider, since the provider
37+
// also contains the id that the chat history is stored under.
38+
new VectorChatHistoryProvider(vectorStore, ctx.SerializedState, ctx.JsonSerializerOptions))
3939
});
4040

4141
// Start a new thread for the agent conversation.
4242
AgentThread thread = await agent.GetNewThreadAsync();
4343

44-
// Run the agent with the thread that stores conversation history in the vector store.
44+
// Run the agent with the thread that stores chat history in the vector store.
4545
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
4646

4747
// Serialize the thread state, so it can be stored for later use.
@@ -58,30 +58,30 @@
5858
// Deserialize the thread state after loading from storage.
5959
AgentThread resumedThread = await agent.DeserializeThreadAsync(serializedThread);
6060

61-
// Run the agent with the thread that stores conversation history in the vector store a second time.
61+
// Run the agent with the thread that stores chat history in the vector store a second time.
6262
Console.WriteLine(await agent.RunAsync("Now tell the same joke in the voice of a pirate, and add some emojis to the joke.", resumedThread));
6363

64-
// We can access the VectorChatMessageStore via the thread's GetService method if we need to read the key under which threads are stored.
65-
var messageStore = resumedThread.GetService<VectorChatMessageStore>()!;
66-
Console.WriteLine($"\nThread is stored in vector store under key: {messageStore.ThreadDbKey}");
64+
// We can access the VectorChatHistoryProvider via the thread's GetService method if we need to read the key under which chat history is stored.
65+
var chatHistoryProvider = resumedThread.GetService<VectorChatHistoryProvider>()!;
66+
Console.WriteLine($"\nThread is stored in vector store under key: {chatHistoryProvider.ThreadDbKey}");
6767

6868
namespace SampleApp
6969
{
7070
/// <summary>
71-
/// A sample implementation of <see cref="ChatMessageStore"/> that stores chat messages in a vector store.
71+
/// A sample implementation of <see cref="ChatHistoryProvider"/> that stores chat history in a vector store.
7272
/// </summary>
73-
internal sealed class VectorChatMessageStore : ChatMessageStore
73+
internal sealed class VectorChatHistoryProvider : ChatHistoryProvider
7474
{
7575
private readonly VectorStore _vectorStore;
7676

77-
public VectorChatMessageStore(VectorStore vectorStore, JsonElement serializedStoreState, JsonSerializerOptions? jsonSerializerOptions = null)
77+
public VectorChatHistoryProvider(VectorStore vectorStore, JsonElement serializedState, JsonSerializerOptions? jsonSerializerOptions = null)
7878
{
7979
this._vectorStore = vectorStore ?? throw new ArgumentNullException(nameof(vectorStore));
8080

81-
if (serializedStoreState.ValueKind is JsonValueKind.String)
81+
if (serializedState.ValueKind is JsonValueKind.String)
8282
{
8383
// Here we can deserialize the thread id so that we can access the same messages as before the suspension.
84-
this.ThreadDbKey = serializedStoreState.Deserialize<string>();
84+
this.ThreadDbKey = serializedState.Deserialize<string>();
8585
}
8686
}
8787

dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
{
2525
ChatOptions = new() { Instructions = "You are good at telling jokes." },
2626
Name = "Joker",
27-
ChatMessageStoreFactory = (ctx, ct) => new ValueTask<ChatMessageStore>(new InMemoryChatMessageStore(new MessageCountingChatReducer(2), ctx.SerializedState, ctx.JsonSerializerOptions))
27+
ChatHistoryProviderFactory = (ctx, ct) => new ValueTask<ChatHistoryProvider>(new InMemoryChatHistoryProvider(new MessageCountingChatReducer(2), ctx.SerializedState, ctx.JsonSerializerOptions))
2828
});
2929

3030
AgentThread thread = await agent.GetNewThreadAsync();

dotnet/samples/GettingStarted/Agents/Agent_Step20_AdditionalAIContext/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ You are a helpful personal assistant.
4545
You manage a TODO list for the user. When the user has completed one of the tasks it can be removed from the TODO list. Only provide the list of TODO items if asked.
4646
You remind users of upcoming calendar events when the user interacts with you.
4747
""" },
48-
ChatMessageStoreFactory = (ctx, ct) => new ValueTask<ChatMessageStore>(new InMemoryChatMessageStore()
48+
ChatHistoryProviderFactory = (ctx, ct) => new ValueTask<ChatHistoryProvider>(new InMemoryChatHistoryProvider()
4949
// Use WithAIContextProviderMessageRemoval, so that we don't store the messages from the AI context provider in the chat history.
5050
// You may want to store these messages, depending on their content and your requirements.
5151
.WithAIContextProviderMessageRemoval()),
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
using Microsoft.Extensions.AI;
5+
using Microsoft.Shared.Diagnostics;
6+
7+
namespace Microsoft.Agents.AI;
8+
9+
/// <summary>
10+
/// Contains extension methods to allow storing and retrieving properties using the type name of the property as the key.
11+
/// </summary>
12+
public static class AdditionalPropertiesExtensions
13+
{
14+
/// <summary>
15+
/// Adds an additional property using the type name of the property as the key.
16+
/// </summary>
17+
/// <typeparam name="T">The type of the property to add.</typeparam>
18+
/// <param name="additionalProperties">The dictionary of additional properties.</param>
19+
/// <param name="value">The value to add.</param>
20+
public static void Add<T>(this AdditionalPropertiesDictionary additionalProperties, T value)
21+
{
22+
_ = Throw.IfNull(additionalProperties);
23+
24+
additionalProperties.Add(typeof(T).FullName!, value);
25+
}
26+
27+
/// <summary>
28+
/// Attempts to add a property using the type name of the property as the key.
29+
/// </summary>
30+
/// <remarks>
31+
/// This method uses the full name of the type parameter as the key. If the key already exists,
32+
/// the value is not updated and the method returns <see langword="false"/>.
33+
/// </remarks>
34+
/// <typeparam name="T">The type of the property to add.</typeparam>
35+
/// <param name="additionalProperties">The dictionary of additional properties.</param>
36+
/// <param name="value">The value to add.</param>
37+
/// <returns>
38+
/// <see langword="true"/> if the value was added successfully; <see langword="false"/> if the key already exists.
39+
/// </returns>
40+
public static bool TryAdd<T>(this AdditionalPropertiesDictionary additionalProperties, T value)
41+
{
42+
_ = Throw.IfNull(additionalProperties);
43+
44+
return additionalProperties.TryAdd(typeof(T).FullName!, value);
45+
}
46+
47+
/// <summary>
48+
/// Attempts to retrieve a value from the additional properties dictionary using the type name of the property as the key.
49+
/// </summary>
50+
/// <remarks>
51+
/// This method uses the full name of the type parameter as the key when searching the dictionary.
52+
/// </remarks>
53+
/// <typeparam name="T">The type of the property to be retrieved.</typeparam>
54+
/// <param name="additionalProperties">The dictionary containing additional properties.</param>
55+
/// <param name="value">
56+
/// When this method returns, contains the value retrieved from the dictionary, if found and successfully converted to the requested type;
57+
/// otherwise, the default value of <typeparamref name="T"/>.
58+
/// </param>
59+
/// <returns>
60+
/// <see langword="true"/> if a non-<see langword="null"/> value was found
61+
/// in the dictionary and converted to the requested type; otherwise, <see langword="false"/>.
62+
/// </returns>
63+
public static bool TryGetValue<T>(this AdditionalPropertiesDictionary additionalProperties, [NotNullWhen(true)] out T? value)
64+
{
65+
_ = Throw.IfNull(additionalProperties);
66+
67+
return additionalProperties.TryGetValue(typeof(T).FullName!, out value);
68+
}
69+
70+
/// <summary>
71+
/// Determines whether the additional properties dictionary contains a property with the name of the provided type as the key.
72+
/// </summary>
73+
/// <typeparam name="T">The type of the property to check for.</typeparam>
74+
/// <param name="additionalProperties">The dictionary of additional properties.</param>
75+
/// <returns>
76+
/// <see langword="true"/> if the dictionary contains a property with the name of the provided type as the key; otherwise, <see langword="false"/>.
77+
/// </returns>
78+
public static bool Contains<T>(this AdditionalPropertiesDictionary additionalProperties)
79+
{
80+
_ = Throw.IfNull(additionalProperties);
81+
82+
return additionalProperties.ContainsKey(typeof(T).FullName!);
83+
}
84+
85+
/// <summary>
86+
/// Removes a property from the additional properties dictionary using the name of the provided type as the key.
87+
/// </summary>
88+
/// <typeparam name="T">The type of the property to remove.</typeparam>
89+
/// <param name="additionalProperties">The dictionary of additional properties.</param>
90+
/// <returns>
91+
/// <see langword="true"/> if the property was successfully removed; otherwise, <see langword="false"/>.
92+
/// </returns>
93+
public static bool Remove<T>(this AdditionalPropertiesDictionary additionalProperties)
94+
{
95+
_ = Throw.IfNull(additionalProperties);
96+
97+
return additionalProperties.Remove(typeof(T).FullName!);
98+
}
99+
}

dotnet/src/Microsoft.Agents.AI.Abstractions/AgentAbstractionsJsonUtilities.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private static JsonSerializerOptions CreateDefaultOptions()
8282
[JsonSerializable(typeof(AgentResponseUpdate[]))]
8383
[JsonSerializable(typeof(ServiceIdAgentThread.ServiceIdAgentThreadState))]
8484
[JsonSerializable(typeof(InMemoryAgentThread.InMemoryAgentThreadState))]
85-
[JsonSerializable(typeof(InMemoryChatMessageStore.StoreState))]
85+
[JsonSerializable(typeof(InMemoryChatHistoryProvider.State))]
8686

8787
[ExcludeFromCodeCoverage]
8888
private sealed partial class JsonContext : JsonSerializerContext;

dotnet/src/Microsoft.Agents.AI.Abstractions/AgentThread.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public virtual JsonElement Serialize(JsonSerializerOptions? jsonSerializerOption
6868
/// <exception cref="ArgumentNullException"><paramref name="serviceType"/> is <see langword="null"/>.</exception>
6969
/// <remarks>
7070
/// The purpose of this method is to allow for the retrieval of strongly-typed services that might be provided by the <see cref="AgentThread"/>,
71-
/// including itself or any services it might be wrapping. For example, to access a <see cref="ChatMessageStore"/> if available for the instance,
71+
/// including itself or any services it might be wrapping. For example, to access a <see cref="ChatHistoryProvider"/> if available for the instance,
7272
/// <see cref="GetService"/> may be used to request it.
7373
/// </remarks>
7474
public virtual object? GetService(Type serviceType, object? serviceKey = null)

0 commit comments

Comments
 (0)