Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="9.3.1-preview.1.25305.6" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.3.1" />
<PackageVersion Include="Aspire.Hosting.Azure.CognitiveServices" Version="9.3.1" />
<PackageVersion Include="Aspire.Hosting.Azure.CosmosDB" Version="9.3.1" />
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="9.3.1" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="9.3.1" />
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.1" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.2.0-beta.5" />
<PackageVersion Include="Azure.Identity" Version="1.14.2" />
Expand All @@ -21,6 +24,9 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.52.0" />
<!-- Newtonsoft (Required by CosmosClient) -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<!-- System.* -->
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<PackageVersion Include="System.Text.Json" Version="9.0.7" />
Expand Down
12 changes: 12 additions & 0 deletions dotnet/agent-framework-dotnet.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@
<Project Path="src/Microsoft.Extensions.AI.Agents.CopilotStudio/Microsoft.Extensions.AI.Agents.CopilotStudio.csproj" />
<Project Path="src/Microsoft.Extensions.AI.Agents.OpenAI/Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<Project Path="src/Microsoft.Extensions.AI.Agents.Runtime.Abstractions/Microsoft.Extensions.AI.Agents.Runtime.Abstractions.csproj" />
<Project Path="src/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.csproj">
<BuildType Solution="Publish|*" Project="Release" />
</Project>
<Project Path="src/Microsoft.Extensions.AI.Agents.Runtime/Microsoft.Extensions.AI.Agents.Runtime.csproj" Id="35d72ad5-61e1-45cc-a9ad-fa8490dbd146">
<BuildType Solution="Publish|*" Project="Release" />
</Project>
Expand All @@ -163,5 +166,14 @@
<Project Path="tests/Microsoft.Extensions.AI.Agents.UnitTests/Microsoft.Extensions.AI.Agents.UnitTests.csproj">
<BuildType Solution="Publish|*" Project="Debug" />
</Project>
<Project Path="tests/CosmosDB.IntegrationTests/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.Tests.AppHost/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.Tests.AppHost.csproj">
<BuildType Solution="Publish|*" Project="Release" />
</Project>
<Project Path="tests/CosmosDB.IntegrationTests/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.Tests/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.Tests.csproj">
<BuildType Solution="Publish|*" Project="Release" />
</Project>
<Folder Name="/CosmosDB/">

</Folder>
</Folder>
</Solution>
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.Runtime.Abstractions\Microsoft.Extensions.AI.Agents.Runtime.Abstractions.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.Runtime\Microsoft.Extensions.AI.Agents.Runtime.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB\Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB.csproj" />
<ProjectReference Include="..\HelloHttpApi.ServiceDefaults\HelloHttpApi.ServiceDefaults.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Aspire.Azure.AI.OpenAI" />
<PackageReference Include="Aspire.Hosting.Azure.CognitiveServices" />
<PackageReference Include="Aspire.Microsoft.Azure.Cosmos" />
<PackageReference Include="CommunityToolkit.Aspire.OllamaSharp" />
<PackageReference Include="Microsoft.Extensions.AI" />
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.AI.Agents.Runtime;
using Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB;

namespace HelloHttpApi.ApiService;

Expand All @@ -26,8 +27,12 @@ public static IHostApplicationBuilder AddAIAgent(this IHostApplicationBuilder bu
.Add(triage, customerService, "Hand off to the customer service agent for handling rude customer inquiries.")
.Build("PirateWorkflow");
});

var actorBuilder = builder.AddActorRuntime();

// Add CosmosDB state storage to override default storage
builder.Services.AddCosmosActorStateStorage("actor-state-db", "ActorState");

actorBuilder.AddActorType(
new ActorType(agentKey),
(sp, ctx) => new ChatClientAgentActor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
// Add service defaults & Aspire client integrations.
builder.AddServiceDefaults();

// Add CosmosDB client integration
builder.AddAzureCosmosClient("hello-http-api-cosmosdb");

// Add services to the container.
builder.Services.AddProblemDetails();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
<PackageReference Include="Aspire.Hosting.Azure.CognitiveServices" />
<PackageReference Include="Aspire.Hosting.Azure.CosmosDB" />
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 8 additions & 1 deletion dotnet/samples/HelloHttpApi/HelloHttpApi.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
var azOpenAiResourceGroup = builder.AddParameterFromConfiguration("AzureOpenAIResourceGroup", "AzureOpenAI:ResourceGroup");
var chatModel = builder.AddAIModel("chat-model").AsAzureOpenAI("gpt-4o", o => o.AsExisting(azOpenAiResource, azOpenAiResourceGroup));

var cosmosDbResource = builder.AddParameterFromConfiguration("CosmosDbName", "CosmosDb:Name");
var cosmosDbResourceGroup = builder.AddParameterFromConfiguration("CosmosDbResourceGroup", "CosmosDb:ResourceGroup");
var cosmos = builder.AddAzureCosmosDB("hello-http-api-cosmosdb").RunAsExisting(cosmosDbResource, cosmosDbResourceGroup);

var stateDb = cosmos.AddCosmosDatabase("actor-state-db");

var apiService = builder.AddProject<Projects.HelloHttpApi_ApiService>("apiservice")
.WithReference(chatModel);
.WithReference(chatModel)
.WithReference(cosmos).WaitFor(cosmos);

builder.AddProject<Projects.HelloHttpApi_Web>("webfrontend")
.WithExternalHttpEndpoints()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Text.Json;

namespace Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB;

/// <summary>
/// Root document for each actor that provides actor-level ETag semantics.
/// Every write operation updates this document to ensure a single ETag represents
/// the entire actor's state for optimistic concurrency control.
/// This document contains no actor state data. It only serves to track last modified
/// time and provide a single ETag for the actor's state.
///
/// Example structure:
/// {
/// "id": "rootdoc", // Root document ID (constant per actor partition)
/// "actorId": "actor-123", // Partition key (actor ID)
/// "lastModified": "2024-...", // Timestamp
/// }
/// </summary>
public sealed class ActorRootDocument
{
/// <summary>
/// The document ID.
/// </summary>
public string Id { get; set; } = default!;

/// <summary>
/// The actor ID.
/// </summary>
public string ActorId { get; set; } = default!;

/// <summary>
/// The last modified timestamp.
/// </summary>
public DateTimeOffset LastModified { get; set; }
}

/// <summary>
/// Actor state document that represents a single key-value pair in the actor's state.
/// Document Structure (one per actor key):
/// {
/// "id": "state_sanitizedkey", // Unique document ID for the state entry
/// "actorId": "actor-123", // Partition key (actor ID)
/// "key": "foo", // Logical key for the state entry
/// "value": { "bar": 42, "baz": "hello" } // Arbitrary JsonElement payload
/// }
/// </summary>
public sealed class ActorStateDocument
{
/// <summary>
/// The document ID.
/// </summary>
public string Id { get; set; } = default!;

/// <summary>
/// The actor ID.
/// </summary>
public string ActorId { get; set; } = default!;

/// <summary>
/// The logical key for the state entry.
/// </summary>
public string Key { get; set; } = default!;

/// <summary>
/// The value payload.
/// </summary>
public JsonElement Value { get; set; } = default!;
}

/// <summary>
/// Projection class for Cosmos DB queries to retrieve keys.
/// </summary>
public sealed class KeyProjection
{
/// <summary>
/// The key value.
/// </summary>
public string Key { get; set; } = default!;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Text.Json;
using System.Text.Json.Serialization;

namespace Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB;

/// <summary>
/// Source-generated JSON type information for Cosmos DB actor state documents.
/// </summary>
[JsonSourceGenerationOptions(
JsonSerializerDefaults.Web,
UseStringEnumConverter = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false)]
[JsonSerializable(typeof(ActorStateDocument))]
[JsonSerializable(typeof(ActorRootDocument))]
[JsonSerializable(typeof(KeyProjection))]
internal sealed partial class CosmosActorStateJsonContext : JsonSerializerContext;
Loading
Loading