Skip to content

Commit a9d0bb6

Browse files
authored
Make Azure.AI.Agents.Persistent AOT compatible. (Azure#52434)
* Make Azure.AI.Agents.Persistent AOT compatible. * Fix
1 parent ad6b024 commit a9d0bb6

15 files changed

+897
-113
lines changed

sdk/ai/Azure.AI.Agents.Persistent/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Updated `Microsoft.Extensions.AI.Abstractions` dependency to version 9.8.0.`
77
- Added support of `FileSearchTool` and `CodeInterpreterTool` for `PersistentAgentsChatClient`
88
- Bugfix: Addressed issues related to `ResponseFormat` when using `PersistentAgentsChatClient` with Structured Outputs.
9+
- Make `Azure.AI.Agents.Persistent` AOT compatible.
910

1011
### Breaking Changes
1112

sdk/ai/Azure.AI.Agents.Persistent/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "net",
44
"TagPrefix": "net/ai/Azure.AI.Agents.Persistent",
5-
"Tag": "net/ai/Azure.AI.Agents.Persistent_6bc91f54af"
5+
"Tag": "net/ai/Azure.AI.Agents.Persistent_40abf97769"
66
}

sdk/ai/Azure.AI.Agents.Persistent/src/Azure.AI.Agents.Persistent.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<NoWarn>$(NoWarn);CS1591;AZC0012;SA1649;SA1402;</NoWarn>
1313
<LangVersion>latest</LangVersion>
1414
<IncludeOperationsSharedSource>true</IncludeOperationsSharedSource>
15+
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
1516
</PropertyGroup>
1617

1718
<ItemGroup>

sdk/ai/Azure.AI.Agents.Persistent/src/Custom/FunctionToolDefinition.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,31 @@
66
#nullable disable
77

88
using System;
9+
using System.Collections.Generic;
10+
using System.Text.Json;
11+
using System.Text.Json.Serialization;
912
using Azure.Core;
1013

1114
namespace Azure.AI.Agents.Persistent;
1215

16+
// This type of this object is marked as unknown in typespec. Here we create the
17+
// possible implementation just to serialize it into BinaryObject in AOT
18+
// compatible way.
19+
internal class FunctionParameters
20+
{
21+
public string type;
22+
public Dictionary<string, string> properties;
23+
public FunctionParameters()
24+
{
25+
type = "object";
26+
properties = new Dictionary<string, string>();
27+
}
28+
}
29+
30+
[JsonSerializable(typeof(FunctionParameters))]
31+
internal partial class FunctionParametersContext : JsonSerializerContext
32+
{
33+
}
1334
/*
1435
* CUSTOM CODE DESCRIPTION:
1536
*
@@ -52,7 +73,7 @@ public FunctionToolDefinition(string name, string description, BinaryData parame
5273
/// <param name="description"> A description of what the function does, used by the model to choose when and how to call the function. </param>
5374
/// <exception cref="ArgumentNullException"> <paramref name="name"/> or <paramref name="description"/> is null. </exception>
5475
public FunctionToolDefinition(string name, string description)
55-
: this(name, description, BinaryData.FromObjectAsJson(new { type = "object", properties = new { } }))
76+
: this(name, description, BinaryData.FromString(JsonSerializer.Serialize(new FunctionParameters(), FunctionParametersContext.Default.FunctionParameters)))
5677
{ }
5778

5879
/*
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Generic;
5+
using System.Text.Json;
6+
using System.Text.Json.Serialization;
7+
8+
namespace Azure.AI.Agents.Persistent;
9+
10+
[JsonSerializable(typeof(List<JsonElement>))]
11+
internal partial class JsonElementSerializer : JsonSerializerContext
12+
{
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Text.Json.Serialization;
5+
6+
namespace Azure.AI.Agents.Persistent;
7+
8+
internal class SerializableError
9+
{
10+
public string error { get; set; }
11+
public SerializableError(string message)
12+
{
13+
error = message;
14+
}
15+
}
16+
17+
[JsonSourceGenerationOptions(WriteIndented = true)]
18+
[JsonSerializable(typeof(SerializableError))]
19+
internal partial class SourceGenerationContext : JsonSerializerContext
20+
{
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Text.Json.Serialization;
5+
6+
namespace Azure.AI.Agents.Persistent;
7+
8+
[JsonSerializable(typeof(string))]
9+
internal partial class StringSerializerContext : JsonSerializerContext
10+
{
11+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Generic;
5+
using System.Text.Encodings.Web;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
8+
9+
namespace Azure.AI.Agents.Persistent;
10+
11+
// The set of helper classes to serialize the event object.
12+
13+
internal class EventContent
14+
{
15+
public string content { get; set; }
16+
public EventContent(string content) { this.content = content; }
17+
}
18+
19+
internal class EventRole
20+
{
21+
public string role { get; set; }
22+
public EventRole(string role) { this.role = role; }
23+
}
24+
25+
internal class EventContentRole
26+
{
27+
public string content { get; set; }
28+
public string role { get; set; }
29+
public EventContentRole(string content, string role)
30+
{
31+
this.content = content;
32+
this.role = role;
33+
}
34+
}
35+
36+
internal class EventContentId
37+
{
38+
public string content { get; set; }
39+
public string id { get; set; }
40+
public EventContentId(string content, string id)
41+
{
42+
this.content = content;
43+
this.id = id;
44+
}
45+
}
46+
47+
internal class BasicToolCallAttributes
48+
{
49+
public string id { get; set; } = "";
50+
public string type { get; set; } = "";
51+
public BasicToolCallAttributes(string id, string type)
52+
{
53+
this.id = id;
54+
this.type = type;
55+
}
56+
}
57+
58+
internal class FunctionCall
59+
{
60+
public string name { get; set; }
61+
public Dictionary<string, string> arguments { get; set; }
62+
public FunctionCall(string name, Dictionary<string, string> arguments)
63+
{
64+
this.name = name;
65+
this.arguments = arguments;
66+
}
67+
}
68+
69+
internal class FunctionToolCallEvent: BasicToolCallAttributes
70+
{
71+
public FunctionCall function { get; set; }
72+
public FunctionToolCallEvent(string id, string type, FunctionCall function) : base(id, type)
73+
{
74+
this.function = function;
75+
}
76+
}
77+
78+
//internal class CodeInterpreterOutputBase
79+
80+
internal class CodeInterpreterCallEvent : BasicToolCallAttributes
81+
{
82+
public string input { get; set; }
83+
public IReadOnlyList<RunStepCodeInterpreterToolCallOutput> outputs { get; set; }
84+
public CodeInterpreterCallEvent(string id, string type, string input, IReadOnlyList<RunStepCodeInterpreterToolCallOutput> outputs) : base(id, type)
85+
{
86+
this.input = input;
87+
this.outputs = outputs;
88+
}
89+
}
90+
91+
internal class BingGrounding : BasicToolCallAttributes
92+
{
93+
public IReadOnlyDictionary<string, string> bing_grounding { get; set; }
94+
public BingGrounding(string id, string type, IReadOnlyDictionary<string, string> details) : base(id, type)
95+
{
96+
this.bing_grounding = details;
97+
}
98+
}
99+
100+
internal class GenericToolCallEvent : BasicToolCallAttributes
101+
{
102+
public IReadOnlyDictionary<string, string> details { get; set; }
103+
public GenericToolCallEvent(string id, string type, IReadOnlyDictionary<string, string> details) : base(id, type)
104+
{
105+
this.details = details;
106+
}
107+
}
108+
109+
internal class ToolCallAttribute
110+
{
111+
public List<JsonElement> tool_calls { get; set; }
112+
public ToolCallAttribute(List<JsonElement> tool_calls)
113+
{
114+
this.tool_calls = tool_calls;
115+
}
116+
}
117+
118+
internal class ThreadMessageEventAttributes
119+
{
120+
public string role { get; set; }
121+
122+
public MessageIncompleteDetails incomplete_details { get; set; }
123+
public Dictionary<string, Dictionary<string, string>> content { get; set; }
124+
public IReadOnlyList<IReadOnlyDictionary<string, object>> attachments { get; set; }
125+
public ThreadMessageEventAttributes(
126+
string role,
127+
Dictionary<string, Dictionary<string, string>> content = null,
128+
IReadOnlyList<IReadOnlyDictionary<string, object>> attachments = null,
129+
MessageIncompleteDetails incompleteDetails = null
130+
)
131+
{
132+
this.content = content;
133+
this.attachments = attachments;
134+
this.incomplete_details = incompleteDetails;
135+
this.role = role;
136+
}
137+
}
138+
139+
[JsonSerializable(typeof(EventContentId))]
140+
[JsonSerializable(typeof(EventContentRole))]
141+
[JsonSerializable(typeof(EventRole))]
142+
[JsonSerializable(typeof(EventContent))]
143+
[JsonSerializable(typeof(Dictionary<string, string>))]
144+
[JsonSerializable(typeof(ToolCallAttribute))]
145+
[JsonSerializable(typeof(ThreadMessageEventAttributes))]
146+
// Specific tool call events
147+
[JsonSerializable(typeof(BasicToolCallAttributes))]
148+
[JsonSerializable(typeof(FunctionToolCallEvent))]
149+
[JsonSerializable(typeof(CodeInterpreterCallEvent))]
150+
[JsonSerializable(typeof(BingGrounding))]
151+
[JsonSerializable(typeof(GenericToolCallEvent))]
152+
internal partial class EventsContext : JsonSerializerContext
153+
{
154+
private JsonSerializerOptions _options;
155+
public new JsonSerializerOptions Options
156+
{
157+
get
158+
{
159+
JsonSerializerOptions options = _options;
160+
161+
if (options is null)
162+
{
163+
options = new JsonSerializerOptions
164+
{
165+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
166+
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, // Allow non-ASCII characters
167+
TypeInfoResolver = this
168+
};
169+
options.MakeReadOnly();
170+
_options = options;
171+
}
172+
173+
return options;
174+
}
175+
}
176+
}

sdk/ai/Azure.AI.Agents.Persistent/src/Custom/Streaming/AsyncStreamingUpdateCollection.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using System.Net.ServerSentEvents;
1010
using System.Text.Json;
11+
using System.Text.Json.Serialization;
1112
using System.Threading;
1213
using System.Threading.Tasks;
1314
using Azure.AI.Agents.Persistent.Telemetry;
@@ -99,7 +100,10 @@ protected async override IAsyncEnumerable<StreamingUpdate> GetValuesFromPageAsyn
99100
}
100101
catch (Exception ex)
101102
{
102-
string errorJson = JsonSerializer.Serialize(new { error = ex.GetBaseException().Message });
103+
string errorJson = JsonSerializer.Serialize(
104+
new SerializableError(ex.GetBaseException().Message),
105+
SourceGenerationContext.Default.SerializableError
106+
);
103107
toolOutput = new ToolOutput(newActionUpdate.ToolCallId, errorJson);
104108
hasError = true;
105109
}

sdk/ai/Azure.AI.Agents.Persistent/src/Custom/Streaming/StreamingUpdateCollection.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
using System.ClientModel.Primitives;
77
using System.Collections;
88
using System.Collections.Generic;
9-
using System.IO;
109
using System.Net.ServerSentEvents;
1110
using System.Text.Json;
1211
using System.Threading;
1312
using Azure.AI.Agents.Persistent.Telemetry;
14-
using System.Threading.Tasks;
1513

1614
#nullable enable
1715

@@ -95,7 +93,10 @@ protected override IEnumerable<StreamingUpdate> GetValuesFromPage(ClientResult p
9593
}
9694
catch (Exception ex)
9795
{
98-
string errorJson = JsonSerializer.Serialize(new { error = ex.GetBaseException().Message });
96+
string errorJson = JsonSerializer.Serialize(
97+
new SerializableError(ex.GetBaseException().Message),
98+
SourceGenerationContext.Default.SerializableError
99+
);
99100
toolOutput = new ToolOutput(newActionUpdate.ToolCallId, errorJson);
100101
hasError = true;
101102
}

0 commit comments

Comments
 (0)