Skip to content

Commit 3537bcb

Browse files
committed
WIP
1 parent b5f31ba commit 3537bcb

File tree

16 files changed

+163
-397
lines changed

16 files changed

+163
-397
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# Changelog - Agent Framework Toolkit
22

33
## Unreleased
4-
- Fixed that the AIAgentExtensions was in a wrongly names class called AIToolsExtensions
54
- `.RunAsync<T>(...)` in AIAgentExtensions now used provided serializationOptions (if given); only creating it's own if null.
65
- `.RunAsync<T>(...)` now support List/Array as T (using similar object wrapping technique as Microsoft.Extensions.AI)
76
- AzureOpenAI: Added Auto-correction of the Endpoint if you by mistake give the entire foundry url 'https://[name].services.ai.azure.com/api/projects/[project]' by on the fly correcting it to 'https://[name].services.ai.azure.com'. This is on by default, but can be turned off by setting property `AutoCorrectFoundryEndpoint` to false
7+
- Fixed that the AIAgentExtensions was in a wrongly names class called AIToolsExtensions
8+
- [BREAKING] `ApplyMiddleware` on the various options objects are moved to a central `MiddlewareHelper` to reduce code-duplication
9+
810
---
911

1012
## Version 1.0.0-preview.260108.1

development/Sandbox/Providers/AzureOpenAI.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static class AzureOpenAI
1717
[AITool]
1818
static string GetWeather()
1919
{
20-
return "Sunny";
20+
return "Sunny af 30 degrees";
2121
}
2222

2323
public static async Task RunAsync()
@@ -31,17 +31,10 @@ public static async Task RunAsync()
3131
ApiKey = secrets.AzureOpenAiKey,
3232
});
3333

34-
ChatClientAgent a = factory.Connection.GetClient().GetChatClient(OpenAIChatModels.Gpt41Nano).CreateAIAgent();
34+
AzureOpenAIAgent agent = factory.CreateAgent(OpenAIChatModels.Gpt41, instructions: null);
3535

36-
ChatClientAgentRunResponse<Movie[]> response = await a.RunAsync<Movie[]>("Give me the top 3 movies according to IMDB");
37-
38-
AzureOpenAIAgent agent = factory.CreateAgent(new AgentOptions
39-
{
40-
Model = OpenAIChatModels.Gpt41Nano,
41-
RawToolCallDetails = Console.WriteLine
42-
});
43-
44-
ChatClientAgentRunResponse<Movie[]> response2 = await agent.RunAsync<Movie[]>("Give me the top 3 movies according to IMDB");
36+
AgentRunResponse response2 = await agent.RunAsync("How is the weather?");
37+
Console.WriteLine(response2);
4538
}
4639

4740
private class MovieResult

src/AgentFrameworkToolkit.Anthropic/AnthropicAgentFactory.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,45 +68,50 @@ public AnthropicAgent CreateAgent(AnthropicAgentOptions options)
6868
{
6969
IChatClient client = Connection.GetClient(options.RawHttpCallDetails).AsIChatClient();
7070

71-
AIAgent innerAgent = new ChatClientAgent(client, CreateChatClientAgentOptions(options), options.LoggerFactory, options.Services);
72-
73-
// ReSharper disable once ConvertIfStatementToReturnStatement
74-
if (options.RawToolCallDetails != null || options.ToolCallingMiddleware != null || options.OpenTelemetryMiddleware != null || options.LoggingMiddleware != null)
75-
{
76-
return new AnthropicAgent(options.ApplyMiddleware(innerAgent));
77-
}
78-
79-
return new AnthropicAgent(innerAgent);
71+
AIAgent innerAgent = new ChatClientAgent(client, CreateChatClientAgentOptions(options),
72+
options.LoggerFactory,
73+
options.Services);
74+
75+
return new AnthropicAgent(MiddlewareHelper.ApplyMiddleware(
76+
innerAgent,
77+
options.RawToolCallDetails,
78+
options.ToolCallingMiddleware,
79+
options.OpenTelemetryMiddleware,
80+
options.LoggingMiddleware,
81+
options.Services));
8082
}
8183

8284
private static ChatClientAgentOptions CreateChatClientAgentOptions(AnthropicAgentOptions options)
8385
{
8486
ChatOptions chatOptions = new()
8587
{
8688
ModelId = options.Model,
87-
Instructions = options.Instructions
89+
MaxOutputTokens = options.MaxOutputTokens,
8890
};
8991

9092
if (options.Tools != null)
9193
{
9294
chatOptions.Tools = options.Tools;
9395
}
9496

95-
chatOptions.MaxOutputTokens = options.MaxOutputTokens;
97+
if (!string.IsNullOrWhiteSpace(options.Instructions))
98+
{
99+
chatOptions.Instructions = options.Instructions;
100+
}
96101

97102
if (options.Temperature != null)
98103
{
99104
chatOptions.Temperature = options.Temperature;
100105
}
101106

102-
if (options.BudgetTokens > 0)
107+
if (options.BudgetTokens != null)
103108
{
104109
chatOptions.RawRepresentationFactory = _ => new MessageCreateParams
105110
{
106111
MaxTokens = options.MaxOutputTokens,
107112
Messages = [],
108113
Model = options.Model,
109-
Thinking = new ThinkingConfigParam(new ThinkingConfigEnabled() { BudgetTokens = options.BudgetTokens }),
114+
Thinking = new ThinkingConfigParam(new ThinkingConfigEnabled() { BudgetTokens = options.BudgetTokens.Value }),
110115
};
111116
}
112117

@@ -117,7 +122,7 @@ private static ChatClientAgentOptions CreateChatClientAgentOptions(AnthropicAgen
117122
Id = options.Id,
118123
ChatOptions = chatOptions,
119124
AIContextProviderFactory = options.AIContextProviderFactory,
120-
ChatMessageStoreFactory = options.ChatMessageStoreFactory,
125+
ChatMessageStoreFactory = options.ChatMessageStoreFactory
121126
};
122127

123128
options.AdditionalChatClientAgentOptions?.Invoke(chatClientAgentOptions);

src/AgentFrameworkToolkit.Anthropic/AnthropicAgentOptions.cs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class AnthropicAgentOptions
6363
/// <summary>
6464
/// Reasoning effort knob, in tokens. Higher value --> more internal reasoning.
6565
/// </summary>
66-
public int BudgetTokens { get; set; }
66+
public int? BudgetTokens { get; set; }
6767

6868
/// <summary>The temperature for generating chat responses.</summary>
6969
/// <remarks>
@@ -108,36 +108,4 @@ public class AnthropicAgentOptions
108108
/// provide additional context for each agent run.
109109
/// </summary>
110110
public Func<AIContextProviderFactoryContext, AIContextProvider>? AIContextProviderFactory { get; set; }
111-
112-
/// <summary>
113-
/// Apply Middleware to the Agent, if needed
114-
/// </summary>
115-
/// <param name="innerAgent">The inner Agent</param>
116-
/// <returns>The Agent back with applied middleware</returns>
117-
public AIAgent ApplyMiddleware(AIAgent innerAgent)
118-
{
119-
AIAgentBuilder builder = innerAgent.AsBuilder();
120-
if (RawToolCallDetails != null)
121-
{
122-
builder = builder.Use(new ToolCallsHandler(RawToolCallDetails).ToolCallingMiddlewareAsync);
123-
}
124-
125-
if (OpenTelemetryMiddleware != null)
126-
{
127-
builder = builder.UseOpenTelemetry(OpenTelemetryMiddleware.Source, OpenTelemetryMiddleware.Configure);
128-
}
129-
130-
if (ToolCallingMiddleware != null)
131-
{
132-
builder = builder.Use(ToolCallingMiddleware.Invoke);
133-
}
134-
135-
if (LoggingMiddleware != null)
136-
{
137-
builder = builder.UseLogging(LoggingMiddleware.LoggerFactory, LoggingMiddleware.Configure);
138-
}
139-
140-
innerAgent = builder.Build(Services);
141-
return innerAgent;
142-
}
143111
}
Lines changed: 10 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
using AgentFrameworkToolkit.OpenAI;
2+
using Azure.AI.OpenAI;
23
using Azure.Core;
34
using JetBrains.Annotations;
45
using Microsoft.Agents.AI;
56
using Microsoft.Extensions.AI;
6-
using OpenAI;
7-
using OpenAI.Chat;
8-
using OpenAI.Responses;
9-
10-
#pragma warning disable OPENAI001
117

128
namespace AgentFrameworkToolkit.AzureOpenAI;
139

@@ -86,162 +82,14 @@ public AzureOpenAIAgent CreateAgent(string model, string? instructions = null, s
8682
/// <returns>The Agent</returns>
8783
public AzureOpenAIAgent CreateAgent(AgentOptions options)
8884
{
89-
OpenAIClient client = Connection.GetClient(options.RawHttpCallDetails);
90-
91-
ChatClientAgentOptions chatClientAgentOptions = CreateChatClientAgentOptions(options);
92-
93-
ChatClientAgent innerAgent;
94-
switch (options.ClientType)
95-
{
96-
case ClientType.ChatClient:
97-
innerAgent = client
98-
.GetChatClient(options.Model)
99-
.CreateAIAgent(chatClientAgentOptions, options.ClientFactory, options.LoggerFactory, options.Services);
100-
break;
101-
case ClientType.ResponsesApi:
102-
innerAgent = client
103-
.GetResponsesClient(options.Model)
104-
.CreateAIAgent(chatClientAgentOptions, options.ClientFactory, options.LoggerFactory, options.Services);
105-
break;
106-
case null:
107-
innerAgent = Connection.DefaultClientType switch
108-
{
109-
ClientType.ChatClient => client
110-
.GetChatClient(options.Model)
111-
.CreateAIAgent(chatClientAgentOptions, options.ClientFactory, options.LoggerFactory, options.Services),
112-
ClientType.ResponsesApi => client
113-
.GetResponsesClient(options.Model)
114-
.CreateAIAgent(chatClientAgentOptions, options.ClientFactory, options.LoggerFactory, options.Services),
115-
_ => throw new ArgumentOutOfRangeException()
116-
};
117-
break;
118-
default:
119-
throw new ArgumentOutOfRangeException();
120-
}
121-
122-
// ReSharper disable once ConvertIfStatementToReturnStatement
123-
if (options.RawToolCallDetails != null || options.ToolCallingMiddleware != null || options.OpenTelemetryMiddleware != null || options.LoggingMiddleware != null)
124-
{
125-
return new AzureOpenAIAgent(options.ApplyMiddleware(innerAgent));
126-
}
127-
128-
return new AzureOpenAIAgent(innerAgent);
129-
}
130-
131-
private ChatClientAgentOptions CreateChatClientAgentOptions(AgentOptions options)
132-
{
133-
bool anyOptionsSet = false;
134-
ChatOptions chatOptions = new();
135-
if (options.Tools != null)
136-
{
137-
anyOptionsSet = true;
138-
chatOptions.Tools = options.Tools;
139-
}
140-
141-
if (options.MaxOutputTokens.HasValue)
142-
{
143-
anyOptionsSet = true;
144-
chatOptions.MaxOutputTokens = options.MaxOutputTokens.Value;
145-
}
146-
147-
if (options.Temperature != null && !OpenAIChatModels.ReasoningModels.Contains(options.Model))
148-
{
149-
anyOptionsSet = true;
150-
chatOptions.Temperature = options.Temperature;
151-
}
152-
153-
if (!string.IsNullOrWhiteSpace(options.Instructions))
154-
{
155-
anyOptionsSet = true;
156-
chatOptions.Instructions = options.Instructions;
157-
}
158-
159-
string? reasoningEffortAsString = null;
160-
switch (options.ReasoningEffort)
161-
{
162-
case OpenAIReasoningEffort.None:
163-
reasoningEffortAsString = "none";
164-
break;
165-
case OpenAIReasoningEffort.Minimal:
166-
reasoningEffortAsString = "minimal";
167-
break;
168-
case OpenAIReasoningEffort.Low:
169-
reasoningEffortAsString = "low";
170-
break;
171-
case OpenAIReasoningEffort.Medium:
172-
reasoningEffortAsString = "medium";
173-
break;
174-
case OpenAIReasoningEffort.High:
175-
reasoningEffortAsString = "high";
176-
break;
177-
case OpenAIReasoningEffort.ExtraHigh:
178-
reasoningEffortAsString = "xhigh";
179-
break;
180-
}
181-
182-
if (!string.IsNullOrWhiteSpace(reasoningEffortAsString) && !OpenAIChatModels.NonReasoningModels.Contains(options.Model))
183-
{
184-
anyOptionsSet = true;
185-
186-
switch (options.ClientType)
187-
{
188-
case ClientType.ChatClient:
189-
chatOptions = chatOptions.WithOpenAIChatClientReasoning(new ChatReasoningEffortLevel(reasoningEffortAsString));
190-
break;
191-
case ClientType.ResponsesApi:
192-
switch (options.ReasoningSummaryVerbosity)
193-
{
194-
case OpenAIReasoningSummaryVerbosity.Auto:
195-
chatOptions = chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Auto);
196-
break;
197-
case OpenAIReasoningSummaryVerbosity.Concise:
198-
chatOptions = chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Concise);
199-
break;
200-
case OpenAIReasoningSummaryVerbosity.Detailed:
201-
chatOptions = chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Detailed);
202-
break;
203-
case null:
204-
chatOptions = chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString));
205-
break;
206-
}
207-
208-
break;
209-
case null:
210-
chatOptions = Connection.DefaultClientType switch
211-
{
212-
ClientType.ChatClient => chatOptions.WithOpenAIChatClientReasoning(new ChatReasoningEffortLevel(reasoningEffortAsString)),
213-
ClientType.ResponsesApi => options.ReasoningSummaryVerbosity switch
214-
{
215-
OpenAIReasoningSummaryVerbosity.Auto => chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Auto),
216-
OpenAIReasoningSummaryVerbosity.Concise => chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Concise),
217-
OpenAIReasoningSummaryVerbosity.Detailed => chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString), ResponseReasoningSummaryVerbosity.Detailed),
218-
null => chatOptions.WithOpenAIResponsesApiReasoning(new ResponseReasoningEffortLevel(reasoningEffortAsString)),
219-
_ => chatOptions
220-
},
221-
_ => throw new ArgumentOutOfRangeException()
222-
};
223-
224-
break;
225-
default:
226-
throw new ArgumentOutOfRangeException();
227-
}
228-
}
229-
230-
ChatClientAgentOptions chatClientAgentOptions = new()
231-
{
232-
Name = options.Name,
233-
Description = options.Description,
234-
Id = options.Id,
235-
AIContextProviderFactory = options.AIContextProviderFactory,
236-
ChatMessageStoreFactory = options.ChatMessageStoreFactory,
237-
};
238-
if (anyOptionsSet)
239-
{
240-
chatClientAgentOptions.ChatOptions = chatOptions;
241-
}
242-
243-
options.AdditionalChatClientAgentOptions?.Invoke(chatClientAgentOptions);
244-
245-
return chatClientAgentOptions;
85+
AzureOpenAIClient client = Connection.GetClient(options.RawHttpCallDetails);
86+
ChatClientAgent innerAgent = OpenAIAgentFactory.GetChatClientAgent(options, client, options.Model, Connection.DefaultClientType);
87+
return new AzureOpenAIAgent(MiddlewareHelper.ApplyMiddleware(
88+
innerAgent,
89+
options.RawToolCallDetails,
90+
options.ToolCallingMiddleware,
91+
options.OpenTelemetryMiddleware,
92+
options.LoggingMiddleware,
93+
options.Services));
24694
}
24795
}

src/AgentFrameworkToolkit.GitHub/GitHubAgentFactory.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,20 @@ public GitHubAgent CreateAgent(string model, string? instructions = null, string
6363
public GitHubAgent CreateAgent(GitHubAgentOptions options)
6464
{
6565
IChatClient client = Connection.GetClient(options.RawHttpCallDetails).AsIChatClient(options.Model);
66-
AIAgent innerAgent = new ChatClientAgent(client, CreateChatClientAgentOptions(options), options.LoggerFactory, options.Services);
66+
AIAgent innerAgent = new ChatClientAgent(client, CreateChatClientAgentOptions(options),
67+
options.LoggerFactory,
68+
options.Services);
6769

6870
// ReSharper disable once ConvertIfStatementToReturnStatement
6971
if (options.RawToolCallDetails != null || options.ToolCallingMiddleware != null || options.OpenTelemetryMiddleware != null || options.LoggingMiddleware != null)
7072
{
71-
return new GitHubAgent(options.ApplyMiddleware(innerAgent));
73+
return new GitHubAgent(MiddlewareHelper.ApplyMiddleware(
74+
innerAgent,
75+
options.RawToolCallDetails,
76+
options.ToolCallingMiddleware,
77+
options.OpenTelemetryMiddleware,
78+
options.LoggingMiddleware,
79+
options.Services));
7280
}
7381

7482
return new GitHubAgent(innerAgent);

0 commit comments

Comments
 (0)