Skip to content

Commit fc7937f

Browse files
Use source generated JSON context for future nativeAOT support.
1 parent db2499a commit fc7937f

File tree

4 files changed

+86
-63
lines changed

4 files changed

+86
-63
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System;
4+
using System.Text.Json;
5+
6+
namespace Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB;
7+
8+
/// <summary>
9+
/// Root document for each actor that provides actor-level ETag semantics.
10+
/// </summary>
11+
public sealed class ActorRootDocument
12+
{
13+
/// <summary>
14+
/// The document ID.
15+
/// </summary>
16+
public string Id { get; set; } = default!;
17+
18+
/// <summary>
19+
/// The actor ID.
20+
/// </summary>
21+
public string ActorId { get; set; } = default!;
22+
23+
/// <summary>
24+
/// The last modified timestamp.
25+
/// </summary>
26+
public DateTimeOffset LastModified { get; set; }
27+
}
28+
29+
/// <summary>
30+
/// Actor state document that represents a single key-value pair in the actor's state.
31+
/// </summary>
32+
public sealed class ActorStateDocument
33+
{
34+
/// <summary>
35+
/// The document ID.
36+
/// </summary>
37+
public string Id { get; set; } = default!;
38+
39+
/// <summary>
40+
/// The actor ID.
41+
/// </summary>
42+
public string ActorId { get; set; } = default!;
43+
44+
/// <summary>
45+
/// The logical key for the state entry.
46+
/// </summary>
47+
public string Key { get; set; } = default!;
48+
49+
/// <summary>
50+
/// The value payload.
51+
/// </summary>
52+
public JsonElement Value { get; set; } = default!;
53+
}
54+
55+
/// <summary>
56+
/// Projection class for Cosmos DB queries to retrieve keys.
57+
/// </summary>
58+
public sealed class KeyProjection
59+
{
60+
/// <summary>
61+
/// The key value.
62+
/// </summary>
63+
public string Key { get; set; } = default!;
64+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
5+
6+
namespace Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB;
7+
8+
/// <summary>
9+
/// Source-generated JSON type information for Cosmos DB actor state documents.
10+
/// </summary>
11+
[JsonSourceGenerationOptions(
12+
JsonSerializerDefaults.Web,
13+
UseStringEnumConverter = true,
14+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
15+
WriteIndented = false)]
16+
[JsonSerializable(typeof(ActorStateDocument))]
17+
[JsonSerializable(typeof(ActorRootDocument))]
18+
[JsonSerializable(typeof(KeyProjection))]
19+
internal sealed partial class CosmosActorStateJsonContext : JsonSerializerContext;

dotnet/src/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB/CosmosActorStateStorage.cs

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
using System;
44
using System.Collections.Generic;
5-
using System.Diagnostics.CodeAnalysis;
6-
using System.Text.Json;
7-
using System.Text.Json.Serialization;
85
using System.Threading;
96
using System.Threading.Tasks;
107
using Microsoft.Azure.Cosmos;
@@ -178,7 +175,7 @@ public async ValueTask<ReadResponse> ReadStateAsync(
178175
var requestOptions = new QueryRequestOptions
179176
{
180177
PartitionKey = GetPartitionKey(actorId),
181-
MaxItemCount = 100 // TODO Fix
178+
MaxItemCount = -1 // Use dynamic page size
182179
};
183180

184181
var iterator = container.GetItemQueryIterator<KeyProjection>(
@@ -211,64 +208,6 @@ public async ValueTask<ReadResponse> ReadStateAsync(
211208
return new ReadResponse(actorETag, results);
212209
}
213210

214-
[SuppressMessage("Performance", "CA1812", Justification = "This is a projection class for Cosmos DB queries.")]
215-
private sealed class KeyProjection
216-
{
217-
[JsonPropertyName("key")]
218-
public string Key { get; set; } = default!;
219-
}
220-
221-
/// <summary>
222-
/// Root document for each actor that provides actor-level ETag semantics.
223-
/// Every write operation updates this document to ensure a single ETag represents
224-
/// the entire actor's state for optimistic concurrency control.
225-
/// This document contains no actor state data. It only serves to track last modified
226-
/// time and provide a single ETag for the actor's state.
227-
///
228-
/// Example structure:
229-
/// {
230-
/// "id": "rootdoc", // Root document ID (constant per actor partition)
231-
/// "actorId": "actor-123", // Partition key (actor ID)
232-
/// "lastModified": "2024-...", // Timestamp
233-
/// }
234-
/// </summary>
235-
private sealed class ActorRootDocument
236-
{
237-
[JsonPropertyName("id")]
238-
public string Id { get; set; } = default!;
239-
240-
[JsonPropertyName("actorId")]
241-
public string ActorId { get; set; } = default!;
242-
243-
[JsonPropertyName("lastModified")]
244-
public DateTimeOffset LastModified { get; set; }
245-
}
246-
247-
/// <summary>
248-
/// Actor state document that represents a single key-value pair in the actor's state.
249-
/// Document Structure (one per actor key):
250-
/// {
251-
/// "id": "state_sanitizedkey", // Unique document ID for the state entry
252-
/// "actorId": "actor-123", // Partition key (actor ID)
253-
/// "key": "foo", // Logical key for the state entry
254-
/// "value": { "bar": 42, "baz": "hello" } // Arbitrary JsonElement payload
255-
/// }
256-
/// </summary>
257-
private sealed class ActorStateDocument
258-
{
259-
[JsonPropertyName("id")]
260-
public string Id { get; set; } = default!;
261-
262-
[JsonPropertyName("actorId")]
263-
public string ActorId { get; set; } = default!;
264-
265-
[JsonPropertyName("key")]
266-
public string Key { get; set; } = default!;
267-
268-
[JsonPropertyName("value")]
269-
public JsonElement Value { get; set; } = default!;
270-
}
271-
272211
private static string GetDocumentId(string key) => $"state_{CosmosIdSanitizer.Sanitize(key)}";
273212
private const string RootDocumentId = "rootdoc";
274213

dotnet/src/Microsoft.Extensions.AI.Agents.Runtime.Storage.CosmosDB/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ public static IServiceCollection AddCosmosActorStateStorage(
3535
ApplicationName = "AgentFramework",
3636
ConnectionMode = ConnectionMode.Direct,
3737
ConsistencyLevel = ConsistencyLevel.Session,
38-
UseSystemTextJsonSerializerWithOptions = new JsonSerializerOptions()
38+
UseSystemTextJsonSerializerWithOptions = new JsonSerializerOptions
3939
{
4040
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
41+
TypeInfoResolver = CosmosActorStateJsonContext.Default
4142
}
4243
};
4344

0 commit comments

Comments
 (0)