diff --git a/dotnet/src/Microsoft.Agents.AI/AgentJsonUtilities.cs b/dotnet/src/Microsoft.Agents.AI/AgentJsonUtilities.cs
index c400a1cb6c..c9de4cbc38 100644
--- a/dotnet/src/Microsoft.Agents.AI/AgentJsonUtilities.cs
+++ b/dotnet/src/Microsoft.Agents.AI/AgentJsonUtilities.cs
@@ -69,6 +69,7 @@ private static JsonSerializerOptions CreateDefaultOptions()
[JsonSerializable(typeof(ChatClientAgentThread.ThreadState))]
[JsonSerializable(typeof(TextSearchProvider.TextSearchProviderState))]
[JsonSerializable(typeof(ChatHistoryMemoryProvider.ChatHistoryMemoryProviderState))]
+ [JsonSerializable(typeof(Functions.ContextualFunctionProvider.ContextualFunctionProviderState))]
[ExcludeFromCodeCoverage]
internal sealed partial class JsonContext : JsonSerializerContext;
diff --git a/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs
new file mode 100644
index 0000000000..6caf8b1449
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs
@@ -0,0 +1,230 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.VectorData;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI.Functions;
+
+///
+/// Represents a contextual function provider that performs RAG (Retrieval-Augmented Generation) on the provided functions to identify
+/// the most relevant functions for the current context. The provider vectorizes the provided function names and descriptions
+/// and stores them in the specified vector store, allowing for a vector search to find the most relevant
+/// functions for a given context and provide the functions to the AI model/agent.
+///
+///
+///
+///
+/// The provider is designed to work with in-memory vector stores. Using other vector stores
+/// will require the data synchronization and data lifetime management to be done by the caller.
+///
+///
+/// The in-memory vector store is supposed to be created per provider and not shared between providers
+/// unless each provider uses a different collection name. Not following this may lead to a situation
+/// where one provider identifies a function belonging to another provider as relevant and, as a result,
+/// an attempt to access it by the first provider will fail because the function is not registered with it.
+///
+///
+/// The provider uses function name as a key for the records and as such the specified vector store
+/// should support record keys of string type.
+///
+///
+///
+public sealed class ContextualFunctionProvider : AIContextProvider
+{
+ private readonly FunctionStore _functionStore;
+ private readonly ConcurrentQueue _recentMessages = [];
+ private readonly ContextualFunctionProviderOptions _options;
+ private bool _areFunctionsVectorized;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An instance of a vector store.
+ /// The number of dimensions to use for the memory embeddings.
+ /// The functions to vectorize and store for searching related functions.
+ /// The maximum number of relevant functions to retrieve from the vector store.
+ /// Further optional settings for configuring the provider.
+ /// The logger factory to use for logging. If not provided, no logging will be performed.
+ public ContextualFunctionProvider(
+ VectorStore vectorStore,
+ int vectorDimensions,
+ IEnumerable functions,
+ int maxNumberOfFunctions,
+ ContextualFunctionProviderOptions? options = null,
+ ILoggerFactory? loggerFactory = null)
+ : this(vectorStore, vectorDimensions, functions, maxNumberOfFunctions, default, options, null, loggerFactory)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An instance of a vector store.
+ /// The number of dimensions to use for the memory embeddings.
+ /// The functions to vectorize and store for searching related functions.
+ /// The maximum number of relevant functions to retrieve from the vector store.
+ /// A representing the serialized provider state.
+ /// Further optional settings for configuring the provider.
+ /// Optional serializer options. If not provided, will be used.
+ /// The logger factory to use for logging. If not provided, no logging will be performed.
+ public ContextualFunctionProvider(
+ VectorStore vectorStore,
+ int vectorDimensions,
+ IEnumerable functions,
+ int maxNumberOfFunctions,
+ JsonElement serializedState,
+ ContextualFunctionProviderOptions? options = null,
+ JsonSerializerOptions? jsonSerializerOptions = null,
+ ILoggerFactory? loggerFactory = null)
+ {
+ Throw.IfNull(vectorStore);
+ Throw.IfLessThan(vectorDimensions, 1, "Vector dimensions must be greater than 0");
+ Throw.IfNull(functions);
+ Throw.IfLessThan(maxNumberOfFunctions, 1, "Max number of functions must be greater than 0");
+
+ this._options = options ?? new ContextualFunctionProviderOptions();
+ Throw.IfLessThan(this._options.NumberOfRecentMessagesInContext, 1, "Number of recent messages to include into context must be greater than 0");
+
+ this._functionStore = new FunctionStore(
+ vectorStore,
+ string.IsNullOrWhiteSpace(this._options.CollectionName) ? "functions" : this._options.CollectionName,
+ vectorDimensions,
+ functions,
+ maxNumberOfFunctions,
+ loggerFactory,
+ options: new()
+ {
+ EmbeddingValueProvider = this._options.EmbeddingValueProvider,
+ }
+ );
+
+ // Restore recent messages from serialized state if provided
+ if (serializedState.ValueKind is not JsonValueKind.Null and not JsonValueKind.Undefined)
+ {
+ JsonSerializerOptions jso = jsonSerializerOptions ?? AgentJsonUtilities.DefaultOptions;
+ ContextualFunctionProviderState? state = serializedState.Deserialize(jso.GetTypeInfo(typeof(ContextualFunctionProviderState))) as ContextualFunctionProviderState;
+ if (state?.RecentMessages is { Count: > 0 })
+ {
+ // Restore recent messages respecting the limit (may truncate if limit changed afterwards).
+ foreach (ChatMessage message in state.RecentMessages.Take(this._options.NumberOfRecentMessagesInContext))
+ {
+ this._recentMessages.Enqueue(message);
+ }
+ }
+ }
+ }
+
+ ///
+ public override async ValueTask InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(context);
+
+ // Vectorize the functions if they are not already vectorized
+ if (!this._areFunctionsVectorized)
+ {
+ await this._functionStore.SaveAsync(cancellationToken).ConfigureAwait(false);
+
+ this._areFunctionsVectorized = true;
+ }
+
+ // Build the search context
+ var searchContext = await this.BuildContextAsync(context.RequestMessages, cancellationToken).ConfigureAwait(false);
+
+ // Get the function relevant to the context
+ var functions = await this._functionStore
+ .SearchAsync(searchContext, cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
+
+ return new AIContext { Tools = [.. functions] };
+ }
+
+ ///
+ public override ValueTask InvokedAsync(InvokedContext context, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(context);
+
+ // Don't add messages to the recent messages queue if the invocation failed
+ if (context.InvokeException is not null)
+ {
+ return default;
+ }
+
+ // Add the request and response messages to the recent messages queue
+ foreach (var message in context.RequestMessages)
+ {
+ this._recentMessages.Enqueue(message);
+ }
+
+ if (context.ResponseMessages is not null)
+ {
+ foreach (var message in context.ResponseMessages)
+ {
+ this._recentMessages.Enqueue(message);
+ }
+ }
+
+ // If there are more messages than the configured limit, remove the oldest ones
+ while (this._recentMessages.Count > this._options.NumberOfRecentMessagesInContext)
+ {
+ this._recentMessages.TryDequeue(out _);
+ }
+
+ return default;
+ }
+
+ ///
+ /// Serializes the current provider state to a containing the recent messages.
+ ///
+ /// Optional serializer options. This parameter is not used; is always used for serialization.
+ /// A with the recent messages, or default if there are no recent messages.
+ public override JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null)
+ {
+ ContextualFunctionProviderState state = new();
+ if (this._options.NumberOfRecentMessagesInContext > 0 && !this._recentMessages.IsEmpty)
+ {
+ state.RecentMessages = this._recentMessages.Take(this._options.NumberOfRecentMessagesInContext).ToList();
+ }
+
+ return JsonSerializer.SerializeToElement(state, AgentJsonUtilities.DefaultOptions.GetTypeInfo(typeof(ContextualFunctionProviderState)));
+ }
+
+ ///
+ /// Builds the context from chat messages.
+ ///
+ /// The new messages.
+ /// The cancellation token to use for cancellation.
+ private async Task BuildContextAsync(IEnumerable newMessages, CancellationToken cancellationToken)
+ {
+ if (this._options.ContextEmbeddingValueProvider is not null)
+ {
+ // Ensure we only take the recent messages up to the configured limit
+ var recentMessages = this._recentMessages
+ .Skip(Math.Max(0, this._recentMessages.Count - this._options.NumberOfRecentMessagesInContext));
+
+ return await this._options.ContextEmbeddingValueProvider.Invoke(recentMessages, newMessages, cancellationToken).ConfigureAwait(false);
+ }
+
+ // Build context by concatenating the recent messages and the new messages
+ return string.Join(
+ Environment.NewLine,
+ this._recentMessages
+ .Skip(Math.Max(0, this._recentMessages.Count - this._options.NumberOfRecentMessagesInContext))
+ .Concat(newMessages)
+ .Where(m => !string.IsNullOrWhiteSpace(m?.Text))
+ .Select(m => m.Text));
+ }
+
+ internal sealed class ContextualFunctionProviderState
+ {
+ public List? RecentMessages { get; set; }
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProviderOptions.cs b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProviderOptions.cs
new file mode 100644
index 0000000000..f56a18b183
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProviderOptions.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.AI;
+
+namespace Microsoft.Agents.AI.Functions;
+
+///
+/// Options for the .
+///
+public sealed class ContextualFunctionProviderOptions
+{
+ ///
+ /// Gets or sets the collection name to use for storing and retrieving functions.
+ ///
+ /// If not set, the default value "functions" will be used.
+ public string? CollectionName { get; set; }
+
+ ///
+ /// Gets or sets the number of recent messages (messages from previous model/agent invocations) the provider uses to form a context.
+ /// The provider collects all messages from all model/agent invocations, up to this number,
+ /// and prepends them to the new messages of the current model/agent invocation to build a context.
+ /// While collecting new messages, the provider will remove the oldest messages
+ /// to keep the number of recent messages within the specified limit.
+ ///
+ ///
+ /// Using the recent messages together with the new messages can be very useful
+ /// in cases where the model/agent is prompted to perform a task that requires details from
+ /// previous invocation(s). For example, if the agent is asked to provision an Azure resource in the first
+ /// invocation and deploy the resource in the second invocation, the second invocation will need
+ /// information about the provisioned resource in the first invocation to deploy it.
+ ///
+ public int NumberOfRecentMessagesInContext { get; set; } = 2;
+
+ ///
+ /// Gets or sets a callback function that returns a value used to create a context embedding. The value is vectorized,
+ /// and the resulting vector is used to perform vector searches for functions relevant to the context.
+ /// If not provided, the default behavior is to concatenate the non-empty messages into a single string,
+ /// separated by a new line.
+ ///
+ ///
+ /// The callback receives three parameters:
+ /// `recentMessages` - messages from the previous model/agent invocations.
+ /// `newMessages` - the new messages of the current model/agent invocation.
+ /// `cancellationToken` - a cancellation token that can be used to cancel the operation.
+ ///
+ public Func, IEnumerable, CancellationToken, Task>? ContextEmbeddingValueProvider { get; set; }
+
+ ///
+ /// Gets or sets a callback function that returns a value used to create a function embedding. The value is vectorized,
+ /// and the resulting vector is stored in the vector store for use in vector searches for functions relevant
+ /// to the context.
+ /// If not provided, the default behavior is to concatenate the function name and description into a single string.
+ ///
+ ///
+ /// The callback receives two parameters:
+ /// `function` - the function to get embedding value for.
+ /// `cancellationToken` - a cancellation token that can be used to cancel the operation.
+ ///
+ public Func>? EmbeddingValueProvider { get; set; }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI/Functions/FunctionStore.cs b/dotnet/src/Microsoft.Agents.AI/Functions/FunctionStore.cs
new file mode 100644
index 0000000000..45e69bb327
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI/Functions/FunctionStore.cs
@@ -0,0 +1,185 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.VectorData;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI.Functions;
+
+///
+/// Represents a vector store for objects where the function name and description can be used for similarity searches.
+///
+internal sealed class FunctionStore
+{
+ private readonly VectorStore _vectorStore;
+ private readonly Dictionary _functionByName;
+ private readonly string _collectionName;
+ private readonly int _maxNumberOfFunctions;
+ private readonly ILogger _logger;
+ private readonly FunctionStoreOptions _options;
+ private readonly VectorStoreCollection