mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c798cb7a2e | ||
|
|
3446eb8d5d | ||
|
|
5f06b68535 | ||
|
|
524c0216e4 | ||
|
|
281661e409 | ||
|
|
b0613a8ceb | ||
|
|
79b38040e8 | ||
|
|
a356a16568 |
+2
-1
@@ -29,7 +29,8 @@ using types like `IChatClient`, `FunctionInvokingChatClient`, `AITool`, `AIFunct
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- **Encoding**: All new files must be saved with UTF-8 encoding with BOM (Byte Order Mark). This is required for `dotnet format` to work correctly.
|
||||
- **Command output capture**: When running `dotnet build`, `dotnet test`, `dotnet format`, or similar commands, redirect output to a temp file first (e.g., `dotnet build --tl:off 2>&1 | Out-File $env:TEMP\build.log`), then analyze the file as needed. This avoids re-running expensive commands when the initial analysis misses something.
|
||||
- **Encoding**: All new files must be saved with UTF-8 encoding with BOM (Byte Order Mark). This is required for `dotnet format` to work correctly. When using PowerShell `Set-Content`, always pass `-Encoding UTF8BOM` to preserve the BOM (e.g., `Set-Content $file $content -NoNewline -Encoding UTF8BOM`).
|
||||
- **Copyright header**: `// Copyright (c) Microsoft. All rights reserved.` at top of all `.cs` files
|
||||
- **XML docs**: Required for all public methods and classes
|
||||
- **Async**: Use `Async` suffix for methods returning `Task`/`ValueTask`
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>false</IsReleaseCandidate>
|
||||
<IsGenerallyAvailable>false</IsGenerallyAvailable>
|
||||
<IsReleased>false</IsReleased>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="$(AspireAppHostSdkVersion)" />
|
||||
<PackageVersion Include="CommunityToolkit.Aspire.OllamaSharp" Version="13.0.0" />
|
||||
<!-- Azure.* -->
|
||||
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0-beta.2" />
|
||||
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0" />
|
||||
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.10" />
|
||||
<PackageVersion Include="Azure.AI.OpenAI" Version="2.9.0-beta.1" />
|
||||
<PackageVersion Include="Azure.Identity" Version="1.19.0" />
|
||||
<PackageVersion Include="Azure.Identity" Version="1.20.0" />
|
||||
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
|
||||
<!-- Google Gemini -->
|
||||
<PackageVersion Include="Google.GenAI" Version="0.11.0" />
|
||||
<PackageVersion Include="Google.GenAI" Version="1.6.0" />
|
||||
<PackageVersion Include="Mscc.GenerativeAI.Microsoft" Version="2.9.3" />
|
||||
<!-- Microsoft.Azure.* -->
|
||||
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.54.0" />
|
||||
@@ -35,7 +35,7 @@
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.4" />
|
||||
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
|
||||
<PackageVersion Include="Microsoft.Bcl.Memory" Version="10.0.4" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.9.0" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.10.0" />
|
||||
<PackageVersion Include="System.CodeDom" Version="10.0.0" />
|
||||
<PackageVersion Include="System.Collections.Immutable" Version="10.0.1" />
|
||||
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_GoogleGemini/Agent_With_GoogleGemini.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_Ollama/Agent_With_Ollama.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_ONNX/Agent_With_ONNX.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIChatCompletion/Agent_With_OpenAIChatCompletion.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIResponses/Agent_With_OpenAIResponses.csproj" />
|
||||
</Folder>
|
||||
|
||||
@@ -781,19 +781,6 @@ internal static class AgentsSamples
|
||||
SkipReason = "Requires local Ollama server.",
|
||||
},
|
||||
|
||||
new SampleDefinition
|
||||
{
|
||||
Name = "Agent_With_OpenAIAssistants",
|
||||
ProjectPath = "samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants",
|
||||
RequiredEnvironmentVariables = ["OPENAI_API_KEY"],
|
||||
OptionalEnvironmentVariables = ["OPENAI_CHAT_MODEL_NAME"],
|
||||
ExpectedOutputDescription =
|
||||
[
|
||||
"The output should contain a joke about a pirate from the OpenAI Assistants API.",
|
||||
"The output should not contain error messages or stack traces.",
|
||||
],
|
||||
},
|
||||
|
||||
new SampleDefinition
|
||||
{
|
||||
Name = "Agent_With_OpenAIChatCompletion",
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
<PropertyGroup>
|
||||
<!-- Central version prefix - applies to all nuget packages. -->
|
||||
<VersionPrefix>1.0.0</VersionPrefix>
|
||||
<RCNumber>5</RCNumber>
|
||||
<RCNumber>6</RCNumber>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' == 'true'">$(VersionPrefix)-rc$(RCNumber)</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix).260330.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' == ''">$(VersionPrefix)-preview.260330.1</PackageVersion>
|
||||
<GitTag>1.0.0-rc5</GitTag>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix).260402.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' == ''">$(VersionPrefix)-preview.260402.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleased)' == 'true'">$(VersionPrefix)</PackageVersion>
|
||||
<GitTag>1.0.0</GitTag>
|
||||
|
||||
<Configurations>Debug;Release;Publish</Configurations>
|
||||
<IsPackable>true</IsPackable>
|
||||
|
||||
<!-- Package validation. Baseline Version should be the latest version available on NuGet. -->
|
||||
<PackageValidationBaselineVersion>1.0.0-rc4</PackageValidationBaselineVersion>
|
||||
<PackageValidationBaselineVersion>1.0.0-rc5</PackageValidationBaselineVersion>
|
||||
<!-- Enable validation for RC packages and GA packages -->
|
||||
<EnablePackageValidation Condition="'$(IsReleaseCandidate)' == 'true' OR '$(IsGenerallyAvailable)' == 'true'">true</EnablePackageValidation>
|
||||
<EnablePackageValidation Condition="'$(IsReleaseCandidate)' == 'true' OR '$(IsReleased)' == 'true'">true</EnablePackageValidation>
|
||||
<!-- Validate assembly attributes only for Publish builds -->
|
||||
<NoWarn Condition="'$(Configuration)' != 'Publish'">$(NoWarn);CP0003</NoWarn>
|
||||
<!-- Do not validate reference assemblies -->
|
||||
|
||||
@@ -20,10 +20,10 @@ const string JokerName = "JokerAgent";
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
// Define the agent you want to create. (Prompt Agent in this case)
|
||||
var agentVersionCreationOptions = new AgentVersionCreationOptions(new PromptAgentDefinition(model: deploymentName) { Instructions = "You are good at telling jokes." });
|
||||
var agentVersionCreationOptions = new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition(model: deploymentName) { Instructions = "You are good at telling jokes." });
|
||||
// Azure.AI.Agents SDK creates and manages agent by name and versions.
|
||||
// You can create a server side agent version with the Azure.AI.Agents SDK client below.
|
||||
var createdAgentVersion = aiProjectClient.Agents.CreateAgentVersion(agentName: JokerName, options: agentVersionCreationOptions);
|
||||
var createdAgentVersion = aiProjectClient.AgentAdministrationClient.CreateAgentVersion(agentName: JokerName, options: agentVersionCreationOptions);
|
||||
|
||||
// Note:
|
||||
// agentVersion.Id = "<agentName>:<versionNumber>",
|
||||
@@ -34,15 +34,15 @@ var createdAgentVersion = aiProjectClient.Agents.CreateAgentVersion(agentName: J
|
||||
FoundryAgent existingJokerAgent = aiProjectClient.AsAIAgent(createdAgentVersion);
|
||||
|
||||
// You can also create another AIAgent version by providing the same name with a different definition.
|
||||
AgentVersion newJokerAgentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion newJokerAgentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
JokerName,
|
||||
new AgentVersionCreationOptions(new PromptAgentDefinition(model: deploymentName) { Instructions = "You are extremely hilarious at telling jokes." }));
|
||||
new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition(model: deploymentName) { Instructions = "You are extremely hilarious at telling jokes." }));
|
||||
FoundryAgent newJokerAgent = aiProjectClient.AsAIAgent(newJokerAgentVersion);
|
||||
|
||||
// You can also get the AIAgent latest version just providing its name.
|
||||
AgentRecord jokerAgentRecord = await aiProjectClient.Agents.GetAgentAsync(JokerName);
|
||||
ProjectsAgentRecord jokerAgentRecord = await aiProjectClient.AgentAdministrationClient.GetAgentAsync(JokerName);
|
||||
FoundryAgent jokerAgentLatest = aiProjectClient.AsAIAgent(jokerAgentRecord);
|
||||
AgentVersion latestAgentVersion = jokerAgentRecord.GetLatestVersion();
|
||||
ProjectsAgentVersion latestAgentVersion = jokerAgentRecord.GetLatestVersion();
|
||||
|
||||
// The AIAgent version can be accessed via the GetService method.
|
||||
Console.WriteLine($"Latest agent version id: {latestAgentVersion.Id}");
|
||||
@@ -55,4 +55,4 @@ Console.WriteLine(await jokerAgentLatest.RunAsync("Tell me a joke about a pirate
|
||||
Console.WriteLine(await jokerAgentLatest.RunAsync("Now tell me a joke about a cat and a dog using last joke as the anchor.", session));
|
||||
|
||||
// Cleanup by agent name removes both agent versions created.
|
||||
aiProjectClient.Agents.DeleteAgent(existingJokerAgent.Name);
|
||||
aiProjectClient.AgentAdministrationClient.DeleteAgent(existingJokerAgent.Name);
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// This sample shows how to create and use a simple AI agent with OpenAI Assistants as the backend.
|
||||
|
||||
// WARNING: The Assistants API is deprecated and will be shut down.
|
||||
// For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete - OpenAI Assistants API is deprecated but still used in this sample
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Assistants;
|
||||
|
||||
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
|
||||
var model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-4o-mini";
|
||||
|
||||
const string JokerName = "Joker";
|
||||
const string JokerInstructions = "You are good at telling jokes.";
|
||||
|
||||
// Get a client to create/retrieve server side agents with.
|
||||
var assistantClient = new OpenAIClient(apiKey).GetAssistantClient();
|
||||
|
||||
// You can create a server side assistant with the OpenAI SDK.
|
||||
var createResult = await assistantClient.CreateAssistantAsync(model, new() { Name = JokerName, Instructions = JokerInstructions });
|
||||
|
||||
// You can retrieve an already created server side assistant as an AIAgent.
|
||||
AIAgent agent1 = await assistantClient.GetAIAgentAsync(createResult.Value.Id);
|
||||
|
||||
// You can also create a server side assistant and return it as an AIAgent directly.
|
||||
AIAgent agent2 = await assistantClient.CreateAIAgentAsync(
|
||||
model: model,
|
||||
name: JokerName,
|
||||
instructions: JokerInstructions);
|
||||
|
||||
// You can invoke the agent like any other AIAgent.
|
||||
AgentSession session = await agent1.CreateSessionAsync();
|
||||
Console.WriteLine(await agent1.RunAsync("Tell me a joke about a pirate.", session));
|
||||
|
||||
// Cleanup for sample purposes.
|
||||
await assistantClient.DeleteAssistantAsync(agent1.Id);
|
||||
await assistantClient.DeleteAssistantAsync(agent2.Id);
|
||||
@@ -1,16 +0,0 @@
|
||||
# Prerequisites
|
||||
|
||||
WARNING: The Assistants API is deprecated and will be shut down.
|
||||
For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
|
||||
|
||||
Before you begin, ensure you have the following prerequisites:
|
||||
|
||||
- .NET 10 SDK or later
|
||||
- OpenAI API key
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
```powershell
|
||||
$env:OPENAI_API_KEY="*****" # Replace with your OpenAI API key
|
||||
$env:OPENAI_CHAT_MODEL_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
|
||||
```
|
||||
@@ -25,7 +25,6 @@ See the README.md for each sample for the prerequisites for that sample.
|
||||
|[Creating an AIAgent with GitHub Copilot](./Agent_With_GitHubCopilot/)|This sample demonstrates how to create an AIAgent using GitHub Copilot SDK as the underlying inference service|
|
||||
|[Creating an AIAgent with Ollama](./Agent_With_Ollama/)|This sample demonstrates how to create an AIAgent using Ollama as the underlying inference service|
|
||||
|[Creating an AIAgent with ONNX](./Agent_With_ONNX/)|This sample demonstrates how to create an AIAgent using ONNX as the underlying inference service|
|
||||
|[Creating an AIAgent with OpenAI Assistants](./Agent_With_OpenAIAssistants/)|This sample demonstrates how to create an AIAgent using OpenAI Assistants as the underlying inference service.</br>WARNING: The Assistants API is deprecated and will be shut down. For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration|
|
||||
|[Creating an AIAgent with OpenAI ChatCompletion](./Agent_With_OpenAIChatCompletion/)|This sample demonstrates how to create an AIAgent using OpenAI ChatCompletion as the underlying inference service|
|
||||
|[Creating an AIAgent with OpenAI Responses](./Agent_With_OpenAIResponses/)|This sample demonstrates how to create an AIAgent using OpenAI Responses as the underlying inference service|
|
||||
|
||||
|
||||
+4
-4
@@ -44,10 +44,10 @@ ClientResult<VectorStore> vectorStoreCreate = await vectorStoreClient.CreateVect
|
||||
FileSearchTool fileSearchTool = new([vectorStoreCreate.Value.Id]);
|
||||
#pragma warning restore OPENAI001
|
||||
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
"AskContoso",
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.",
|
||||
Tools = { fileSearchTool }
|
||||
@@ -68,4 +68,4 @@ Console.WriteLine(await agent.RunAsync("What is the best way to maintain the Tra
|
||||
// Cleanup
|
||||
await fileClient.DeleteFileAsync(uploadResult.Value.Id);
|
||||
await vectorStoreClient.DeleteVectorStoreAsync(vectorStoreCreate.Value.Id);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
|
||||
@@ -19,10 +19,10 @@ var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYME
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
// Create a server side agent and expose it as an AIAgent.
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
"Joker",
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.",
|
||||
})
|
||||
|
||||
+4
-4
@@ -18,10 +18,10 @@ const string JokerName = "JokerAgent";
|
||||
AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential());
|
||||
|
||||
// Create a server-side agent version using the native SDK.
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
JokerName,
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are good at telling jokes.",
|
||||
}));
|
||||
@@ -33,4 +33,4 @@ FoundryAgent agent = aiProjectClient.AsAIAgent(agentVersion);
|
||||
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
|
||||
|
||||
// Cleanup: deletes the agent and all its versions.
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Agents;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
|
||||
@@ -31,10 +31,10 @@ var mcpTool = ResponseTool.CreateMcpTool(
|
||||
toolCallApprovalPolicy: new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.NeverRequireApproval));
|
||||
|
||||
// Create a server side agent with the mcp tool, and expose it as an AIAgent.
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
"MicrosoftLearnAgent",
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = "You answer questions by searching the Microsoft Learn content only.",
|
||||
Tools = { mcpTool }
|
||||
@@ -47,7 +47,7 @@ AgentSession session = await agent.CreateSessionAsync();
|
||||
Console.WriteLine(await agent.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", session));
|
||||
|
||||
// Cleanup for sample purposes.
|
||||
aiProjectClient.Agents.DeleteAgent(agent.Name);
|
||||
aiProjectClient.AgentAdministrationClient.DeleteAgent(agent.Name);
|
||||
|
||||
// **** MCP Tool with Approval Required ****
|
||||
// *****************************************
|
||||
@@ -61,10 +61,10 @@ var mcpToolWithApproval = ResponseTool.CreateMcpTool(
|
||||
toolCallApprovalPolicy: new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.AlwaysRequireApproval));
|
||||
|
||||
// Create an agent with the MCP tool that requires approval.
|
||||
AgentVersion agentVersionWithApproval = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersionWithApproval = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
"MicrosoftLearnAgentWithApproval",
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = "You answer questions by searching the Microsoft Learn content only.",
|
||||
Tools = { mcpToolWithApproval }
|
||||
|
||||
@@ -58,9 +58,9 @@ public static class Program
|
||||
finally
|
||||
{
|
||||
// Cleanup the agents created for the sample.
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(frenchAgent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(spanishAgent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(englishAgent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(frenchAgent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(spanishAgent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(englishAgent.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,10 @@ public static class Program
|
||||
AIProjectClient aiProjectClient,
|
||||
string model)
|
||||
{
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
$"{targetLanguage} Translator",
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = $"You are a translation assistant that translates the provided text to {targetLanguage}.",
|
||||
}));
|
||||
|
||||
@@ -97,7 +97,7 @@ internal sealed class Program
|
||||
agentDescription: "Escalate agent for human support");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineSelfServiceAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineSelfServiceAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -144,7 +144,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineTicketingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static DeclarativeAgentDefinition DefineTicketingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -208,7 +208,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineTicketRoutingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static DeclarativeAgentDefinition DefineTicketRoutingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -253,7 +253,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineWindowsSupportAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static DeclarativeAgentDefinition DefineWindowsSupportAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -323,7 +323,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineResolutionAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static DeclarativeAgentDefinition DefineResolutionAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -357,7 +357,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition TicketEscalationAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static DeclarativeAgentDefinition TicketEscalationAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -88,7 +88,7 @@ internal sealed class Program
|
||||
agentDescription: "Weather agent for DeepResearch workflow");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineResearchAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineResearchAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -114,13 +114,13 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefinePlannerAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefinePlannerAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions = // TODO: Use Structured Inputs / Prompt Template
|
||||
@@ -139,7 +139,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineManagerAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineManagerAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions = // TODO: Use Structured Inputs / Prompt Template
|
||||
@@ -225,7 +225,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineSummaryAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineSummaryAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -240,18 +240,18 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineKnowledgeAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineKnowledgeAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Tools =
|
||||
{
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineCoderAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineCoderAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -265,7 +265,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineWeatherAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineWeatherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -274,7 +274,7 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
AgentTool.CreateOpenApiTool(
|
||||
ProjectsAgentTool.CreateOpenApiTool(
|
||||
new OpenApiFunctionDefinition(
|
||||
"weather-forecast",
|
||||
BinaryData.FromString(File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "wttr.json"))),
|
||||
|
||||
@@ -67,9 +67,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
private static DeclarativeAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
{
|
||||
PromptAgentDefinition agentDefinition =
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -46,7 +46,7 @@ internal sealed class Program
|
||||
await CreateAgentsAsync(aiProjectClient, configuration);
|
||||
|
||||
// Ensure workflow agent exists in Foundry.
|
||||
AgentVersion agentVersion = await CreateWorkflowAsync(aiProjectClient, configuration);
|
||||
ProjectsAgentVersion agentVersion = await CreateWorkflowAsync(aiProjectClient, configuration);
|
||||
|
||||
string workflowInput = GetWorkflowInput(args);
|
||||
|
||||
@@ -86,7 +86,7 @@ internal sealed class Program
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<AgentVersion> CreateWorkflowAsync(AIProjectClient agentClient, IConfiguration configuration)
|
||||
private static async Task<ProjectsAgentVersion> CreateWorkflowAsync(AIProjectClient agentClient, IConfiguration configuration)
|
||||
{
|
||||
string workflowYaml = File.ReadAllText("MathChat.yaml");
|
||||
|
||||
@@ -114,7 +114,7 @@ internal sealed class Program
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -127,7 +127,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -68,7 +68,7 @@ internal sealed class Program
|
||||
agentDescription: "Chats with the user with location awareness.");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineLocationTriageAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineLocationTriageAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -79,7 +79,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineLocationCaptureAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineLocationCaptureAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -128,7 +128,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineLocationAwareAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineLocationAwareAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
// Parameterized instructions reference the "location" input argument.
|
||||
|
||||
@@ -63,9 +63,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
private static DeclarativeAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
{
|
||||
PromptAgentDefinition agentDefinition =
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -125,9 +125,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information based on search results");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineSearchAgent(IConfiguration configuration)
|
||||
private static DeclarativeAgentDefinition DefineSearchAgent(IConfiguration configuration)
|
||||
{
|
||||
return new PromptAgentDefinition(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
return new DeclarativeAgentDefinition(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
"""
|
||||
|
||||
@@ -67,7 +67,7 @@ internal sealed class Program
|
||||
agentDescription: "Editor agent for Marketing workflow");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineAnalystAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineAnalystAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -79,13 +79,13 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(configuration[Application.Settings.FoundryGroundingTool])]))
|
||||
}
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineWriterAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineWriterAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -96,7 +96,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineEditorAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineEditorAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -62,7 +62,7 @@ internal sealed class Program
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -75,7 +75,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static PromptAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -58,7 +58,7 @@ internal sealed class Program
|
||||
agentDescription: "Searches documents on Microsoft Learn");
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition DefineSearchAgent(IConfiguration configuration) =>
|
||||
private static DeclarativeAgentDefinition DefineSearchAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+1
@@ -6,6 +6,7 @@
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);MAAIW001</NoWarn> <!-- Handoff Orchestrations are Experimental -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -20,7 +20,7 @@ internal static class HostAgentFactory
|
||||
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
AgentRecord agentRecord = await aiProjectClient.Agents.GetAgentAsync(agentName);
|
||||
ProjectsAgentRecord agentRecord = await aiProjectClient.AgentAdministrationClient.GetAgentAsync(agentName);
|
||||
AIAgent agent = aiProjectClient.AsAIAgent(agentRecord, tools: tools);
|
||||
|
||||
AgentCard agentCard = agentType.ToUpperInvariant() switch
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.Agents.AI</RootNamespace>
|
||||
<NoWarn>$(NoWarn);MEAI001</NoWarn>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -25,8 +25,8 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
{
|
||||
private readonly ChatClientMetadata? _metadata;
|
||||
private readonly AIProjectClient _agentClient;
|
||||
private readonly AgentVersion? _agentVersion;
|
||||
private readonly AgentRecord? _agentRecord;
|
||||
private readonly ProjectsAgentVersion? _agentVersion;
|
||||
private readonly ProjectsAgentRecord? _agentRecord;
|
||||
private readonly ChatOptions? _chatOptions;
|
||||
private readonly AgentReference _agentReference;
|
||||
|
||||
@@ -56,34 +56,34 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
/// Initializes a new instance of the <see cref="AzureAIProjectChatClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">An instance of <see cref="AIProjectClient"/> to interact with Azure AI Agents services.</param>
|
||||
/// <param name="agentRecord">An instance of <see cref="AgentRecord"/> representing the specific agent to use.</param>
|
||||
/// <param name="agentRecord">An instance of <see cref="ProjectsAgentRecord"/> representing the specific agent to use.</param>
|
||||
/// <param name="chatOptions">An instance of <see cref="ChatOptions"/> representing the options on how the agent was predefined.</param>
|
||||
/// <remarks>
|
||||
/// The <see cref="IChatClient"/> provided should be decorated with a <see cref="AzureAIProjectChatClient"/> for proper functionality.
|
||||
/// </remarks>
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, AgentRecord agentRecord, ChatOptions? chatOptions)
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, ProjectsAgentRecord agentRecord, ChatOptions? chatOptions)
|
||||
: this(aiProjectClient, Throw.IfNull(agentRecord).GetLatestVersion(), chatOptions)
|
||||
{
|
||||
this._agentRecord = agentRecord;
|
||||
}
|
||||
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, AgentVersion agentVersion, ChatOptions? chatOptions)
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, ProjectsAgentVersion agentVersion, ChatOptions? chatOptions)
|
||||
: this(
|
||||
aiProjectClient,
|
||||
CreateAgentReference(Throw.IfNull(agentVersion)),
|
||||
(agentVersion.Definition as PromptAgentDefinition)?.Model,
|
||||
(agentVersion.Definition as DeclarativeAgentDefinition)?.Model,
|
||||
chatOptions)
|
||||
{
|
||||
this._agentVersion = agentVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AgentReference"/> from an <see cref="AgentVersion"/>.
|
||||
/// Creates an <see cref="AgentReference"/> from an <see cref="ProjectsAgentVersion"/>.
|
||||
/// Uses the agent version's version if available, otherwise defaults to "latest".
|
||||
/// </summary>
|
||||
/// <param name="agentVersion">The agent version to create a reference from.</param>
|
||||
/// <returns>An <see cref="AgentReference"/> for the specified agent version.</returns>
|
||||
private static AgentReference CreateAgentReference(AgentVersion agentVersion)
|
||||
private static AgentReference CreateAgentReference(ProjectsAgentVersion agentVersion)
|
||||
{
|
||||
// If the version is null, empty, or whitespace, use "latest" as the default.
|
||||
// This handles cases where hosted agents (like MCP agents) may not have a version assigned.
|
||||
@@ -98,9 +98,9 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
? this._metadata
|
||||
: (serviceKey is null && serviceType == typeof(AIProjectClient))
|
||||
? this._agentClient
|
||||
: (serviceKey is null && serviceType == typeof(AgentVersion))
|
||||
: (serviceKey is null && serviceType == typeof(ProjectsAgentVersion))
|
||||
? this._agentVersion
|
||||
: (serviceKey is null && serviceType == typeof(AgentRecord))
|
||||
: (serviceKey is null && serviceType == typeof(ProjectsAgentRecord))
|
||||
? this._agentRecord
|
||||
: (serviceKey is null && serviceType == typeof(AgentReference))
|
||||
? this._agentReference
|
||||
|
||||
@@ -38,7 +38,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="InvalidOperationException">The agent with the specified name was not found.</exception>
|
||||
/// <remarks>
|
||||
/// When instantiating a <see cref="ChatClientAgent"/> by using an <see cref="AgentReference"/>, minimal information will be available about the agent in the instance level, and any logic that relies
|
||||
/// on <see cref="AIAgent.GetService{TService}(object?)"/> to retrieve information about the agent like <see cref="AgentVersion" /> will receive <see langword="null"/> as the result.
|
||||
/// on <see cref="AIAgent.GetService{TService}(object?)"/> to retrieve information about the agent like <see cref="ProjectsAgentVersion" /> will receive <see langword="null"/> as the result.
|
||||
/// </remarks>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
@@ -67,7 +67,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="AgentRecord"/>.
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="ProjectsAgentRecord"/>.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||
/// <param name="agentRecord">The agent record to be converted. The latest version will be used. Cannot be <see langword="null"/>.</param>
|
||||
@@ -78,7 +78,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="aiProjectClient"/> or <paramref name="agentRecord"/> is <see langword="null"/>.</exception>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
AgentRecord agentRecord,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
@@ -100,7 +100,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="AgentVersion"/>.
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="ProjectsAgentVersion"/>.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||
/// <param name="agentVersion">The agent version to be converted. Cannot be <see langword="null"/>.</param>
|
||||
@@ -111,7 +111,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="aiProjectClient"/> or <paramref name="agentVersion"/> is <see langword="null"/>.</exception>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
AgentVersion agentVersion,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
@@ -206,7 +206,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>Creates a <see cref="ChatClientAgent"/> with the specified options.</summary>
|
||||
private static ChatClientAgent CreateChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
AgentVersion agentVersion,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -249,7 +249,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with the specified ChatClientAgentOptions.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
AgentVersion agentVersion,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -258,7 +258,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with the specified ChatClientAgentOptions.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
AgentRecord agentRecord,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -293,14 +293,14 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with a auto-generated ChatClientAgentOptions from the specified configuration parameters.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient AIProjectClient,
|
||||
AgentVersion agentVersion,
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
IList<AITool>? tools,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
bool requireInvocableTools,
|
||||
IServiceProvider? services)
|
||||
=> AsChatClientAgent(
|
||||
AIProjectClient,
|
||||
aiProjectClient,
|
||||
agentVersion,
|
||||
CreateChatClientAgentOptions(agentVersion, new ChatOptions() { Tools = tools }, requireInvocableTools),
|
||||
clientFactory,
|
||||
@@ -308,21 +308,21 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with a auto-generated ChatClientAgentOptions from the specified configuration parameters.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient AIProjectClient,
|
||||
AgentRecord agentRecord,
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
IList<AITool>? tools,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
bool requireInvocableTools,
|
||||
IServiceProvider? services)
|
||||
=> AsChatClientAgent(
|
||||
AIProjectClient,
|
||||
aiProjectClient,
|
||||
agentRecord,
|
||||
CreateChatClientAgentOptions(agentRecord.GetLatestVersion(), new ChatOptions() { Tools = tools }, requireInvocableTools),
|
||||
clientFactory,
|
||||
services);
|
||||
|
||||
/// <summary>
|
||||
/// This method creates <see cref="ChatClientAgentOptions"/> for the specified <see cref="AgentVersion"/> and the provided tools.
|
||||
/// This method creates <see cref="ChatClientAgentOptions"/> for the specified <see cref="ProjectsAgentVersion"/> and the provided tools.
|
||||
/// </summary>
|
||||
/// <param name="agentVersion">The agent version.</param>
|
||||
/// <param name="chatOptions">The <see cref="ChatOptions"/> to use when interacting with the agent.</param>
|
||||
@@ -334,12 +334,12 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// This method rebuilds the agent options from the agent definition returned by the version and combine with the in-proc tools when provided
|
||||
/// this ensures that all required tools are provided and the definition of the agent options are consistent with the agent definition coming from the server.
|
||||
/// </remarks>
|
||||
private static ChatClientAgentOptions CreateChatClientAgentOptions(AgentVersion agentVersion, ChatOptions? chatOptions, bool requireInvocableTools)
|
||||
private static ChatClientAgentOptions CreateChatClientAgentOptions(ProjectsAgentVersion agentVersion, ChatOptions? chatOptions, bool requireInvocableTools)
|
||||
{
|
||||
var agentDefinition = agentVersion.Definition;
|
||||
|
||||
List<AITool>? agentTools = null;
|
||||
if (agentDefinition is PromptAgentDefinition { Tools: { Count: > 0 } definitionTools })
|
||||
if (agentDefinition is DeclarativeAgentDefinition { Tools: { Count: > 0 } definitionTools })
|
||||
{
|
||||
// Check if no tools were provided while the agent definition requires in-proc tools.
|
||||
if (requireInvocableTools && chatOptions?.Tools is not { Count: > 0 } && definitionTools.Any(t => t is FunctionTool))
|
||||
@@ -395,7 +395,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
Description = agentVersion.Description,
|
||||
};
|
||||
|
||||
if (agentDefinition is PromptAgentDefinition promptAgentDefinition)
|
||||
if (agentDefinition is DeclarativeAgentDefinition promptAgentDefinition)
|
||||
{
|
||||
agentOptions.ChatOptions ??= chatOptions?.Clone() ?? new();
|
||||
agentOptions.ChatOptions.Instructions = promptAgentDefinition.Instructions;
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace Microsoft.Agents.AI.Foundry;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class wraps <see cref="AgentTool"/> (Azure.AI.Projects.OpenAI) and <see cref="ResponseTool"/> (OpenAI SDK) factory methods,
|
||||
/// This class wraps <see cref="ProjectsAgentTool"/> (Azure.AI.Projects.Agents) and <see cref="ResponseTool"/> (OpenAI SDK) factory methods,
|
||||
/// returning <see cref="AITool"/> directly — eliminating the need for manual casting and <c>.AsAITool()</c> calls.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Instead of writing:
|
||||
/// <c>((ResponseTool)AgentTool.CreateOpenApiTool(definition)).AsAITool()</c>
|
||||
/// <c>((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(definition)).AsAITool()</c>
|
||||
/// You can write:
|
||||
/// <c>FoundryAITool.CreateOpenApiTool(definition)</c>
|
||||
/// </para>
|
||||
@@ -37,7 +37,7 @@ public static class FoundryAITool
|
||||
/// <returns>An <see cref="AITool"/> wrapping the provided response tool.</returns>
|
||||
public static AITool FromResponseTool(ResponseTool responseTool) => responseTool.AsAITool();
|
||||
|
||||
// --- Azure.AI.Projects.OpenAI AgentTool factories ---
|
||||
// --- Azure.AI.Projects.OpenAI ProjectsAgentTool factories ---
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for OpenAPI tool invocations.
|
||||
@@ -45,7 +45,7 @@ public static class FoundryAITool
|
||||
/// <param name="definition">The OpenAPI function definition specifying the API endpoint, schema, and authentication.</param>
|
||||
/// <returns>An <see cref="AITool"/> that calls the specified OpenAPI endpoint.</returns>
|
||||
public static AITool CreateOpenApiTool(OpenApiFunctionDefinition definition)
|
||||
=> ((ResponseTool)AgentTool.CreateOpenApiTool(definition)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(definition)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Bing Grounding search.
|
||||
@@ -53,7 +53,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The Bing Grounding search configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Bing Grounding search.</returns>
|
||||
public static AITool CreateBingGroundingTool(BingGroundingSearchToolOptions options)
|
||||
=> ((ResponseTool)AgentTool.CreateBingGroundingTool(options)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBingGroundingTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Bing Custom Search.
|
||||
@@ -61,7 +61,7 @@ public static class FoundryAITool
|
||||
/// <param name="parameters">The Bing Custom Search configuration parameters.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Bing Custom Search.</returns>
|
||||
public static AITool CreateBingCustomSearchTool(BingCustomSearchToolOptions parameters)
|
||||
=> ((ResponseTool)AgentTool.CreateBingCustomSearchTool(parameters)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBingCustomSearchTool(parameters)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Microsoft Fabric data agent.
|
||||
@@ -69,7 +69,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The Fabric data agent configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Microsoft Fabric.</returns>
|
||||
public static AITool CreateMicrosoftFabricTool(FabricDataAgentToolOptions options)
|
||||
=> ((ResponseTool)AgentTool.CreateMicrosoftFabricTool(options)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateMicrosoftFabricTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for SharePoint grounding.
|
||||
@@ -77,7 +77,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The SharePoint grounding configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for SharePoint grounding.</returns>
|
||||
public static AITool CreateSharepointTool(SharePointGroundingToolOptions options)
|
||||
=> ((ResponseTool)AgentTool.CreateSharepointTool(options)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateSharepointTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Azure AI Search.
|
||||
@@ -85,7 +85,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">Optional Azure AI Search configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Azure AI Search.</returns>
|
||||
public static AITool CreateAzureAISearchTool(AzureAISearchToolOptions? options = null)
|
||||
=> ((ResponseTool)AgentTool.CreateAzureAISearchTool(options)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateAzureAISearchTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for browser automation.
|
||||
@@ -93,7 +93,7 @@ public static class FoundryAITool
|
||||
/// <param name="parameters">The browser automation configuration parameters.</param>
|
||||
/// <returns>An <see cref="AITool"/> for browser automation.</returns>
|
||||
public static AITool CreateBrowserAutomationTool(BrowserAutomationToolOptions parameters)
|
||||
=> ((ResponseTool)AgentTool.CreateBrowserAutomationTool(parameters)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBrowserAutomationTool(parameters)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for structured output capture.
|
||||
@@ -101,7 +101,7 @@ public static class FoundryAITool
|
||||
/// <param name="outputs">The structured output definition.</param>
|
||||
/// <returns>An <see cref="AITool"/> for structured output capture.</returns>
|
||||
public static AITool CreateStructuredOutputsTool(StructuredOutputDefinition outputs)
|
||||
=> ((ResponseTool)AgentTool.CreateStructuredOutputsTool(outputs)).AsAITool();
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateStructuredOutputsTool(outputs)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Agent-to-Agent (A2A) communication.
|
||||
@@ -110,7 +110,7 @@ public static class FoundryAITool
|
||||
/// <param name="agentCardPath">Optional path to the agent card.</param>
|
||||
/// <returns>An <see cref="AITool"/> for A2A communication.</returns>
|
||||
public static AITool CreateA2ATool(Uri baseUri, string? agentCardPath = null)
|
||||
=> AgentTool.CreateA2ATool(baseUri, agentCardPath).AsAITool();
|
||||
=> ProjectsAgentTool.CreateA2ATool(baseUri, agentCardPath).AsAITool();
|
||||
|
||||
// --- OpenAI SDK ResponseTool factories ---
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Compliance.Redaction;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.ClientModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
|
||||
namespace Microsoft.Agents.AI.Foundry;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
<NoWarn>$(NoWarn);OPENAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -2,106 +2,36 @@
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
|
||||
@@ -1,433 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ClientModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.DiagnosticIds;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace OpenAI.Assistants;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for OpenAI <see cref="AssistantClient"/>
|
||||
/// to simplify the creation of AI agents that work with OpenAI services.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These extensions bridge the gap between OpenAI SDK client objects and the Microsoft Agent Framework,
|
||||
/// allowing developers to easily create AI agents that leverage OpenAI's chat completion and response services.
|
||||
/// The methods handle the conversion from OpenAI clients to <see cref="IChatClient"/> instances and then wrap them
|
||||
/// in <see cref="ChatClientAgent"/> objects that implement the <see cref="AIAgent"/> interface.
|
||||
/// </remarks>
|
||||
[Experimental(DiagnosticIds.Experiments.AIOpenAIAssistants)]
|
||||
public static class OpenAIAssistantClientExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from a <see cref="ClientResult{Assistant}"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantClientResult">The client result containing the assistant.</param>
|
||||
/// <param name="chatOptions">Optional chat options.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
ClientResult<Assistant> assistantClientResult,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantClientResult is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClientResult));
|
||||
}
|
||||
|
||||
return assistantClient.AsAIAgent(assistantClientResult.Value, chatOptions, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from an <see cref="Assistant"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantMetadata">The assistant metadata.</param>
|
||||
/// <param name="chatOptions">Optional chat options.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
Assistant assistantMetadata,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantMetadata is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantMetadata));
|
||||
}
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
|
||||
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(assistantMetadata.Instructions) && chatOptions?.Instructions is null)
|
||||
{
|
||||
chatOptions ??= new ChatOptions();
|
||||
chatOptions.Instructions = assistantMetadata.Instructions;
|
||||
}
|
||||
|
||||
return new ChatClientAgent(chatClient, options: new()
|
||||
{
|
||||
Id = assistantMetadata.Id,
|
||||
Name = assistantMetadata.Name,
|
||||
Description = assistantMetadata.Description,
|
||||
ChatOptions = chatOptions
|
||||
}, services: services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AssistantClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The <see cref="AssistantClient"/> to create the <see cref="ChatClientAgent"/> with.</param>
|
||||
/// <param name="agentId"> The ID of the server side agent to create a <see cref="ChatClientAgent"/> for.</param>
|
||||
/// <param name="chatOptions">Options that should apply to all runs of the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant agent.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||
this AssistantClient assistantClient,
|
||||
string agentId,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(agentId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
|
||||
}
|
||||
|
||||
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
|
||||
return assistantClient.AsAIAgent(assistantResponse, chatOptions, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from a <see cref="ClientResult{Assistant}"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantClientResult">The client result containing the assistant.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantClientResult"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
ClientResult<Assistant> assistantClientResult,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantClientResult is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClientResult));
|
||||
}
|
||||
|
||||
return assistantClient.AsAIAgent(assistantClientResult.Value, options, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from an <see cref="Assistant"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantMetadata">The assistant metadata.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantMetadata"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
Assistant assistantMetadata,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantMetadata is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantMetadata));
|
||||
}
|
||||
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (options is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
|
||||
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ChatOptions?.Instructions) && !string.IsNullOrWhiteSpace(assistantMetadata.Instructions))
|
||||
{
|
||||
options.ChatOptions ??= new ChatOptions();
|
||||
options.ChatOptions.Instructions = assistantMetadata.Instructions;
|
||||
}
|
||||
|
||||
var mergedOptions = new ChatClientAgentOptions()
|
||||
{
|
||||
Id = assistantMetadata.Id,
|
||||
Name = options.Name ?? assistantMetadata.Name,
|
||||
Description = options.Description ?? assistantMetadata.Description,
|
||||
ChatOptions = options.ChatOptions,
|
||||
AIContextProviders = options.AIContextProviders,
|
||||
ChatHistoryProvider = options.ChatHistoryProvider,
|
||||
UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs
|
||||
};
|
||||
|
||||
return new ChatClientAgent(chatClient, mergedOptions, services: services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AssistantClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The <see cref="AssistantClient"/> to create the <see cref="ChatClientAgent"/> with.</param>
|
||||
/// <param name="agentId"> The ID of the server side agent to create a <see cref="ChatClientAgent"/> for.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant agent.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="agentId"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||
this AssistantClient assistantClient,
|
||||
string agentId,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(agentId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
|
||||
}
|
||||
|
||||
if (options is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
|
||||
return assistantClient.AsAIAgent(assistantResponse, options, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AI agent from an <see cref="AssistantClient"/> using the OpenAI Assistant API.
|
||||
/// </summary>
|
||||
/// <param name="client">The OpenAI <see cref="AssistantClient" /> to use for the agent.</param>
|
||||
/// <param name="model">The model identifier to use (e.g., "gpt-4").</param>
|
||||
/// <param name="instructions">Optional system instructions that define the agent's behavior and personality.</param>
|
||||
/// <param name="name">Optional name for the agent for identification purposes.</param>
|
||||
/// <param name="description">Optional description of the agent's capabilities and purpose.</param>
|
||||
/// <param name="tools">Optional collection of AI tools that the agent can use during conversations.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="ChatClientAgent"/> instance backed by the OpenAI Assistant service.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="client"/> or <paramref name="model"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this AssistantClient client,
|
||||
string model,
|
||||
string? instructions = null,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
ILoggerFactory? loggerFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await client.CreateAIAgentAsync(model,
|
||||
new ChatClientAgentOptions()
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
ChatOptions = tools is null && string.IsNullOrWhiteSpace(instructions) ? null : new ChatOptions()
|
||||
{
|
||||
Tools = tools,
|
||||
Instructions = instructions,
|
||||
}
|
||||
},
|
||||
clientFactory,
|
||||
loggerFactory,
|
||||
services,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AI agent from an <see cref="AssistantClient"/> using the OpenAI Assistant API.
|
||||
/// </summary>
|
||||
/// <param name="client">The OpenAI <see cref="AssistantClient" /> to use for the agent.</param>
|
||||
/// <param name="model">The model identifier to use (e.g., "gpt-4").</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="ChatClientAgent"/> instance backed by the OpenAI Assistant service.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="client"/> or <paramref name="model"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this AssistantClient client,
|
||||
string model,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
ILoggerFactory? loggerFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(client);
|
||||
Throw.IfNull(model);
|
||||
Throw.IfNull(options);
|
||||
|
||||
var assistantOptions = new AssistantCreationOptions()
|
||||
{
|
||||
Name = options.Name,
|
||||
Description = options.Description,
|
||||
Instructions = options.ChatOptions?.Instructions,
|
||||
};
|
||||
|
||||
// Convert AITools to ToolDefinitions and ToolResources
|
||||
var toolDefinitionsAndResources = ConvertAIToolsToToolDefinitions(options.ChatOptions?.Tools);
|
||||
if (toolDefinitionsAndResources.ToolDefinitions is { Count: > 0 } toolDefinitions)
|
||||
{
|
||||
toolDefinitions.ForEach(x => assistantOptions.Tools.Add(x));
|
||||
}
|
||||
if (toolDefinitionsAndResources.ToolResources is not null)
|
||||
{
|
||||
assistantOptions.ToolResources = toolDefinitionsAndResources.ToolResources;
|
||||
}
|
||||
|
||||
// Create the assistant in the assistant service.
|
||||
var assistantCreateResult = await client.CreateAssistantAsync(model, assistantOptions, cancellationToken).ConfigureAwait(false);
|
||||
var assistantId = assistantCreateResult.Value.Id;
|
||||
|
||||
// Build the local agent object.
|
||||
var chatClient = client.AsIChatClient(assistantId);
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
var agentOptions = options.Clone();
|
||||
agentOptions.Id = assistantId;
|
||||
options.ChatOptions ??= new ChatOptions();
|
||||
options.ChatOptions!.Tools = toolDefinitionsAndResources.FunctionToolsAndOtherTools;
|
||||
|
||||
return new ChatClientAgent(chatClient, agentOptions, loggerFactory, services);
|
||||
}
|
||||
|
||||
private static (List<ToolDefinition>? ToolDefinitions, ToolResources? ToolResources, List<AITool>? FunctionToolsAndOtherTools) ConvertAIToolsToToolDefinitions(IList<AITool>? tools)
|
||||
{
|
||||
List<ToolDefinition>? toolDefinitions = null;
|
||||
ToolResources? toolResources = null;
|
||||
List<AITool>? functionToolsAndOtherTools = null;
|
||||
|
||||
if (tools is not null)
|
||||
{
|
||||
foreach (AITool tool in tools)
|
||||
{
|
||||
switch (tool)
|
||||
{
|
||||
case HostedCodeInterpreterTool codeTool:
|
||||
|
||||
toolDefinitions ??= [];
|
||||
toolDefinitions.Add(new CodeInterpreterToolDefinition());
|
||||
|
||||
if (codeTool.Inputs is { Count: > 0 })
|
||||
{
|
||||
foreach (var input in codeTool.Inputs)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HostedFileContent hostedFile:
|
||||
// If the input is a HostedFileContent, we can use its ID directly.
|
||||
toolResources ??= new();
|
||||
toolResources.CodeInterpreter ??= new();
|
||||
toolResources.CodeInterpreter.FileIds.Add(hostedFile.FileId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HostedFileSearchTool fileSearchTool:
|
||||
toolDefinitions ??= [];
|
||||
toolDefinitions.Add(new FileSearchToolDefinition
|
||||
{
|
||||
MaxResults = fileSearchTool.MaximumResultCount,
|
||||
});
|
||||
|
||||
if (fileSearchTool.Inputs is { Count: > 0 })
|
||||
{
|
||||
foreach (var input in fileSearchTool.Inputs)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HostedVectorStoreContent hostedVectorStore:
|
||||
toolResources ??= new();
|
||||
toolResources.FileSearch ??= new();
|
||||
toolResources.FileSearch.VectorStoreIds.Add(hostedVectorStore.VectorStoreId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
functionToolsAndOtherTools ??= [];
|
||||
functionToolsAndOtherTools.Add(tool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (toolDefinitions, toolResources, functionToolsAndOtherTools);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative;
|
||||
/// <param name="projectCredentials">The credentials used to authenticate with the Foundry project. This must be a valid instance of <see cref="TokenCredential"/>.</param>
|
||||
public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential projectCredentials) : ResponseAgentProvider
|
||||
{
|
||||
private readonly Dictionary<string, AgentVersion> _versionCache = [];
|
||||
private readonly Dictionary<string, ProjectsAgentVersion> _versionCache = [];
|
||||
private readonly Dictionary<string, AIAgent> _agentCache = [];
|
||||
|
||||
private AIProjectClient? _agentClient;
|
||||
@@ -99,7 +99,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
IDictionary<string, object?>? inputArguments,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
AgentVersion agentVersionResult = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
|
||||
ProjectsAgentVersion agentVersionResult = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
|
||||
AIAgent agent = await this.GetAgentAsync(agentVersionResult, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
ChatOptions chatOptions =
|
||||
@@ -133,10 +133,10 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AgentVersion> QueryAgentAsync(string agentName, string? agentVersion, CancellationToken cancellationToken = default)
|
||||
private async Task<ProjectsAgentVersion> QueryAgentAsync(string agentName, string? agentVersion, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string agentKey = $"{agentName}:{agentVersion}";
|
||||
if (this._versionCache.TryGetValue(agentKey, out AgentVersion? targetAgent))
|
||||
if (this._versionCache.TryGetValue(agentKey, out ProjectsAgentVersion? targetAgent))
|
||||
{
|
||||
return targetAgent;
|
||||
}
|
||||
@@ -145,8 +145,8 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
|
||||
if (string.IsNullOrEmpty(agentVersion))
|
||||
{
|
||||
AgentRecord agentRecord =
|
||||
await client.Agents.GetAgentAsync(
|
||||
ProjectsAgentRecord agentRecord =
|
||||
await client.AgentAdministrationClient.GetAgentAsync(
|
||||
agentName,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -155,7 +155,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
else
|
||||
{
|
||||
targetAgent =
|
||||
await client.Agents.GetAgentVersionAsync(
|
||||
await client.AgentAdministrationClient.GetAgentVersionAsync(
|
||||
agentName,
|
||||
agentVersion,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
@@ -166,7 +166,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
return targetAgent;
|
||||
}
|
||||
|
||||
private async Task<AIAgent> GetAgentAsync(AgentVersion agentVersion, CancellationToken cancellationToken = default)
|
||||
private async Task<AIAgent> GetAgentAsync(ProjectsAgentVersion agentVersion, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this._agentCache.TryGetValue(agentVersion.Id, out AIAgent? agent))
|
||||
{
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(RepoRoot)/dotnet/nuget/nuget-package.props" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Agents.AI.Workflows.Specialized;
|
||||
@@ -154,6 +155,7 @@ public static partial class AgentWorkflowBuilder
|
||||
/// The <see cref="AIAgent"/> must be capable of understanding those <see cref="AgentRunOptions"/> provided. If the agent
|
||||
/// ignores the tools or is otherwise unable to advertize them to the underlying provider, handoffs will not occur.
|
||||
/// </remarks>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public static HandoffWorkflowBuilder CreateHandoffBuilderWith(AIAgent initialAgent)
|
||||
{
|
||||
Throw.IfNull(initialAgent);
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
</Suppressions>
|
||||
@@ -23,7 +23,8 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
private readonly CancellationTokenSource _runLoopCancellation;
|
||||
private readonly bool _disableRunLoop;
|
||||
private Task? _runLoopTask;
|
||||
private RunStatus _runStatus = RunStatus.NotStarted;
|
||||
private volatile RunStatus _runStatus = RunStatus.NotStarted;
|
||||
|
||||
private int _completionEpoch; // Tracks which completion signal belongs to which consumer iteration
|
||||
|
||||
public StreamingRunEventStream(ISuperStepRunner stepRunner, bool disableRunLoop = false)
|
||||
@@ -127,7 +128,7 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
|
||||
// Wait for next input from the consumer
|
||||
// Works for both Idle (no work) and PendingRequests (waiting for responses)
|
||||
await this._inputWaiter.WaitForInputAsync(TimeSpan.FromSeconds(1), linkedSource.Token).ConfigureAwait(false);
|
||||
await this._inputWaiter.WaitForInputAsync(linkedSource.Token).ConfigureAwait(false);
|
||||
|
||||
// When signaled, resume running
|
||||
this._runStatus = RunStatus.Running;
|
||||
@@ -209,7 +210,10 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Get the current epoch - we'll only respond to completion signals from this epoch or later
|
||||
int myEpoch = Volatile.Read(ref this._completionEpoch) + 1;
|
||||
int currentEpoch = Volatile.Read(ref this._completionEpoch);
|
||||
|
||||
bool expectingFreshWork = this._stepRunner.HasUnprocessedMessages || this._runStatus == RunStatus.Running;
|
||||
int myEpoch = expectingFreshWork ? currentEpoch + 1 : currentEpoch;
|
||||
|
||||
// Use custom async enumerable to avoid exceptions on cancellation.
|
||||
NonThrowingChannelReaderAsyncEnumerable<WorkflowEvent> eventStream = new(this._eventChannel.Reader);
|
||||
|
||||
+10
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Specialized;
|
||||
using Microsoft.Extensions.AI;
|
||||
@@ -9,13 +10,21 @@ using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows;
|
||||
|
||||
internal static class DiagnosticConstants
|
||||
{
|
||||
public const string ExperimentalFeatureDiagnostic = "MAAIW001";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Prefer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed in a future release before GA.")]
|
||||
#pragma warning disable MAAIW001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||
public sealed class HandoffsWorkflowBuilder(AIAgent initialAgent) : HandoffWorkflowBuilderCore<HandoffsWorkflowBuilder>(initialAgent)
|
||||
#pragma warning restore MAAIW001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public sealed class HandoffWorkflowBuilder(AIAgent initialAgent) : HandoffWorkflowBuilderCore<HandoffWorkflowBuilder>(initialAgent)
|
||||
{
|
||||
}
|
||||
@@ -23,6 +32,7 @@ public sealed class HandoffWorkflowBuilder(AIAgent initialAgent) : HandoffWorkfl
|
||||
/// <summary>
|
||||
/// Provides a builder for specifying the handoff relationships between agents and building the resulting workflow.
|
||||
/// </summary>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public class HandoffWorkflowBuilderCore<TBuilder> where TBuilder : HandoffWorkflowBuilderCore<TBuilder>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -1,13 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
<NoWarn>$(NoWarn);MEAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
<InjectIsExternalInitOnLegacy>true</InjectIsExternalInitOnLegacy>
|
||||
<InjectExperimentalAttributeOnLegacy>true</InjectExperimentalAttributeOnLegacy>
|
||||
<InjectTrimAttributesOnLegacy>true</InjectTrimAttributesOnLegacy>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
@@ -31,6 +32,7 @@ internal sealed class HandoffAgentExecutorOptions
|
||||
public HandoffToolCallFilteringBehavior ToolCallFilteringBehavior { get; set; } = HandoffToolCallFilteringBehavior.HandoffOnly;
|
||||
}
|
||||
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal sealed class HandoffMessagesFilter
|
||||
{
|
||||
private readonly HandoffToolCallFilteringBehavior _filteringBehavior;
|
||||
@@ -40,6 +42,7 @@ internal sealed class HandoffMessagesFilter
|
||||
this._filteringBehavior = filteringBehavior;
|
||||
}
|
||||
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal static bool IsHandoffFunctionName(string name)
|
||||
{
|
||||
return name.StartsWith(HandoffWorkflowBuilder.FunctionPrefix, StringComparison.Ordinal);
|
||||
@@ -164,6 +167,7 @@ internal sealed class HandoffMessagesFilter
|
||||
}
|
||||
|
||||
/// <summary>Executor used to represent an agent in a handoffs workflow, responding to <see cref="HandoffState"/> events.</summary>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal sealed class HandoffAgentExecutor(
|
||||
AIAgent agent,
|
||||
HandoffAgentExecutorOptions options) : Executor<HandoffState, HandoffState>(agent.GetDescriptiveId(), declareCrossRunShareable: true), IResettableExecutor
|
||||
|
||||
@@ -2,71 +2,106 @@
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<IsReleased>true</IsReleased>
|
||||
<NoWarn>$(NoWarn);MEAI001;MAAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ internal static class DiagnosticIds
|
||||
// We use the same IDs so consumers do not need to suppress additional diagnostics
|
||||
// when using the experimental OpenAI APIs.
|
||||
internal const string AIOpenAIResponses = "OPENAI001";
|
||||
internal const string AIOpenAIAssistants = "OPENAI001";
|
||||
|
||||
private const string MEAIExperiments = "MEAI001";
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@ namespace Shared.Foundry;
|
||||
|
||||
internal static class AgentFactory
|
||||
{
|
||||
public static async ValueTask<AgentVersion> CreateAgentAsync(
|
||||
public static async ValueTask<ProjectsAgentVersion> CreateAgentAsync(
|
||||
this AIProjectClient aiProjectClient,
|
||||
string agentName,
|
||||
AgentDefinition agentDefinition,
|
||||
ProjectsAgentDefinition agentDefinition,
|
||||
string agentDescription)
|
||||
{
|
||||
AgentVersionCreationOptions options =
|
||||
ProjectsAgentVersionCreationOptions options =
|
||||
new(agentDefinition)
|
||||
{
|
||||
Description = agentDescription,
|
||||
@@ -29,7 +29,7 @@ internal static class AgentFactory
|
||||
},
|
||||
};
|
||||
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(agentName, options).ConfigureAwait(false);
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(agentName, options).ConfigureAwait(false);
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
try
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for versioned <see cref="FoundryAgent"/> creation via
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// <c>AIProjectClient.AgentAdministrationClient.CreateAgentVersionAsync</c> and <c>AIProjectClient.AsAIAgent(ProjectsAgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentCreateTests
|
||||
{
|
||||
@@ -32,10 +32,10 @@ public class FoundryVersionedAgentCreateTests
|
||||
const string AgentInstructions = "You are an integration test agent";
|
||||
|
||||
// Act.
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions
|
||||
})
|
||||
@@ -53,17 +53,17 @@ public class FoundryVersionedAgentCreateTests
|
||||
Assert.Equal(AgentDescription, agent.Description);
|
||||
Assert.Equal(AgentInstructions, agent.GetService<ChatClientAgent>()!.Instructions);
|
||||
|
||||
var agentRecord = await this._client.Agents.GetAgentAsync(agent.Name);
|
||||
var agentRecord = await this._client.AgentAdministrationClient.GetAgentAsync(agent.Name);
|
||||
Assert.NotNull(agentRecord);
|
||||
Assert.Equal(AgentName, agentRecord.Value.Name);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(agentRecord.Value.GetLatestVersion().Definition);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(agentRecord.Value.GetLatestVersion().Definition);
|
||||
Assert.Equal(AgentDescription, agentRecord.Value.GetLatestVersion().Description);
|
||||
Assert.Equal(AgentInstructions, definition.Instructions);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,15 +95,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
var vectorStoreMetadata = await projectOpenAIClient.GetProjectVectorStoresClient().CreateVectorStoreAsync(options: new() { FileIds = { uploadedAgentFile.Id }, Name = "WordCodeLookup_VectorStore" });
|
||||
|
||||
// Act — create agent version with FileSearch tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreMetadata.Value.Id]) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await projectOpenAIClient.GetProjectVectorStoresClient().DeleteVectorStoreAsync(vectorStoreMetadata.Value.Id);
|
||||
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedAgentFile.Id);
|
||||
File.Delete(searchFilePath);
|
||||
@@ -149,15 +149,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
);
|
||||
|
||||
// Act — create agent version with CodeInterpreter tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateCodeInterpreterTool(new CodeInterpreterToolContainer(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration([uploadedCodeFile.Id]))) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
@@ -171,7 +171,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedCodeFile.Id);
|
||||
File.Delete(codeFilePath);
|
||||
}
|
||||
@@ -252,14 +252,14 @@ public class FoundryVersionedAgentCreateTests
|
||||
Description = "Retrieve information about countries by currency code"
|
||||
};
|
||||
|
||||
var definition = new PromptAgentDefinition(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new DeclarativeAgentDefinition(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { (ResponseTool)AgentTool.CreateOpenApiTool(openApiFunction) }
|
||||
Tools = { (ResponseTool)ProjectsAgentTool.CreateOpenApiTool(openApiFunction) }
|
||||
};
|
||||
|
||||
AgentVersionCreationOptions creationOptions = new(definition);
|
||||
AgentVersion agentVersion = await this._client.Agents.CreateAgentVersionAsync(AgentName, creationOptions);
|
||||
ProjectsAgentVersionCreationOptions creationOptions = new(definition);
|
||||
ProjectsAgentVersion agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(AgentName, creationOptions);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -269,7 +269,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
// Assert the agent was created correctly and retains version metadata.
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal(AgentName, agent.Name);
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
Assert.NotNull(retrievedVersion);
|
||||
|
||||
// Step 3: Call RunAsync to trigger the server-side OpenAPI function.
|
||||
@@ -301,7 +301,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.Agents.DeleteAgentAsync(AgentName);
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(AgentName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,15 +317,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
|
||||
// Create agent version with the function tool registered in the server-side definition,
|
||||
// then wrap with AsAIAgent passing the local AIFunction implementation.
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
};
|
||||
definition.Tools.Add(weatherFunction.AsOpenAIResponseTool());
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new AgentVersionCreationOptions(definition));
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
|
||||
FoundryAgent agent = this._client.AsAIAgent(agentVersion, tools: [weatherFunction]);
|
||||
|
||||
@@ -342,7 +342,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration test fixture that creates versioned Foundry agents via
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and wraps them
|
||||
/// with <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// <c>AIProjectClient.AgentAdministrationClient.CreateAgentVersionAsync</c> and wraps them
|
||||
/// with <c>AIProjectClient.AsAIAgent(ProjectsAgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
@@ -121,7 +121,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
string instructions = "You are a helpful assistant.",
|
||||
IList<AITool>? aiTools = null)
|
||||
{
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = instructions
|
||||
};
|
||||
@@ -139,9 +139,9 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
}
|
||||
}
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName(name),
|
||||
new AgentVersionCreationOptions(definition));
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
|
||||
return this._client.AsAIAgent(agentVersion, tools: aiTools).GetService<ChatClientAgent>()!;
|
||||
}
|
||||
@@ -150,15 +150,15 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
|
||||
var definition = new PromptAgentDefinition(
|
||||
var definition = new DeclarativeAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
new ProjectsAgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
|
||||
@@ -169,7 +169,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
$"{baseName}-{Guid.NewGuid().ToString("N").Substring(0, 8)}";
|
||||
|
||||
public Task DeleteAgentAsync(ChatClientAgent agent) =>
|
||||
this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
|
||||
public async Task DeleteSessionAsync(AgentSession session)
|
||||
{
|
||||
@@ -201,7 +201,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
|
||||
if (this._client is not null && this._agent is not null)
|
||||
{
|
||||
return new ValueTask(this._client.Agents.DeleteAgentAsync(this._agent.Name));
|
||||
return new ValueTask(this._client.AgentAdministrationClient.DeleteAgentAsync(this._agent.Name));
|
||||
}
|
||||
|
||||
return default;
|
||||
@@ -211,10 +211,10 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName("HelpfulAssistant"),
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = "You are a helpful assistant."
|
||||
}));
|
||||
@@ -227,15 +227,15 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
|
||||
var definition = new PromptAgentDefinition(
|
||||
var definition = new DeclarativeAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
new ProjectsAgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
this._agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
|
||||
+129
-129
@@ -187,7 +187,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, AgentRecord) Tests
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentRecord) Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent throws ArgumentNullException when AIProjectClient is null.
|
||||
@@ -197,7 +197,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient? client = null;
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
@@ -217,20 +217,20 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
mockClient.Object.AsAIAgent((AgentRecord)null!));
|
||||
mockClient.Object.AsAIAgent((ProjectsAgentRecord)null!));
|
||||
|
||||
Assert.Equal("agentRecord", exception.ParamName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentRecord creates a valid agent.
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord creates a valid agent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecord_CreatesValidAgent()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -243,14 +243,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentRecord and clientFactory applies the factory.
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord and clientFactory applies the factory.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecord_WithClientFactory_AppliesFactoryCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
TestChatClient? testChatClient = null;
|
||||
|
||||
// Act
|
||||
@@ -267,7 +267,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, AgentVersion) Tests
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentVersion) Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent throws ArgumentNullException when AIProjectClient is null.
|
||||
@@ -277,7 +277,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient? client = null;
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
@@ -297,20 +297,20 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
mockClient.Object.AsAIAgent((AgentVersion)null!));
|
||||
mockClient.Object.AsAIAgent((ProjectsAgentVersion)null!));
|
||||
|
||||
Assert.Equal("agentVersion", exception.ParamName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentVersion creates a valid agent.
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion creates a valid agent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersion_CreatesValidAgent()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -323,14 +323,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentVersion and clientFactory applies the factory.
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion and clientFactory applies the factory.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersion_WithClientFactory_AppliesFactoryCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
TestChatClient? testChatClient = null;
|
||||
|
||||
// Act
|
||||
@@ -353,7 +353,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "test", "test_function", "A test function")
|
||||
@@ -375,7 +375,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act - should not throw even without tools when requireInvocableTools is false
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -439,7 +439,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, AgentRecord) with tools Tests
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentRecord) with tools Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with additional tools when the definition has no tools does not throw and results in an agent with no tools.
|
||||
@@ -449,7 +449,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "test", "test_function", "A test function")
|
||||
@@ -463,9 +463,9 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var chatClient = agent.GetService<IChatClient>();
|
||||
Assert.NotNull(chatClient);
|
||||
var agentVersion = chatClient.GetService<AgentVersion>();
|
||||
var agentVersion = chatClient.GetService<ProjectsAgentVersion>();
|
||||
Assert.NotNull(agentVersion);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(agentVersion.Definition);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(agentVersion.Definition);
|
||||
Assert.Empty(definition.Tools);
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord, tools: null);
|
||||
@@ -502,7 +502,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
var agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Manually add tools to the definition to simulate inline tools
|
||||
if (agentVersion.Definition is PromptAgentDefinition promptDef)
|
||||
if (agentVersion.Definition is DeclarativeAgentDefinition promptDef)
|
||||
{
|
||||
promptDef.Tools.Add(ResponseTool.CreateFunctionTool("inline_tool", BinaryData.FromString("{}"), strictModeEnabled: false));
|
||||
}
|
||||
@@ -513,9 +513,9 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Act & Assert
|
||||
var agent = client.AsAIAgent(agentVersion, tools: [invocableInlineAITool, shouldBeIgnoredTool]);
|
||||
Assert.NotNull(agent);
|
||||
var version = agent.GetService<AgentVersion>();
|
||||
var version = agent.GetService<ProjectsAgentVersion>();
|
||||
Assert.NotNull(version);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(version.Definition);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(version.Definition);
|
||||
Assert.NotEmpty(definition.Tools);
|
||||
Assert.NotNull(GetAgentChatOptions(agent));
|
||||
Assert.NotNull(GetAgentChatOptions(agent)!.Tools);
|
||||
@@ -535,7 +535,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "tool1", "param_tool_1", "First parameter tool"),
|
||||
@@ -550,7 +550,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var chatClient = agent.GetService<IChatClient>();
|
||||
Assert.NotNull(chatClient);
|
||||
var agentVersion = chatClient.GetService<AgentVersion>();
|
||||
var agentVersion = chatClient.GetService<ProjectsAgentVersion>();
|
||||
Assert.NotNull(agentVersion);
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public async Task CreateAIAgentAsync_WithResponseToolsInDefinition_CreatesAgentSuccessfullyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test instructions" };
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test instructions" };
|
||||
|
||||
var fabricToolOptions = new FabricDataAgentToolOptions();
|
||||
fabricToolOptions.ProjectConnections.Add(new ToolProjectConnection("connection-id"));
|
||||
@@ -577,33 +577,33 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Add tools to the definition
|
||||
definition.Tools.Add(ResponseTool.CreateFunctionTool("create_tool", BinaryData.FromString("{}"), strictModeEnabled: false));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBingCustomSearchTool(new BingCustomSearchToolOptions([new BingCustomSearchConfiguration("connection-id", "instance-name")])));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBrowserAutomationTool(new BrowserAutomationToolOptions(new BrowserAutomationToolConnectionParameters("id"))));
|
||||
definition.Tools.Add(AgentTool.CreateA2ATool(new Uri("https://test-uri.microsoft.com")));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBingGroundingTool(new BingGroundingSearchToolOptions([new BingGroundingSearchConfiguration("connection-id")])));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateMicrosoftFabricTool(fabricToolOptions));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateOpenApiTool(new OpenApiFunctionDefinition("name", BinaryData.FromString(OpenAPISpec), new OpenAPIAnonymousAuthenticationDetails())));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateSharepointTool(sharepointOptions));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateStructuredOutputsTool(structuredOutputs));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateAzureAISearchTool(new AzureAISearchToolOptions([new AzureAISearchToolIndex() { IndexName = "name" }])));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBingCustomSearchTool(new BingCustomSearchToolOptions([new BingCustomSearchConfiguration("connection-id", "instance-name")])));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBrowserAutomationTool(new BrowserAutomationToolOptions(new BrowserAutomationToolConnectionParameters("id"))));
|
||||
definition.Tools.Add(ProjectsAgentTool.CreateA2ATool(new Uri("https://test-uri.microsoft.com")));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBingGroundingTool(new BingGroundingSearchToolOptions([new BingGroundingSearchConfiguration("connection-id")])));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateMicrosoftFabricTool(fabricToolOptions));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(new OpenApiFunctionDefinition("name", BinaryData.FromString(OpenAPISpec), new OpenAPIAnonymousAuthenticationDetails())));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateSharepointTool(sharepointOptions));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateStructuredOutputsTool(structuredOutputs));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateAzureAISearchTool(new AzureAISearchToolOptions([new AzureAISearchToolIndex() { IndexName = "name" }])));
|
||||
|
||||
// Generate agent definition response with the tools
|
||||
var definitionResponse = GeneratePromptDefinitionResponse(definition, definition.Tools.Select(t => t.AsAITool()).ToList());
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var agentVersion2 = agent.GetService<AgentVersion>()!;
|
||||
var agentVersion2 = agent.GetService<ProjectsAgentVersion>()!;
|
||||
Assert.NotNull(agentVersion);
|
||||
if (agentVersion2.Definition is PromptAgentDefinition promptDef)
|
||||
if (agentVersion2.Definition is DeclarativeAgentDefinition promptDef)
|
||||
{
|
||||
Assert.NotEmpty(promptDef.Tools);
|
||||
Assert.Equal(10, promptDef.Tools.Count);
|
||||
@@ -624,19 +624,19 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
functionDescription: "Gets the user's name, as used for friendly address."
|
||||
);
|
||||
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definition.Tools.Add(functionTool);
|
||||
|
||||
// Generate response with the declarative function
|
||||
var definitionResponse = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definitionResponse = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definitionResponse.Tools.Add(functionTool);
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentName: "test-agent", agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -652,7 +652,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
using var testClient = CreateTestAgentClientWithHandler();
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
|
||||
// Create a declarative function (not invocable) using AIFunctionFactory.CreateDeclaration
|
||||
using var doc = JsonDocument.Parse("{}");
|
||||
@@ -661,10 +661,10 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Add to definition
|
||||
definition.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -679,7 +679,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public async Task AsAIAgent_WithDeclarativeFunctionInDefinition_AcceptsDeclarativeFunctionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
|
||||
// Create a declarative function (not invocable) using AIFunctionFactory.CreateDeclaration
|
||||
using var doc = JsonDocument.Parse("{}");
|
||||
@@ -689,15 +689,15 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
definition.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
// Generate response with the declarative function
|
||||
var definitionResponse = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definitionResponse = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definitionResponse.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentName: "test-agent", agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -758,7 +758,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
int factoryCallCount = 0;
|
||||
|
||||
// Act
|
||||
@@ -785,7 +785,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent1 = client.AsAIAgent(
|
||||
@@ -904,7 +904,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Arrange
|
||||
var aiProjectClient = new AIProjectClient(new Uri("https://test.openai.azure.com/"), new FakeAuthenticationTokenProvider(), new() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agentVersion = (await aiProjectClient.Agents.CreateAgentVersionAsync("test-agent", new AgentVersionCreationOptions(new PromptAgentDefinition("test-model") { Instructions = "Test instructions" }))).Value;
|
||||
var agentVersion = (await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition("test-model") { Instructions = "Test instructions" }))).Value;
|
||||
|
||||
// Act
|
||||
var agent = aiProjectClient.AsAIAgent(agentVersion);
|
||||
@@ -1043,21 +1043,21 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetService<AgentRecord> Tests
|
||||
#region GetService<ProjectsAgentRecord> Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns AgentRecord for agents created from AgentRecord.
|
||||
/// Verify that GetService returns ProjectsAgentRecord for agents created from ProjectsAgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentRecord_ReturnsAgentRecord()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
var retrievedRecord = agent.GetService<AgentRecord>();
|
||||
var retrievedRecord = agent.GetService<ProjectsAgentRecord>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrievedRecord);
|
||||
@@ -1065,7 +1065,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentRecord when agent is created from AgentReference.
|
||||
/// Verify that GetService returns null for ProjectsAgentRecord when agent is created from AgentReference.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentReference_ReturnsNullForAgentRecord()
|
||||
@@ -1076,7 +1076,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentReference);
|
||||
var retrievedRecord = agent.GetService<AgentRecord>();
|
||||
var retrievedRecord = agent.GetService<ProjectsAgentRecord>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(retrievedRecord);
|
||||
@@ -1084,21 +1084,21 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetService<AgentVersion> Tests
|
||||
#region GetService<ProjectsAgentVersion> Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns AgentVersion for agents created from AgentVersion.
|
||||
/// Verify that GetService returns ProjectsAgentVersion for agents created from ProjectsAgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentVersion_ReturnsAgentVersion()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrievedVersion);
|
||||
@@ -1106,7 +1106,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentVersion when agent is created from AgentReference.
|
||||
/// Verify that GetService returns null for ProjectsAgentVersion when agent is created from AgentReference.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentReference_ReturnsNullForAgentVersion()
|
||||
@@ -1117,7 +1117,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentReference);
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(retrievedVersion);
|
||||
@@ -1128,14 +1128,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
#region ChatClientMetadata Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from AgentRecord.
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from ProjectsAgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithAgentRecord_IsPopulatedCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1147,18 +1147,18 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata.DefaultModelId is set from PromptAgentDefinition model property.
|
||||
/// Verify that ChatClientMetadata.DefaultModelId is set from DeclarativeAgentDefinition model property.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithPromptAgentDefinition_SetsDefaultModelIdFromModel()
|
||||
public void ChatClientMetadata_WithDeclarativeAgentDefinition_SetsDefaultModelIdFromModel()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
var definition = new PromptAgentDefinition("gpt-4-turbo")
|
||||
var definition = new DeclarativeAgentDefinition("gpt-4-turbo")
|
||||
{
|
||||
Instructions = "Test instructions"
|
||||
};
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord(definition);
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord(definition);
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1172,14 +1172,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from AgentVersion.
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from ProjectsAgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithAgentVersion_IsPopulatedCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1188,7 +1188,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Assert
|
||||
Assert.NotNull(metadata);
|
||||
Assert.NotNull(metadata.DefaultModelId);
|
||||
Assert.Equal((agentVersion.Definition as PromptAgentDefinition)!.Model, metadata.DefaultModelId);
|
||||
Assert.Equal((agentVersion.Definition as DeclarativeAgentDefinition)!.Model, metadata.DefaultModelId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1216,14 +1216,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from AgentRecord.
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from ProjectsAgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentRecord_ReturnsAlsoAgentReference()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1235,14 +1235,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from AgentVersion.
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from ProjectsAgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentVersion_ReturnsAlsoAgentReference()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1278,14 +1278,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
#region Empty Version and ID Handling Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentRecord handles empty version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord handles empty version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecordEmptyVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithEmptyVersion();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecordWithEmptyVersion();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecordWithEmptyVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1297,14 +1297,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentVersion handles empty version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion handles empty version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersionEmptyVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithEmptyVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersionWithEmptyVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersionWithEmptyVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1316,14 +1316,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentRecord handles whitespace-only version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord handles whitespace-only version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecordWhitespaceVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithWhitespaceVersion();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecordWithWhitespaceVersion();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecordWithWhitespaceVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1335,14 +1335,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with AgentVersion handles whitespace-only version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion handles whitespace-only version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersionWhitespaceVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithWhitespaceVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersionWithWhitespaceVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersionWithWhitespaceVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1364,11 +1364,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public void AsAIAgent_WithServerHostedTools_AddsToolsToAgentOptions()
|
||||
{
|
||||
// Arrange
|
||||
PromptAgentDefinition definition = new("test-model") { Instructions = "Test" };
|
||||
DeclarativeAgentDefinition definition = new("test-model") { Instructions = "Test" };
|
||||
definition.Tools.Add(new HostedWebSearchTool().GetService<ResponseTool>() ?? new HostedWebSearchTool().AsOpenAIResponseTool());
|
||||
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
AgentVersion agentVersion = ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson(agentDefinition: definition)))!;
|
||||
ProjectsAgentVersion agentVersion = ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson(agentDefinition: definition)))!;
|
||||
|
||||
// Act - no tools provided, but requireInvocableTools is false when no tools param is passed
|
||||
FoundryAgent agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1385,7 +1385,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with fake behavior.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse);
|
||||
}
|
||||
@@ -1395,7 +1395,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// Used for tests that exercise the protocol-method code path (CreateAgentVersion).
|
||||
/// The returned client must be disposed to clean up the underlying HttpClient/handler.
|
||||
/// </summary>
|
||||
private static DisposableTestClient CreateTestAgentClientWithHandler(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
private static DisposableTestClient CreateTestAgentClientWithHandler(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
var responseJson = TestDataUtil.GetAgentVersionResponseJson(agentName, agentDefinitionResponse, instructions, description);
|
||||
|
||||
@@ -1439,59 +1439,59 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentRecord for testing.
|
||||
/// Creates a test ProjectsAgentRecord for testing.
|
||||
/// </summary>
|
||||
private AgentRecord CreateTestAgentRecord(AgentDefinition? agentDefinition = null)
|
||||
private ProjectsAgentRecord CreateTestAgentRecord(ProjectsAgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJson(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJson(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with empty version fields for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClientWithEmptyVersion(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClientWithEmptyVersion(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse, useEmptyVersion: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentRecord with empty version for testing hosted MCP agents.
|
||||
/// Creates a test ProjectsAgentRecord with empty version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private AgentRecord CreateTestAgentRecordWithEmptyVersion(AgentDefinition? agentDefinition = null)
|
||||
private ProjectsAgentRecord CreateTestAgentRecordWithEmptyVersion(ProjectsAgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithEmptyVersion(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithEmptyVersion(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentVersion with empty version for testing hosted MCP agents.
|
||||
/// Creates a test ProjectsAgentVersion with empty version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private AgentVersion CreateTestAgentVersionWithEmptyVersion()
|
||||
private ProjectsAgentVersion CreateTestAgentVersionWithEmptyVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithEmptyVersion()))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithEmptyVersion()))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with whitespace-only version fields for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClientWithWhitespaceVersion(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClientWithWhitespaceVersion(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse, versionMode: VersionMode.Whitespace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentRecord with whitespace-only version for testing hosted MCP agents.
|
||||
/// Creates a test ProjectsAgentRecord with whitespace-only version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private AgentRecord CreateTestAgentRecordWithWhitespaceVersion(AgentDefinition? agentDefinition = null)
|
||||
private ProjectsAgentRecord CreateTestAgentRecordWithWhitespaceVersion(ProjectsAgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithWhitespaceVersion(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithWhitespaceVersion(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentVersion with whitespace-only version for testing hosted MCP agents.
|
||||
/// Creates a test ProjectsAgentVersion with whitespace-only version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private AgentVersion CreateTestAgentVersionWithWhitespaceVersion()
|
||||
private ProjectsAgentVersion CreateTestAgentVersionWithWhitespaceVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithWhitespaceVersion()))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithWhitespaceVersion()))!;
|
||||
}
|
||||
|
||||
private const string OpenAPISpec = """
|
||||
@@ -1525,11 +1525,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AgentVersion for testing.
|
||||
/// Creates a test ProjectsAgentVersion for testing.
|
||||
/// </summary>
|
||||
private AgentVersion CreateTestAgentVersion()
|
||||
private ProjectsAgentVersion CreateTestAgentVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson()))!;
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson()))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1547,11 +1547,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// </summary>
|
||||
private sealed class FakeAgentClient : AIProjectClient
|
||||
{
|
||||
public FakeAgentClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null, bool useEmptyVersion = false, VersionMode versionMode = VersionMode.Normal)
|
||||
public FakeAgentClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null, bool useEmptyVersion = false, VersionMode versionMode = VersionMode.Normal)
|
||||
{
|
||||
// Handle backward compatibility with bool parameter
|
||||
var effectiveVersionMode = useEmptyVersion ? VersionMode.Empty : versionMode;
|
||||
this.Agents = new FakeAgentsClient(agentName, instructions, description, agentDefinitionResponse, effectiveVersionMode);
|
||||
this.AgentAdministrationClient = new FakeAgentsClient(agentName, instructions, description, agentDefinitionResponse, effectiveVersionMode);
|
||||
}
|
||||
|
||||
public override ClientConnection GetConnection(string connectionId)
|
||||
@@ -1559,17 +1559,17 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
return new ClientConnection("fake-connection-id", "http://localhost", ClientPipeline.Create(), CredentialKind.None);
|
||||
}
|
||||
|
||||
public override AgentsClient Agents { get; }
|
||||
public override AgentAdministrationClient AgentAdministrationClient { get; }
|
||||
|
||||
private sealed class FakeAgentsClient : AgentsClient
|
||||
private sealed class FakeAgentsClient : AgentAdministrationClient
|
||||
{
|
||||
private readonly string? _agentName;
|
||||
private readonly string? _instructions;
|
||||
private readonly string? _description;
|
||||
private readonly AgentDefinition? _agentDefinition;
|
||||
private readonly ProjectsAgentDefinition? _agentDefinition;
|
||||
private readonly VersionMode _versionMode;
|
||||
|
||||
public FakeAgentsClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null, VersionMode versionMode = VersionMode.Normal)
|
||||
public FakeAgentsClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null, VersionMode versionMode = VersionMode.Normal)
|
||||
{
|
||||
this._agentName = agentName;
|
||||
this._instructions = instructions;
|
||||
@@ -1601,44 +1601,44 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public override ClientResult GetAgent(string agentName, RequestOptions options)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson)));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson)));
|
||||
}
|
||||
|
||||
public override ClientResult<AgentRecord> GetAgent(string agentName, CancellationToken cancellationToken = default)
|
||||
public override ClientResult<ProjectsAgentRecord> GetAgent(string agentName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
}
|
||||
|
||||
public override Task<ClientResult> GetAgentAsync(string agentName, RequestOptions options)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return Task.FromResult<ClientResult>(ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson))));
|
||||
return Task.FromResult<ClientResult>(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson))));
|
||||
}
|
||||
|
||||
public override Task<ClientResult<AgentRecord>> GetAgentAsync(string agentName, CancellationToken cancellationToken = default)
|
||||
public override Task<ClientResult<ProjectsAgentRecord>> GetAgentAsync(string agentName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
}
|
||||
|
||||
public override ClientResult<AgentVersion> CreateAgentVersion(string agentName, AgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
public override ClientResult<ProjectsAgentVersion> CreateAgentVersion(string agentName, ProjectsAgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentVersionResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
}
|
||||
|
||||
public override Task<ClientResult<AgentVersion>> CreateAgentVersionAsync(string agentName, AgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
public override Task<ClientResult<ProjectsAgentVersion>> CreateAgentVersionAsync(string agentName, ProjectsAgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentVersionResponseJson();
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PromptAgentDefinition GeneratePromptDefinitionResponse(PromptAgentDefinition inputDefinition, List<AITool>? tools)
|
||||
private static DeclarativeAgentDefinition GeneratePromptDefinitionResponse(DeclarativeAgentDefinition inputDefinition, List<AITool>? tools)
|
||||
{
|
||||
var definitionResponse = new PromptAgentDefinition(inputDefinition.Model) { Instructions = inputDefinition.Instructions };
|
||||
var definitionResponse = new DeclarativeAgentDefinition(inputDefinition.Model) { Instructions = inputDefinition.Instructions };
|
||||
if (tools is not null)
|
||||
{
|
||||
foreach (var tool in tools)
|
||||
|
||||
@@ -29,7 +29,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -42,7 +42,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -55,7 +55,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with empty version and ID fields for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJsonWithEmptyVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJsonWithEmptyVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -71,7 +71,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with empty version and ID fields in the latest version for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJsonWithEmptyVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJsonWithEmptyVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -87,7 +87,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with whitespace-only version and ID fields for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJsonWithWhitespaceVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJsonWithWhitespaceVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -103,7 +103,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with whitespace-only version and ID fields in the latest version for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJsonWithWhitespaceVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJsonWithWhitespaceVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -119,7 +119,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the OpenAI default response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetOpenAIDefaultResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetOpenAIDefaultResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_openAIDefaultResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -138,7 +138,7 @@ internal static class TestDataUtil
|
||||
return json;
|
||||
}
|
||||
|
||||
private static string ApplyAgentDefinition(string json, AgentDefinition? definition)
|
||||
private static string ApplyAgentDefinition(string json, ProjectsAgentDefinition? definition)
|
||||
{
|
||||
return (definition is not null)
|
||||
? json.Replace(AgentDefinitionPlaceholder, ModelReaderWriter.Write(definition).ToString())
|
||||
|
||||
-1013
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -35,13 +35,13 @@ internal abstract class AgentProvider(IConfiguration configuration)
|
||||
{
|
||||
Uri foundryEndpoint = new(this.GetSetting(TestSettings.AzureAIProjectEndpoint));
|
||||
|
||||
await foreach (AgentVersion agent in this.CreateAgentsAsync(foundryEndpoint))
|
||||
await foreach (ProjectsAgentVersion agent in this.CreateAgentsAsync(foundryEndpoint))
|
||||
{
|
||||
Console.WriteLine($"Created agent: {agent.Name}:{agent.Version}");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint);
|
||||
protected abstract IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint);
|
||||
|
||||
protected string GetSetting(string settingName) =>
|
||||
configuration[settingName] ??
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class FunctionToolAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
MenuPlugin menuPlugin = new();
|
||||
AIFunction[] functions =
|
||||
@@ -33,9 +33,9 @@ internal sealed class FunctionToolAgentProvider(IConfiguration configuration) :
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefineMenuAgent(AIFunction[] functions)
|
||||
private DeclarativeAgentDefinition DefineMenuAgent(AIFunction[] functions)
|
||||
{
|
||||
PromptAgentDefinition agentDefinition =
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+5
-5
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class MarketingAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -35,7 +35,7 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
agentDescription: "Editor agent for Marketing workflow");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefineAnalystAgent() =>
|
||||
private DeclarativeAgentDefinition DefineAnalystAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -47,13 +47,13 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private PromptAgentDefinition DefineWriterAgent() =>
|
||||
private DeclarativeAgentDefinition DefineWriterAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -64,7 +64,7 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
"""
|
||||
};
|
||||
|
||||
private PromptAgentDefinition DefineEditorAgent() =>
|
||||
private DeclarativeAgentDefinition DefineEditorAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class MathChatAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed class MathChatAgentProvider(IConfiguration configuration) : Agen
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefineStudentAgent() =>
|
||||
private DeclarativeAgentDefinition DefineStudentAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -41,7 +41,7 @@ internal sealed class MathChatAgentProvider(IConfiguration configuration) : Agen
|
||||
"""
|
||||
};
|
||||
|
||||
private PromptAgentDefinition DefineTeacherAgent() =>
|
||||
private DeclarativeAgentDefinition DefineTeacherAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class PoemAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -23,7 +23,7 @@ internal sealed class PoemAgentProvider(IConfiguration configuration) : AgentPro
|
||||
agentDescription: "Authors original poems");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefinePoemAgent() =>
|
||||
private DeclarativeAgentDefinition DefinePoemAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class TestAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -23,6 +23,6 @@ internal sealed class TestAgentProvider(IConfiguration configuration) : AgentPro
|
||||
agentDescription: "Basic agent");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefineMenuAgent() =>
|
||||
private DeclarativeAgentDefinition DefineMenuAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName));
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class VisionAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -23,7 +23,7 @@ internal sealed class VisionAgentProvider(IConfiguration configuration) : AgentP
|
||||
agentDescription: "Use computer vision to describe an image or document.");
|
||||
}
|
||||
|
||||
private PromptAgentDefinition DefineVisionAgent() =>
|
||||
private DeclarativeAgentDefinition DefineVisionAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -132,6 +132,53 @@ public class InProcessExecutionTests
|
||||
"both versions should produce the same number of agent events");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This test checks that the logic around waiting for input and halting appropriately works right when the
|
||||
/// workflow runs to halting before the EventStream is watched by the user.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task RunStreamingAsyncWaitToTakeStreamAsync()
|
||||
{
|
||||
// Arrange: Create a simple agent that responds to messages
|
||||
var agent = new SimpleTestAgent("test-agent");
|
||||
var workflow = AgentWorkflowBuilder.BuildSequential(agent);
|
||||
var inputMessage = new ChatMessage(ChatRole.User, "Hello");
|
||||
|
||||
// Act: Execute using streaming version with TurnToken
|
||||
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new List<ChatMessage> { inputMessage });
|
||||
|
||||
// Send TurnToken to actually trigger execution (this is the key step)
|
||||
bool messageSent = await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
|
||||
messageSent.Should().BeTrue("TurnToken should be accepted");
|
||||
|
||||
while (await run.GetStatusAsync() != RunStatus.Idle)
|
||||
{
|
||||
await Task.Delay(200);
|
||||
}
|
||||
|
||||
// Collect events
|
||||
List<WorkflowEvent> events = [];
|
||||
|
||||
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
|
||||
{
|
||||
events.Add(evt);
|
||||
}
|
||||
|
||||
// Assert: The workflow should have executed and produced events
|
||||
RunStatus status = await run.GetStatusAsync();
|
||||
status.Should().Be(RunStatus.Idle, "workflow should complete execution");
|
||||
|
||||
events.Should().NotBeEmpty("workflow should produce events during execution");
|
||||
|
||||
// Check that we have agent execution events
|
||||
var agentEvents = events.OfType<AgentResponseUpdateEvent>().ToList();
|
||||
agentEvents.Should().NotBeEmpty("agent should have executed and produced update events");
|
||||
|
||||
// Check that we have output events
|
||||
var outputEvents = events.OfType<WorkflowOutputEvent>().ToList();
|
||||
outputEvents.Should().NotBeEmpty("workflow should produce output events");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple test agent that echoes back the input message.
|
||||
/// </summary>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<NoWarn>$(NoWarn);MEAI001</NoWarn>
|
||||
<NoWarn>$(NoWarn);MEAI001;MAAIW001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
-268
@@ -1,268 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete - Testing deprecated OpenAI Assistants API extension methods
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using AgentConformance.IntegrationTests.Support;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Assistants;
|
||||
using OpenAI.Files;
|
||||
using OpenAI.VectorStores;
|
||||
using Shared.IntegrationTests;
|
||||
|
||||
namespace OpenAIAssistant.IntegrationTests;
|
||||
|
||||
public class OpenAIAssistantClientExtensionsTests
|
||||
{
|
||||
private const string SkipCodeInterpreterReason = "OpenAI Assistant Code Interpreter intermittently fails in CI";
|
||||
|
||||
private readonly AssistantClient _assistantClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetAssistantClient();
|
||||
private readonly OpenAIFileClient _fileClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetOpenAIFileClient();
|
||||
|
||||
[Theory]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithChatClientAgentOptionsSync")]
|
||||
[InlineData("CreateWithParamsAsync")]
|
||||
public async Task CreateAIAgentAsync_WithAIFunctionTool_InvokesFunctionAsync(string createMechanism)
|
||||
{
|
||||
// Arrange
|
||||
const string AgentInstructions = "You are a helpful weather assistant. Always call the GetWeather function to answer questions about weather.";
|
||||
|
||||
static string GetWeather(string location) => $"The weather in {location} is sunny with a high of 23C.";
|
||||
var weatherFunction = AIFunctionFactory.Create(GetWeather, nameof(GetWeather));
|
||||
|
||||
// Act
|
||||
var agent = createMechanism switch
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = [weatherFunction]
|
||||
}
|
||||
}),
|
||||
"CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = [weatherFunction]
|
||||
}
|
||||
}),
|
||||
"CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
instructions: AgentInstructions,
|
||||
tools: [weatherFunction]),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// Trigger function call.
|
||||
var response = await agent.RunAsync("What is the weather like in Amsterdam?");
|
||||
var text = response.Text;
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Amsterdam", text, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("sunny", text, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("23", text, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await this._assistantClient.DeleteAssistantAsync(agent.Id);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory(Skip = SkipCodeInterpreterReason)]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithChatClientAgentOptionsSync")]
|
||||
[InlineData("CreateWithParamsAsync")]
|
||||
public async Task CreateAIAgentAsync_WithHostedCodeInterpreter_RunsCodeAsync(string createMechanism)
|
||||
{
|
||||
// Arrange
|
||||
const string Instructions = "Use the Code Interpreter Tool to run the uploaded python file and respond only with the secret number.";
|
||||
|
||||
// Create a python file that prints a known value.
|
||||
var codeFilePath = Path.GetTempFileName() + "openai_secret_number.py";
|
||||
File.WriteAllText(
|
||||
path: codeFilePath,
|
||||
contents: "print(\"OPENAI_SECRET=13579\")" // Deterministic output we will look for.
|
||||
);
|
||||
|
||||
// Upload file to OpenAI Assistants file store for use with the Code Interpreter.
|
||||
var uploadResult = await this._fileClient.UploadFileAsync(codeFilePath, FileUploadPurpose.Assistants);
|
||||
string uploadedFileId = uploadResult.Value.Id;
|
||||
var codeInterpreterTool = new HostedCodeInterpreterTool() { Inputs = [new HostedFileContent(uploadedFileId)] };
|
||||
|
||||
var agent = createMechanism switch
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = Instructions,
|
||||
Tools = [codeInterpreterTool]
|
||||
}
|
||||
}),
|
||||
"CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = Instructions,
|
||||
Tools = [codeInterpreterTool]
|
||||
}
|
||||
}),
|
||||
"CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
instructions: Instructions,
|
||||
tools: [codeInterpreterTool]),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await agent.RunAsync("What is the OPENAI_SECRET number?");
|
||||
var text = response.ToString();
|
||||
Assert.Contains("13579", text);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await this._assistantClient.DeleteAssistantAsync(agent.Id);
|
||||
await this._fileClient.DeleteFileAsync(uploadedFileId);
|
||||
File.Delete(codeFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory(Skip = "For manual testing only")]
|
||||
[InlineData("CreateWithChatClientAgentOptionsAsync")]
|
||||
[InlineData("CreateWithChatClientAgentOptionsSync")]
|
||||
[InlineData("CreateWithParamsAsync")]
|
||||
public async Task CreateAIAgentAsync_WithHostedFileSearchTool_SearchesFilesAsync(string createMechanism)
|
||||
{
|
||||
// Arrange.
|
||||
const string Instructions = """
|
||||
You are a helpful agent that can help fetch data from files you know about.
|
||||
Use the File Search Tool to look up codes for words.
|
||||
Do not answer a question unless you can find the answer using the File Search Tool.
|
||||
""";
|
||||
|
||||
// Create a local file with deterministic content and upload it.
|
||||
var searchFilePath = Path.GetTempFileName() + "wordcodelookup.txt";
|
||||
File.WriteAllText(
|
||||
path: searchFilePath,
|
||||
contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457.");
|
||||
var uploadResult = await this._fileClient.UploadFileAsync(searchFilePath, FileUploadPurpose.Assistants);
|
||||
string uploadedFileId = uploadResult.Value.Id;
|
||||
|
||||
// Create a vector store backing the file search (HostedFileSearchTool requires a vector store id).
|
||||
var vectorStoreClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetVectorStoreClient();
|
||||
var vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions()
|
||||
{
|
||||
Name = "WordCodeLookup_VectorStore",
|
||||
FileIds = { uploadedFileId }
|
||||
});
|
||||
string vectorStoreId = vectorStoreCreate.Value.Id;
|
||||
|
||||
// Wait for vector store indexing to complete before using it
|
||||
await WaitForVectorStoreReadyAsync(vectorStoreClient, vectorStoreId);
|
||||
|
||||
var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] };
|
||||
|
||||
var agent = createMechanism switch
|
||||
{
|
||||
"CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = Instructions,
|
||||
Tools = [fileSearchTool]
|
||||
}
|
||||
}),
|
||||
"CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
options: new ChatClientAgentOptions()
|
||||
{
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = Instructions,
|
||||
Tools = [fileSearchTool]
|
||||
}
|
||||
}),
|
||||
"CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
|
||||
instructions: Instructions,
|
||||
tools: [fileSearchTool]),
|
||||
_ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// Act - ask about banana code which must be retrieved via file search.
|
||||
var response = await agent.RunAsync("Can you give me the documented code for 'banana'?");
|
||||
var text = response.ToString();
|
||||
Assert.Contains("673457", text);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await this._assistantClient.DeleteAssistantAsync(agent.Id);
|
||||
await vectorStoreClient.DeleteVectorStoreAsync(vectorStoreId);
|
||||
await this._fileClient.DeleteFileAsync(uploadedFileId);
|
||||
File.Delete(searchFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for a vector store to complete indexing by polling its status.
|
||||
/// </summary>
|
||||
/// <param name="client">The vector store client.</param>
|
||||
/// <param name="vectorStoreId">The ID of the vector store.</param>
|
||||
/// <param name="maxWaitSeconds">Maximum time to wait in seconds (default: 30).</param>
|
||||
/// <returns>A task that completes when the vector store is ready or throws on timeout/failure.</returns>
|
||||
private static async Task WaitForVectorStoreReadyAsync(
|
||||
VectorStoreClient client,
|
||||
string vectorStoreId,
|
||||
int maxWaitSeconds = 30)
|
||||
{
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
while (sw.Elapsed.TotalSeconds < maxWaitSeconds)
|
||||
{
|
||||
VectorStore vectorStore = await client.GetVectorStoreAsync(vectorStoreId);
|
||||
VectorStoreStatus status = vectorStore.Status;
|
||||
|
||||
if (status == VectorStoreStatus.Completed)
|
||||
{
|
||||
if (vectorStore.FileCounts.Failed > 0)
|
||||
{
|
||||
throw new InvalidOperationException("Vector store indexing failed for some files");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == VectorStoreStatus.Expired)
|
||||
{
|
||||
throw new InvalidOperationException("Vector store has expired");
|
||||
}
|
||||
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
throw new TimeoutException($"Vector store did not complete indexing within {maxWaitSeconds}s");
|
||||
}
|
||||
}
|
||||
+85
-8
@@ -97,13 +97,20 @@ def __getattr__(name: str) -> Any:
|
||||
|
||||
**Important:** Do not create a new package unless approved by the core team.
|
||||
|
||||
### Initial Release (Preview)
|
||||
Every new package starts as `alpha`.
|
||||
|
||||
### Alpha package checklist
|
||||
|
||||
1. Create directory under `packages/` (e.g., `packages/my-connector/`)
|
||||
2. Add the package to `tool.uv.sources` in root `pyproject.toml`
|
||||
3. Include samples inside the package (e.g., `packages/my-connector/samples/`)
|
||||
4. Do **NOT** add to `[all]` extra in `packages/core/pyproject.toml`
|
||||
5. Do **NOT** create lazy loading in core yet
|
||||
3. Set the package version to the alpha pattern: `1.0.0a<date>`
|
||||
4. Set the package classifier to `Development Status :: 3 - Alpha`
|
||||
5. Include samples inside the package (e.g., `packages/my-connector/samples/`)
|
||||
6. Do **NOT** add to `[all]` extra in `packages/core/pyproject.toml`
|
||||
7. Do **NOT** create lazy loading in core yet
|
||||
8. Add the package to `python/PACKAGE_STATUS.md` and keep that file updated when packages are added,
|
||||
removed, renamed, or promoted. If the package exposes individually staged APIs, keep the feature list
|
||||
there current too.
|
||||
|
||||
Recommended dependency workflow during connector implementation:
|
||||
|
||||
@@ -116,17 +123,83 @@ Recommended dependency workflow during connector implementation:
|
||||
`uv run poe add-dependency-and-validate-bounds --package core --dependency "<dependency-spec>"`
|
||||
If compatibility checks are not in place yet, add the dependency first, then implement tests before running bound validation.
|
||||
|
||||
### Promotion to Stable
|
||||
### Promotion path
|
||||
|
||||
1. Move samples to root `samples/` folder
|
||||
2. Add to `[all]` extra in `packages/core/pyproject.toml`
|
||||
3. Create provider folder in `agent_framework/` with lazy loading `__init__.py`
|
||||
Promotion work is not isolated to the package being promoted. If a promotion changes dependency
|
||||
metadata for downstream packages, also update the dependent packages' own versions so they publish
|
||||
new metadata alongside the promoted dependency bounds.
|
||||
Apply the internal package dependency update rules from the versioning section below during
|
||||
promotions as well as standalone version update work.
|
||||
|
||||
#### Alpha -> Beta
|
||||
|
||||
Move a package to `beta` when it is stable enough to be part of the main install surface.
|
||||
|
||||
1. Update the package version to the beta pattern: `1.0.0b<date>`
|
||||
2. Update the classifier to `Development Status :: 4 - Beta`
|
||||
3. Add the package to `[all]` in `packages/core/pyproject.toml`
|
||||
4. Move samples to the root `samples/` tree and remove package-local samples
|
||||
5. Create or update the relevant lazy-loading namespace in core when the package belongs under one
|
||||
6. Update `python/PACKAGE_STATUS.md`
|
||||
|
||||
After `alpha`, there should be no samples left inside a package folder.
|
||||
|
||||
#### Beta -> RC
|
||||
|
||||
Move a package to `rc` when its API is close to the final released shape.
|
||||
|
||||
1. Update the package version to the release-candidate pattern: `1.0.0rc<number>`
|
||||
2. Keep the classifier at `Development Status :: 4 - Beta` because PyPI does not have a separate
|
||||
release-candidate classifier
|
||||
3. Keep the package in `core[all]`
|
||||
4. Keep samples only in the root `samples/` tree
|
||||
5. Update `python/PACKAGE_STATUS.md` to show the package as `rc`
|
||||
|
||||
#### RC -> Released
|
||||
|
||||
Move a package to `released` when it no longer carries a prerelease qualifier.
|
||||
|
||||
1. Update the package version to the stable pattern: `1.0.0`
|
||||
2. Update the classifier to `Development Status :: 5 - Production/Stable`
|
||||
3. Keep the package in `core[all]`
|
||||
4. Keep samples only in the root `samples/` tree
|
||||
5. Update `python/PACKAGE_STATUS.md` to show the package as `released`
|
||||
6. Update all `README.md` files that install that package with
|
||||
`pip install agent-framework-... --pre` so they use `pip install agent-framework-...` without
|
||||
the `--pre` suffix
|
||||
|
||||
## Versioning
|
||||
|
||||
### Internal package dependency updates
|
||||
|
||||
- If package A depends on package B within this repository, only update package A's dependency
|
||||
declaration when the work on package B actually affects package A.
|
||||
- If package A does not need anything from the package B change, leave package A's dependency
|
||||
declaration unchanged.
|
||||
- If package A does need something from the package B change, update package A's dependency
|
||||
declaration to the version or versioning scheme that matches what package A now requires.
|
||||
- If package B is promoted to a different lifecycle stage, update package A's dependency
|
||||
declaration to the new versioning scheme for package B even when the only change is the stage
|
||||
transition itself.
|
||||
- Use this guidance both for ordinary version updates and for package promotion work.
|
||||
|
||||
- All non-core packages declare a lower bound on `agent-framework-core`
|
||||
- When core version bumps with breaking changes, update the lower bound in all packages
|
||||
- Non-core packages version independently; only raise core bound when using new core APIs
|
||||
- If promoting a package changes a dependent package's published dependency metadata, bump the
|
||||
dependent package's own version in the correct lifecycle pattern for its current stage
|
||||
- Lifecycle version patterns:
|
||||
- `alpha`: `1.0.0a<date>`
|
||||
- `beta`: `1.0.0b<date>`
|
||||
- `rc`: `1.0.0rc<number>`
|
||||
- `released`: `1.0.0`
|
||||
- Keep the `Development Status` classifier in `pyproject.toml` aligned with the lifecycle stage:
|
||||
- `alpha` -> `Development Status :: 3 - Alpha`
|
||||
- `beta` -> `Development Status :: 4 - Beta`
|
||||
- `rc` -> `Development Status :: 4 - Beta`
|
||||
- `released` -> `Development Status :: 5 - Production/Stable`
|
||||
- See the PyPI classifier list for the available classifier values:
|
||||
`https://pypi.org/classifiers/`
|
||||
|
||||
## Installation Options
|
||||
|
||||
@@ -144,6 +217,10 @@ When changing a package, check if its `AGENTS.md` needs updates:
|
||||
- Changing the package's purpose or architecture
|
||||
- Modifying import paths or usage patterns
|
||||
|
||||
Keep `python/PACKAGE_STATUS.md` updated when:
|
||||
- A package is added, removed, renamed, or promoted between lifecycle stages
|
||||
- A package starts or stops exposing individually staged experimental or release-candidate APIs
|
||||
|
||||
When a package adds, removes, or renames environment variables, update the related documentation in the same
|
||||
change:
|
||||
- The package's `README.md` for package-level configuration/env var guidance
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# Python Package Status
|
||||
|
||||
This file tracks the current lifecycle state of the Python packages in this workspace. Some packages at later stages might have features within them that are not ready yet, these have feature stage decorators on the relevant APIs, and for `experimental` features warnings are raised. See the [Feature-level staged APIs](#feature-level-staged-apis) section below for details on which features are in which stage and where to find them.
|
||||
|
||||
Status is grouped into these buckets:
|
||||
|
||||
- `alpha` - initial release and early development packages that are not yet ready for general use
|
||||
- `beta` - prerelease packages that are not currently release candidates
|
||||
- `rc` - release candidate packages, these are close to ready for release but may still have some breaking changes before the final release
|
||||
- `released` - stable packages without a prerelease suffix, these are stable packages that should not have breaking changes between versions
|
||||
- `deprecated` - removed or deprecated packages that should not be used for new work
|
||||
|
||||
## Current packages
|
||||
|
||||
| Package | Path | State |
|
||||
| --- | --- | --- |
|
||||
| `agent-framework` | `python/` | `released` |
|
||||
| `agent-framework-a2a` | `python/packages/a2a` | `beta` |
|
||||
| `agent-framework-ag-ui` | `python/packages/ag-ui` | `beta` |
|
||||
| `agent-framework-anthropic` | `python/packages/anthropic` | `beta` |
|
||||
| `agent-framework-azure-ai-search` | `python/packages/azure-ai-search` | `beta` |
|
||||
| `agent-framework-azure-cosmos` | `python/packages/azure-cosmos` | `beta` |
|
||||
| `agent-framework-azurefunctions` | `python/packages/azurefunctions` | `beta` |
|
||||
| `agent-framework-bedrock` | `python/packages/bedrock` | `beta` |
|
||||
| `agent-framework-chatkit` | `python/packages/chatkit` | `beta` |
|
||||
| `agent-framework-claude` | `python/packages/claude` | `beta` |
|
||||
| `agent-framework-copilotstudio` | `python/packages/copilotstudio` | `beta` |
|
||||
| `agent-framework-core` | `python/packages/core` | `released` |
|
||||
| `agent-framework-declarative` | `python/packages/declarative` | `beta` |
|
||||
| `agent-framework-devui` | `python/packages/devui` | `beta` |
|
||||
| `agent-framework-durabletask` | `python/packages/durabletask` | `beta` |
|
||||
| `agent-framework-foundry` | `python/packages/foundry` | `released` |
|
||||
| `agent-framework-foundry-local` | `python/packages/foundry_local` | `beta` |
|
||||
| `agent-framework-github-copilot` | `python/packages/github_copilot` | `beta` |
|
||||
| `agent-framework-lab` | `python/packages/lab` | `beta` |
|
||||
| `agent-framework-mem0` | `python/packages/mem0` | `beta` |
|
||||
| `agent-framework-ollama` | `python/packages/ollama` | `beta` |
|
||||
| `agent-framework-openai` | `python/packages/openai` | `released` |
|
||||
| `agent-framework-orchestrations` | `python/packages/orchestrations` | `beta` |
|
||||
| `agent-framework-purview` | `python/packages/purview` | `beta` |
|
||||
| `agent-framework-redis` | `python/packages/redis` | `beta` |
|
||||
|
||||
## Deprecated / removed packages
|
||||
|
||||
| Package | Previous path | State | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| `agent-framework-azure-ai` | `python/packages/azure-ai` | `deprecated` | The client classes within the `azure-ai` package were renamed, sometimes changed, and moved to `agent-framework-foundry`. |
|
||||
|
||||
## Feature-level staged APIs
|
||||
|
||||
The following feature IDs have explicit feature-stage decorators on public APIs in the packages
|
||||
listed below.
|
||||
|
||||
### Experimental features
|
||||
|
||||
#### `EVALS`
|
||||
|
||||
- `agent-framework-core`: exported evaluation APIs from `agent_framework`, including
|
||||
`LocalEvaluator`, `evaluate_agent`, `evaluate_workflow`, and the related evaluation types and
|
||||
helper checks defined in `agent_framework/_evaluation.py`
|
||||
- `agent-framework-foundry`: `FoundryEvals`, `evaluate_traces`, and `evaluate_foundry_target`
|
||||
|
||||
#### `SKILLS`
|
||||
|
||||
- `agent-framework-core`: exported skills APIs from `agent_framework`, including `Skill`,
|
||||
`SkillResource`, `SkillScript`, `SkillScriptRunner`, and `SkillsProvider` from
|
||||
`agent_framework/_skills.py`
|
||||
|
||||
### Release-candidate features
|
||||
|
||||
There are currently no feature-level `rc` APIs.
|
||||
+7
-7
@@ -9,10 +9,10 @@ We recommend two common installation paths depending on your use case.
|
||||
If you are exploring or developing locally, install the entire framework with all sub-packages:
|
||||
|
||||
```bash
|
||||
pip install agent-framework --pre
|
||||
pip install agent-framework
|
||||
```
|
||||
|
||||
This installs the core and every integration package, making sure that all features are available without additional steps. The `--pre` flag is required while Agent Framework is in preview. This is the simplest way to get started.
|
||||
This installs the core and every integration package, making sure that all features are available without additional steps. This is the simplest way to get started.
|
||||
|
||||
### 2. Selective install
|
||||
|
||||
@@ -22,19 +22,19 @@ If you only need specific integrations, you can install at a more granular level
|
||||
# Core only
|
||||
# includes Azure OpenAI and OpenAI support by default
|
||||
# also includes workflows and orchestrations
|
||||
pip install agent-framework-core --pre
|
||||
pip install agent-framework-core
|
||||
|
||||
# Core + Azure AI Foundry integration
|
||||
pip install agent-framework-foundry --pre
|
||||
pip install agent-framework-foundry
|
||||
|
||||
# Core + Microsoft Copilot Studio integration
|
||||
# Core + Microsoft Copilot Studio integration (preview package)
|
||||
pip install agent-framework-copilotstudio --pre
|
||||
|
||||
# Core + both Microsoft Copilot Studio and Azure AI Foundry integration
|
||||
pip install agent-framework-microsoft agent-framework-foundry --pre
|
||||
pip install --pre agent-framework-copilotstudio agent-framework-foundry
|
||||
```
|
||||
|
||||
This selective approach is useful when you know which integrations you need, and it is the recommended way to set up lightweight environments.
|
||||
This selective approach is useful when you know which integrations you need, and it is the recommended way to set up lightweight environments. Released packages such as `agent-framework`, `agent-framework-core`, and `agent-framework-foundry` no longer require `--pre`, while preview connectors such as `agent-framework-copilotstudio` still do.
|
||||
|
||||
Supported Platforms:
|
||||
|
||||
|
||||
@@ -365,6 +365,7 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
)
|
||||
|
||||
all_updates: list[AgentResponseUpdate] = []
|
||||
streamed_artifact_ids_by_task: dict[str, set[str]] = {}
|
||||
async for item in a2a_stream:
|
||||
if isinstance(item, A2AMessage):
|
||||
# Process A2A Message
|
||||
@@ -378,12 +379,21 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
all_updates.append(update)
|
||||
yield update
|
||||
elif isinstance(item, tuple) and len(item) == 2 and isinstance(item[0], Task):
|
||||
task, _update_event = item
|
||||
for update in self._updates_from_task(
|
||||
task, update_event = item
|
||||
updates = self._updates_from_task(
|
||||
task,
|
||||
update_event=update_event,
|
||||
background=background,
|
||||
emit_intermediate=emit_intermediate,
|
||||
streamed_artifact_ids=streamed_artifact_ids_by_task.get(task.id),
|
||||
)
|
||||
if isinstance(update_event, TaskArtifactUpdateEvent) and any(
|
||||
update.raw_representation is update_event for update in updates
|
||||
):
|
||||
streamed_artifact_ids_by_task.setdefault(task.id, set()).add(update_event.artifact.artifact_id)
|
||||
if task.status.state in TERMINAL_TASK_STATES:
|
||||
streamed_artifact_ids_by_task.pop(task.id, None)
|
||||
for update in updates:
|
||||
all_updates.append(update)
|
||||
yield update
|
||||
else:
|
||||
@@ -403,8 +413,10 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
self,
|
||||
task: Task,
|
||||
*,
|
||||
update_event: TaskStatusUpdateEvent | TaskArtifactUpdateEvent | None = None,
|
||||
background: bool = False,
|
||||
emit_intermediate: bool = False,
|
||||
streamed_artifact_ids: set[str] | None = None,
|
||||
) -> list[AgentResponseUpdate]:
|
||||
"""Convert an A2A Task into AgentResponseUpdate(s).
|
||||
|
||||
@@ -418,8 +430,21 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
"""
|
||||
status = task.status
|
||||
|
||||
if (
|
||||
emit_intermediate
|
||||
and update_event is not None
|
||||
and (event_updates := self._updates_from_task_update_event(update_event))
|
||||
):
|
||||
return event_updates
|
||||
|
||||
if status.state in TERMINAL_TASK_STATES:
|
||||
task_messages = self._parse_messages_from_task(task)
|
||||
if task.artifacts is not None and streamed_artifact_ids:
|
||||
task_messages = [
|
||||
message
|
||||
for message in task_messages
|
||||
if getattr(message.raw_representation, "artifact_id", None) not in streamed_artifact_ids
|
||||
]
|
||||
if task_messages:
|
||||
return [
|
||||
AgentResponseUpdate(
|
||||
@@ -431,6 +456,8 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
)
|
||||
for message in task_messages
|
||||
]
|
||||
if task.artifacts is not None:
|
||||
return []
|
||||
return [AgentResponseUpdate(contents=[], role="assistant", response_id=task.id, raw_representation=task)]
|
||||
|
||||
if background and status.state in IN_PROGRESS_TASK_STATES:
|
||||
@@ -467,6 +494,44 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
|
||||
|
||||
return []
|
||||
|
||||
def _updates_from_task_update_event(
|
||||
self, update_event: TaskStatusUpdateEvent | TaskArtifactUpdateEvent
|
||||
) -> list[AgentResponseUpdate]:
|
||||
"""Convert A2A task update events into streaming AgentResponseUpdates."""
|
||||
if isinstance(update_event, TaskArtifactUpdateEvent):
|
||||
contents = self._parse_contents_from_a2a(update_event.artifact.parts)
|
||||
if not contents:
|
||||
return []
|
||||
return [
|
||||
AgentResponseUpdate(
|
||||
contents=contents,
|
||||
role="assistant",
|
||||
response_id=update_event.task_id,
|
||||
message_id=update_event.artifact.artifact_id,
|
||||
raw_representation=update_event,
|
||||
)
|
||||
]
|
||||
|
||||
if not isinstance(update_event, TaskStatusUpdateEvent):
|
||||
return []
|
||||
|
||||
message = update_event.status.message
|
||||
if message is None or not message.parts:
|
||||
return []
|
||||
|
||||
contents = self._parse_contents_from_a2a(message.parts)
|
||||
if not contents:
|
||||
return []
|
||||
|
||||
return [
|
||||
AgentResponseUpdate(
|
||||
contents=contents,
|
||||
role="assistant" if message.role == A2ARole.agent else "user",
|
||||
response_id=update_event.task_id,
|
||||
raw_representation=update_event,
|
||||
)
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def _build_continuation_token(task: Task) -> A2AContinuationToken | None:
|
||||
"""Build an A2AContinuationToken from an A2A Task if it is still in progress."""
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "A2A integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"a2a-sdk>=0.3.5,<0.3.24",
|
||||
]
|
||||
|
||||
|
||||
@@ -14,8 +14,10 @@ from a2a.types import (
|
||||
FileWithUri,
|
||||
Part,
|
||||
Task,
|
||||
TaskArtifactUpdateEvent,
|
||||
TaskState,
|
||||
TaskStatus,
|
||||
TaskStatusUpdateEvent,
|
||||
TextPart,
|
||||
)
|
||||
from a2a.types import Message as A2AMessage
|
||||
@@ -1189,4 +1191,201 @@ async def test_streaming_working_update_with_empty_parts_is_skipped(
|
||||
assert updates[0].contents[0].text == "Result"
|
||||
|
||||
|
||||
async def test_streaming_artifact_update_event_yields_content(
|
||||
a2a_agent: A2AAgent, mock_a2a_client: MockA2AClient
|
||||
) -> None:
|
||||
"""Test that streaming artifact update events yield incremental content."""
|
||||
task = Task(id="task-art", context_id="ctx-art", status=TaskStatus(state=TaskState.working, message=None))
|
||||
artifact = Artifact(
|
||||
artifact_id="artifact-1",
|
||||
parts=[Part(root=TextPart(text="Hello"))],
|
||||
)
|
||||
update_event = TaskArtifactUpdateEvent(task_id="task-art", context_id="ctx-art", artifact=artifact, append=False)
|
||||
mock_a2a_client.responses.append((task, update_event))
|
||||
|
||||
updates: list[AgentResponseUpdate] = []
|
||||
async for update in a2a_agent.run("Hello", stream=True):
|
||||
updates.append(update)
|
||||
|
||||
assert len(updates) == 1
|
||||
assert updates[0].text == "Hello"
|
||||
assert updates[0].message_id == "artifact-1"
|
||||
assert updates[0].raw_representation == update_event
|
||||
|
||||
|
||||
async def test_streaming_status_update_event_yields_content(
|
||||
a2a_agent: A2AAgent, mock_a2a_client: MockA2AClient
|
||||
) -> None:
|
||||
"""Test that streaming status update events surface message content directly from the update event."""
|
||||
update_event = TaskStatusUpdateEvent(
|
||||
task_id="task-status",
|
||||
context_id="ctx-status",
|
||||
status=TaskStatus(
|
||||
state=TaskState.working,
|
||||
message=A2AMessage(
|
||||
message_id=str(uuid4()),
|
||||
role=A2ARole.agent,
|
||||
parts=[Part(root=TextPart(text="Still working"))],
|
||||
),
|
||||
),
|
||||
final=False,
|
||||
)
|
||||
task = Task(id="task-status", context_id="ctx-status", status=TaskStatus(state=TaskState.working, message=None))
|
||||
mock_a2a_client.responses.append((task, update_event))
|
||||
|
||||
updates: list[AgentResponseUpdate] = []
|
||||
async for update in a2a_agent.run("Hello", stream=True):
|
||||
updates.append(update)
|
||||
|
||||
assert len(updates) == 1
|
||||
assert updates[0].text == "Still working"
|
||||
assert updates[0].role == "assistant"
|
||||
assert updates[0].raw_representation == update_event
|
||||
|
||||
|
||||
async def test_streaming_artifact_update_event_does_not_duplicate_terminal_task_artifacts(
|
||||
a2a_agent: A2AAgent, mock_a2a_client: MockA2AClient
|
||||
) -> None:
|
||||
"""Test that streamed artifact chunks are not re-emitted from the final terminal task."""
|
||||
working_task = Task(id="task-art-dup", context_id="ctx-art-dup", status=TaskStatus(state=TaskState.working))
|
||||
first_chunk = TaskArtifactUpdateEvent(
|
||||
task_id="task-art-dup",
|
||||
context_id="ctx-art-dup",
|
||||
artifact=Artifact(
|
||||
artifact_id="artifact-dup",
|
||||
parts=[Part(root=TextPart(text="Hello "))],
|
||||
),
|
||||
append=False,
|
||||
)
|
||||
second_chunk = TaskArtifactUpdateEvent(
|
||||
task_id="task-art-dup",
|
||||
context_id="ctx-art-dup",
|
||||
artifact=Artifact(
|
||||
artifact_id="artifact-dup",
|
||||
parts=[Part(root=TextPart(text="world"))],
|
||||
),
|
||||
append=True,
|
||||
)
|
||||
terminal_task = Task(
|
||||
id="task-art-dup",
|
||||
context_id="ctx-art-dup",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
artifacts=[
|
||||
Artifact(
|
||||
artifact_id="artifact-dup",
|
||||
parts=[Part(root=TextPart(text="Hello world"))],
|
||||
)
|
||||
],
|
||||
)
|
||||
terminal_event = TaskStatusUpdateEvent(
|
||||
task_id="task-art-dup",
|
||||
context_id="ctx-art-dup",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
final=True,
|
||||
)
|
||||
|
||||
mock_a2a_client.responses.extend(
|
||||
[
|
||||
(working_task, first_chunk),
|
||||
(working_task, second_chunk),
|
||||
(terminal_task, terminal_event),
|
||||
]
|
||||
)
|
||||
|
||||
stream = a2a_agent.run("Hello", stream=True)
|
||||
updates: list[AgentResponseUpdate] = []
|
||||
async for update in stream:
|
||||
updates.append(update)
|
||||
response = await stream.get_final_response()
|
||||
|
||||
assert [update.text for update in updates] == ["Hello ", "world"]
|
||||
assert response.text == "Hello world"
|
||||
assert len(response.messages) == 1
|
||||
|
||||
|
||||
async def test_streaming_terminal_task_artifacts_are_emitted_when_terminal_event_has_no_content(
|
||||
a2a_agent: A2AAgent, mock_a2a_client: MockA2AClient
|
||||
) -> None:
|
||||
"""Test that terminal task artifacts are still emitted when the final status event has no message."""
|
||||
terminal_task = Task(
|
||||
id="task-art-final",
|
||||
context_id="ctx-art-final",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
artifacts=[
|
||||
Artifact(
|
||||
artifact_id="artifact-final",
|
||||
parts=[Part(root=TextPart(text="Final artifact"))],
|
||||
)
|
||||
],
|
||||
)
|
||||
terminal_event = TaskStatusUpdateEvent(
|
||||
task_id="task-art-final",
|
||||
context_id="ctx-art-final",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
final=True,
|
||||
)
|
||||
mock_a2a_client.responses.append((terminal_task, terminal_event))
|
||||
|
||||
updates: list[AgentResponseUpdate] = []
|
||||
async for update in a2a_agent.run("Hello", stream=True):
|
||||
updates.append(update)
|
||||
|
||||
assert len(updates) == 1
|
||||
assert updates[0].text == "Final artifact"
|
||||
assert updates[0].message_id == "artifact-final"
|
||||
|
||||
|
||||
async def test_streaming_terminal_task_only_emits_unstreamed_artifacts(
|
||||
a2a_agent: A2AAgent, mock_a2a_client: MockA2AClient
|
||||
) -> None:
|
||||
"""Test that the terminal task only emits artifacts that were not already streamed incrementally."""
|
||||
working_task = Task(id="task-art-mixed", context_id="ctx-art-mixed", status=TaskStatus(state=TaskState.working))
|
||||
streamed_chunk = TaskArtifactUpdateEvent(
|
||||
task_id="task-art-mixed",
|
||||
context_id="ctx-art-mixed",
|
||||
artifact=Artifact(
|
||||
artifact_id="artifact-streamed",
|
||||
parts=[Part(root=TextPart(text="Hello"))],
|
||||
),
|
||||
append=False,
|
||||
)
|
||||
terminal_task = Task(
|
||||
id="task-art-mixed",
|
||||
context_id="ctx-art-mixed",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
artifacts=[
|
||||
Artifact(
|
||||
artifact_id="artifact-streamed",
|
||||
parts=[Part(root=TextPart(text="Hello"))],
|
||||
),
|
||||
Artifact(
|
||||
artifact_id="artifact-final",
|
||||
parts=[Part(root=TextPart(text="Goodbye"))],
|
||||
),
|
||||
],
|
||||
)
|
||||
terminal_event = TaskStatusUpdateEvent(
|
||||
task_id="task-art-mixed",
|
||||
context_id="ctx-art-mixed",
|
||||
status=TaskStatus(state=TaskState.completed, message=None),
|
||||
final=True,
|
||||
)
|
||||
|
||||
mock_a2a_client.responses.extend(
|
||||
[
|
||||
(working_task, streamed_chunk),
|
||||
(terminal_task, terminal_event),
|
||||
]
|
||||
)
|
||||
|
||||
stream = a2a_agent.run("Hello", stream=True)
|
||||
updates: list[AgentResponseUpdate] = []
|
||||
async for update in stream:
|
||||
updates.append(update)
|
||||
response = await stream.get_final_response()
|
||||
|
||||
assert [update.text for update in updates] == ["Hello", "Goodbye"]
|
||||
assert [message.text for message in response.messages] == ["Hello", "Goodbye"]
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -44,7 +44,7 @@ async def main():
|
||||
metadata = {"thread_id": thread_id} if thread_id else None
|
||||
|
||||
stream = client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
stream=True,
|
||||
options={"metadata": metadata} if metadata else None,
|
||||
)
|
||||
|
||||
@@ -73,7 +73,7 @@ async def streaming_example(client: AGUIChatClient, thread_id: str | None = None
|
||||
print("Assistant: ", end="", flush=True)
|
||||
|
||||
stream = client.get_response(
|
||||
[Message(role="user", text="Tell me a short joke")],
|
||||
[Message(role="user", contents=["Tell me a short joke"])],
|
||||
stream=True,
|
||||
options={"metadata": metadata} if metadata else None,
|
||||
)
|
||||
@@ -100,7 +100,7 @@ async def non_streaming_example(client: AGUIChatClient, thread_id: str | None =
|
||||
|
||||
print("\nUser: What is 2 + 2?\n")
|
||||
|
||||
response = await client.get_response([Message(role="user", text="What is 2 + 2?")], metadata=metadata)
|
||||
response = await client.get_response([Message(role="user", contents=["What is 2 + 2?"])], metadata=metadata)
|
||||
|
||||
print(f"Assistant: {response.text}")
|
||||
|
||||
@@ -139,7 +139,9 @@ async def tool_example(client: AGUIChatClient, thread_id: str | None = None):
|
||||
print("(Server must be configured with matching tools to execute them)\n")
|
||||
|
||||
response = await client.get_response(
|
||||
[Message(role="user", text="What's the weather in Seattle?")], tools=[get_weather, calculate], metadata=metadata
|
||||
[Message(role="user", contents=["What's the weather in Seattle?"])],
|
||||
tools=[get_weather, calculate],
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
print(f"Assistant: {response.text}")
|
||||
@@ -174,7 +176,7 @@ async def conversation_example(client: AGUIChatClient):
|
||||
|
||||
# First turn
|
||||
print("User: My name is Alice\n")
|
||||
response1 = await client.get_response([Message(role="user", text="My name is Alice")])
|
||||
response1 = await client.get_response([Message(role="user", contents=["My name is Alice"])])
|
||||
print(f"Assistant: {response1.text}")
|
||||
thread_id = response1.additional_properties.get("thread_id")
|
||||
print(f"\n[Thread: {thread_id}]")
|
||||
@@ -182,7 +184,7 @@ async def conversation_example(client: AGUIChatClient):
|
||||
# Second turn - using same thread
|
||||
print("\nUser: What's my name?\n")
|
||||
response2 = await client.get_response(
|
||||
[Message(role="user", text="What's my name?")], options={"metadata": {"thread_id": thread_id}}
|
||||
[Message(role="user", contents=["What's my name?"])], options={"metadata": {"thread_id": thread_id}}
|
||||
)
|
||||
print(f"Assistant: {response2.text}")
|
||||
|
||||
@@ -193,7 +195,7 @@ async def conversation_example(client: AGUIChatClient):
|
||||
# Third turn
|
||||
print("\nUser: Can you also tell me what 10 * 5 is?\n")
|
||||
response3 = await client.get_response(
|
||||
[Message(role="user", text="Can you also tell me what 10 * 5 is?")],
|
||||
[Message(role="user", contents=["Can you also tell me what 10 * 5 is?"])],
|
||||
options={"metadata": {"thread_id": thread_id}},
|
||||
tools=[calculate],
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "agent-framework-ag-ui"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
description = "AG-UI protocol integration for Agent Framework"
|
||||
readme = "README.md"
|
||||
license-files = ["LICENSE"]
|
||||
@@ -22,7 +22,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"ag-ui-protocol==0.1.13",
|
||||
"fastapi>=0.115.0,<0.133.1",
|
||||
"uvicorn[standard]>=0.30.0,<0.42.0"
|
||||
|
||||
@@ -67,8 +67,8 @@ class TestAGUIChatClient:
|
||||
"""Test state extraction when no state is present."""
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
messages = [
|
||||
Message(role="user", text="Hello"),
|
||||
Message(role="assistant", text="Hi there"),
|
||||
Message(role="user", contents=["Hello"]),
|
||||
Message(role="assistant", contents=["Hi there"]),
|
||||
]
|
||||
|
||||
result_messages, state = client.extract_state_from_messages(messages)
|
||||
@@ -87,7 +87,7 @@ class TestAGUIChatClient:
|
||||
state_b64 = base64.b64encode(state_json.encode("utf-8")).decode("utf-8")
|
||||
|
||||
messages = [
|
||||
Message(role="user", text="Hello"),
|
||||
Message(role="user", contents=["Hello"]),
|
||||
Message(
|
||||
role="user",
|
||||
contents=[Content.from_uri(uri=f"data:application/json;base64,{state_b64}")],
|
||||
@@ -125,8 +125,8 @@ class TestAGUIChatClient:
|
||||
"""Test message conversion to AG-UI format."""
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
messages = [
|
||||
Message(role="user", text="What is the weather?"),
|
||||
Message(role="assistant", text="Let me check.", message_id="msg_123"),
|
||||
Message(role="user", contents=["What is the weather?"]),
|
||||
Message(role="assistant", contents=["Let me check."], message_id="msg_123"),
|
||||
]
|
||||
|
||||
agui_messages = client.convert_messages_to_agui_format(messages)
|
||||
@@ -173,7 +173,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test message")]
|
||||
messages = [Message(role="user", contents=["Test message"])]
|
||||
chat_options = ChatOptions()
|
||||
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
@@ -206,7 +206,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test message")]
|
||||
messages = [Message(role="user", contents=["Test message"])]
|
||||
chat_options = {}
|
||||
|
||||
response = await client.inner_get_response(messages=messages, options=chat_options)
|
||||
@@ -249,7 +249,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test with tools")]
|
||||
messages = [Message(role="user", contents=["Test with tools"])]
|
||||
chat_options = ChatOptions(tools=[test_tool])
|
||||
|
||||
response = await client.inner_get_response(messages=messages, options=chat_options)
|
||||
@@ -273,7 +273,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test server tool execution")]
|
||||
messages = [Message(role="user", contents=["Test server tool execution"])]
|
||||
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in client.get_response(messages, stream=True):
|
||||
@@ -315,7 +315,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test server tool execution")]
|
||||
messages = [Message(role="user", contents=["Test server tool execution"])]
|
||||
|
||||
async for _ in client.get_response(
|
||||
messages, stream=True, options={"tool_choice": "auto", "tools": [client_tool]}
|
||||
@@ -331,7 +331,7 @@ class TestAGUIChatClient:
|
||||
state_b64 = base64.b64encode(state_json.encode("utf-8")).decode("utf-8")
|
||||
|
||||
messages = [
|
||||
Message(role="user", text="Hello"),
|
||||
Message(role="user", contents=["Hello"]),
|
||||
Message(
|
||||
role="user",
|
||||
contents=[Content.from_uri(uri=f"data:application/json;base64,{state_b64}")],
|
||||
@@ -388,7 +388,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test")]
|
||||
messages = [Message(role="user", contents=["Test"])]
|
||||
response = await client.inner_get_response(messages=messages, options={}, stream=False)
|
||||
|
||||
assert response is not None
|
||||
@@ -416,7 +416,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="Test")]
|
||||
messages = [Message(role="user", contents=["Test"])]
|
||||
updates: list[ChatResponseUpdate] = []
|
||||
async for update in client._inner_get_response(messages=messages, stream=True, options={"tools": [my_tool]}):
|
||||
updates.append(update)
|
||||
@@ -451,7 +451,7 @@ class TestAGUIChatClient:
|
||||
client = StubAGUIChatClient(endpoint="http://localhost:8888/")
|
||||
monkeypatch.setattr(client.http_service, "post_run", mock_post_run)
|
||||
|
||||
messages = [Message(role="user", text="continue")]
|
||||
messages = [Message(role="user", contents=["continue"])]
|
||||
options = {
|
||||
"available_interrupts": available_interrupts,
|
||||
"resume": resume_payload,
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Anthropic integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"anthropic>=0.80.0,<0.80.1",
|
||||
]
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ def test_anthropic_client_service_url(mock_anthropic_client: MagicMock) -> None:
|
||||
def test_prepare_message_for_anthropic_text(mock_anthropic_client: MagicMock) -> None:
|
||||
"""Test converting text message to Anthropic format."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
message = Message(role="user", text="Hello, world!")
|
||||
message = Message(role="user", contents=["Hello, world!"])
|
||||
|
||||
result = client._prepare_message_for_anthropic(message)
|
||||
|
||||
@@ -491,8 +491,8 @@ def test_prepare_messages_for_anthropic_with_system(
|
||||
"""Test converting messages list with system message."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
messages = [
|
||||
Message(role="system", text="You are a helpful assistant."),
|
||||
Message(role="user", text="Hello!"),
|
||||
Message(role="system", contents=["You are a helpful assistant."]),
|
||||
Message(role="user", contents=["Hello!"]),
|
||||
]
|
||||
|
||||
result = client._prepare_messages_for_anthropic(messages)
|
||||
@@ -509,8 +509,8 @@ def test_prepare_messages_for_anthropic_without_system(
|
||||
"""Test converting messages list without system message."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
messages = [
|
||||
Message(role="user", text="Hello!"),
|
||||
Message(role="assistant", text="Hi there!"),
|
||||
Message(role="user", contents=["Hello!"]),
|
||||
Message(role="assistant", contents=["Hi there!"]),
|
||||
]
|
||||
|
||||
result = client._prepare_messages_for_anthropic(messages)
|
||||
@@ -735,7 +735,7 @@ async def test_prepare_options_basic(mock_anthropic_client: MagicMock) -> None:
|
||||
"""Test _prepare_options with basic ChatOptions."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(max_tokens=100, temperature=0.7)
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -753,8 +753,8 @@ async def test_prepare_options_with_system_message(
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [
|
||||
Message(role="system", text="You are helpful."),
|
||||
Message(role="user", text="Hello"),
|
||||
Message(role="system", contents=["You are helpful."]),
|
||||
Message(role="user", contents=["Hello"]),
|
||||
]
|
||||
chat_options = ChatOptions()
|
||||
|
||||
@@ -807,7 +807,7 @@ async def test_anthropic_shell_tool_is_invoked_in_function_loop(
|
||||
]
|
||||
|
||||
await client.get_response(
|
||||
messages=[Message(role="user", text="Run pwd")],
|
||||
messages=[Message(role="user", contents=["Run pwd"])],
|
||||
options={"tools": [shell_tool_instance], "max_tokens": 64},
|
||||
)
|
||||
|
||||
@@ -833,7 +833,7 @@ async def test_prepare_options_with_tool_choice_auto(
|
||||
"""Test _prepare_options with auto tool choice."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(tool_choice="auto", allow_multiple_tool_calls=False)
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -849,7 +849,7 @@ async def test_prepare_options_with_tool_choice_required(
|
||||
"""Test _prepare_options with required tool choice."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
# For required with specific function, need to pass as dict
|
||||
chat_options = ChatOptions(tool_choice={"mode": "required", "required_function_name": "get_weather"})
|
||||
|
||||
@@ -865,7 +865,7 @@ async def test_prepare_options_with_tool_choice_none(
|
||||
"""Test _prepare_options with none tool choice."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(tool_choice="none")
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -882,7 +882,7 @@ async def test_prepare_options_with_tools(mock_anthropic_client: MagicMock) -> N
|
||||
"""Get weather for a location."""
|
||||
return f"Weather for {location}"
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(tools=[get_weather])
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -897,7 +897,7 @@ async def test_prepare_options_with_stop_sequences(
|
||||
"""Test _prepare_options with stop sequences."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(stop=["STOP", "END"])
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -909,7 +909,7 @@ async def test_prepare_options_with_top_p(mock_anthropic_client: MagicMock) -> N
|
||||
"""Test _prepare_options with top_p."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options = ChatOptions(top_p=0.9)
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -923,7 +923,7 @@ async def test_prepare_options_excludes_stream_option(
|
||||
"""Test _prepare_options excludes stream when stream is provided in options."""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options: dict[str, Any] = {"stream": True, "max_tokens": 100}
|
||||
|
||||
run_options = client._prepare_options(messages, chat_options)
|
||||
@@ -941,7 +941,7 @@ async def test_prepare_options_filters_internal_kwargs(
|
||||
"""
|
||||
client = create_test_anthropic_client(mock_anthropic_client)
|
||||
|
||||
messages = [Message(role="user", text="Hello")]
|
||||
messages = [Message(role="user", contents=["Hello"])]
|
||||
chat_options: ChatOptions = {}
|
||||
|
||||
# Simulate internal kwargs that get passed through the middleware pipeline
|
||||
@@ -1174,10 +1174,7 @@ def test_parse_contents_server_tool_use_input_json_delta_ignored(
|
||||
delta_content.partial_json = '{"query": "latest news"}'
|
||||
|
||||
result = client._parse_contents_from_anthropic([delta_content])
|
||||
assert result == [], (
|
||||
"input_json_delta after server_tool_use should produce no content, "
|
||||
"but got: %r" % result
|
||||
)
|
||||
assert result == [], "input_json_delta after server_tool_use should produce no content, but got: %r" % result
|
||||
|
||||
# A second delta must also be ignored
|
||||
delta_content_2 = MagicMock()
|
||||
@@ -1186,8 +1183,7 @@ def test_parse_contents_server_tool_use_input_json_delta_ignored(
|
||||
|
||||
result = client._parse_contents_from_anthropic([delta_content_2])
|
||||
assert result == [], (
|
||||
"subsequent input_json_delta after server_tool_use should also be ignored, "
|
||||
"but got: %r" % result
|
||||
"subsequent input_json_delta after server_tool_use should also be ignored, but got: %r" % result
|
||||
)
|
||||
|
||||
|
||||
@@ -1222,7 +1218,7 @@ async def test_inner_get_response(mock_anthropic_client: MagicMock) -> None:
|
||||
|
||||
mock_anthropic_client.beta.messages.create.return_value = mock_message
|
||||
|
||||
messages = [Message(role="user", text="Hi")]
|
||||
messages = [Message(role="user", contents=["Hi"])]
|
||||
chat_options = ChatOptions(max_tokens=10)
|
||||
|
||||
response = await client._inner_get_response( # type: ignore[attr-defined]
|
||||
@@ -1248,7 +1244,7 @@ async def test_inner_get_response_ignores_options_stream_non_streaming(
|
||||
mock_message.stop_reason = "end_turn"
|
||||
mock_anthropic_client.beta.messages.create.return_value = mock_message
|
||||
|
||||
messages = [Message(role="user", text="Hi")]
|
||||
messages = [Message(role="user", contents=["Hi"])]
|
||||
options: dict[str, Any] = {"max_tokens": 10, "stream": True}
|
||||
|
||||
await client._inner_get_response( # type: ignore[attr-defined]
|
||||
@@ -1272,7 +1268,7 @@ async def test_inner_get_response_streaming(mock_anthropic_client: MagicMock) ->
|
||||
|
||||
mock_anthropic_client.beta.messages.create.return_value = mock_stream()
|
||||
|
||||
messages = [Message(role="user", text="Hi")]
|
||||
messages = [Message(role="user", contents=["Hi"])]
|
||||
chat_options = ChatOptions(max_tokens=10)
|
||||
|
||||
chunks: list[ChatResponseUpdate] = []
|
||||
@@ -1299,7 +1295,7 @@ async def test_inner_get_response_ignores_options_stream_streaming(
|
||||
|
||||
mock_anthropic_client.beta.messages.create.return_value = mock_stream()
|
||||
|
||||
messages = [Message(role="user", text="Hi")]
|
||||
messages = [Message(role="user", contents=["Hi"])]
|
||||
options: dict[str, Any] = {"max_tokens": 10, "stream": False}
|
||||
|
||||
async for _ in client._inner_get_response( # type: ignore[attr-defined]
|
||||
@@ -1453,7 +1449,7 @@ async def test_anthropic_client_integration_basic_chat() -> None:
|
||||
"""Integration test for basic chat completion."""
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [Message(role="user", text="Say 'Hello, World!' and nothing else.")]
|
||||
messages = [Message(role="user", contents=["Say 'Hello, World!' and nothing else."])]
|
||||
|
||||
response = await client.get_response(messages=messages, options={"max_tokens": 50})
|
||||
|
||||
@@ -1471,7 +1467,7 @@ async def test_anthropic_client_integration_streaming_chat() -> None:
|
||||
"""Integration test for streaming chat completion."""
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [Message(role="user", text="Count from 1 to 5.")]
|
||||
messages = [Message(role="user", contents=["Count from 1 to 5."])]
|
||||
|
||||
chunks = []
|
||||
async for chunk in client.get_response(messages=messages, stream=True, options={"max_tokens": 50}):
|
||||
@@ -1488,7 +1484,7 @@ async def test_anthropic_client_integration_function_calling() -> None:
|
||||
"""Integration test for function calling."""
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [Message(role="user", text="What's the weather in San Francisco?")]
|
||||
messages = [Message(role="user", contents=["What's the weather in San Francisco?"])]
|
||||
tools = [get_weather]
|
||||
|
||||
response = await client.get_response(
|
||||
@@ -1509,7 +1505,7 @@ async def test_anthropic_client_integration_hosted_tools() -> None:
|
||||
"""Integration test for hosted tools."""
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [Message(role="user", text="What tools do you have available?")]
|
||||
messages = [Message(role="user", contents=["What tools do you have available?"])]
|
||||
tools = [
|
||||
AnthropicClient.get_web_search_tool(),
|
||||
AnthropicClient.get_code_interpreter_tool(),
|
||||
@@ -1536,8 +1532,8 @@ async def test_anthropic_client_integration_with_system_message() -> None:
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [
|
||||
Message(role="system", text="You are a pirate. Always respond like a pirate."),
|
||||
Message(role="user", text="Hello!"),
|
||||
Message(role="system", contents=["You are a pirate. Always respond like a pirate."]),
|
||||
Message(role="user", contents=["Hello!"]),
|
||||
]
|
||||
|
||||
response = await client.get_response(messages=messages, options={"max_tokens": 50})
|
||||
@@ -1553,7 +1549,7 @@ async def test_anthropic_client_integration_temperature_control() -> None:
|
||||
"""Integration test with temperature control."""
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [Message(role="user", text="Say hello.")]
|
||||
messages = [Message(role="user", contents=["Say hello."])]
|
||||
|
||||
response = await client.get_response(
|
||||
messages=messages,
|
||||
@@ -1572,11 +1568,11 @@ async def test_anthropic_client_integration_ordering() -> None:
|
||||
client = AnthropicClient()
|
||||
|
||||
messages = [
|
||||
Message(role="user", text="Say hello."),
|
||||
Message(role="user", text="Then say goodbye."),
|
||||
Message(role="assistant", text="Thank you for chatting!"),
|
||||
Message(role="assistant", text="Let me know if I can help."),
|
||||
Message(role="user", text="Just testing things."),
|
||||
Message(role="user", contents=["Say hello."]),
|
||||
Message(role="user", contents=["Then say goodbye."]),
|
||||
Message(role="assistant", contents=["Thank you for chatting!"]),
|
||||
Message(role="assistant", contents=["Let me know if I can help."]),
|
||||
Message(role="user", contents=["Just testing things."]),
|
||||
]
|
||||
|
||||
response = await client.get_response(messages=messages)
|
||||
@@ -2685,7 +2681,7 @@ async def test_anthropic_client_integration_tool_rich_content_image() -> None:
|
||||
client = AnthropicClient()
|
||||
client.function_invocation_configuration["max_iterations"] = 2
|
||||
|
||||
messages = [Message(role="user", text="Call the get_test_image tool and describe what you see.")]
|
||||
messages = [Message(role="user", contents=["Call the get_test_image tool and describe what you see."])]
|
||||
|
||||
response = await client.get_response(
|
||||
messages=messages,
|
||||
|
||||
+6
-4
@@ -604,7 +604,9 @@ class AzureAISearchContextProvider(ContextProvider):
|
||||
if not result_messages:
|
||||
return
|
||||
|
||||
context.extend_messages(self.source_id, [Message(role="user", text=self.context_prompt), *result_messages])
|
||||
context.extend_messages(
|
||||
self.source_id, [Message(role="user", contents=[self.context_prompt]), *result_messages]
|
||||
)
|
||||
|
||||
def _find_vector_fields(self, index: Any) -> list[str]:
|
||||
"""Find all fields that can store vectors."""
|
||||
@@ -719,7 +721,7 @@ class AzureAISearchContextProvider(ContextProvider):
|
||||
doc_id = doc.get("id") or doc.get("@search.id") # type: ignore[reportUnknownVariableType]
|
||||
doc_text: str = self._extract_document_text(doc, doc_id=doc_id) # type: ignore[reportUnknownArgumentType]
|
||||
if doc_text:
|
||||
result_messages.append(Message(role="user", text=doc_text)) # type: ignore[reportUnknownArgumentType]
|
||||
result_messages.append(Message(role="user", contents=[doc_text])) # type: ignore[reportUnknownArgumentType]
|
||||
return result_messages
|
||||
|
||||
async def _ensure_knowledge_base(self) -> None:
|
||||
@@ -951,7 +953,7 @@ class AzureAISearchContextProvider(ContextProvider):
|
||||
List of Messages, or a single default Message if no results found.
|
||||
"""
|
||||
if not retrieval_result.response:
|
||||
return [Message(role="assistant", text="No results found from Knowledge Base.")]
|
||||
return [Message(role="assistant", contents=["No results found from Knowledge Base."])]
|
||||
|
||||
annotations = AzureAISearchContextProvider._parse_references_to_annotations(retrieval_result.references)
|
||||
|
||||
@@ -972,7 +974,7 @@ class AzureAISearchContextProvider(ContextProvider):
|
||||
result_messages.append(Message(role=kb_msg.role or "assistant", contents=contents))
|
||||
|
||||
if not result_messages:
|
||||
return [Message(role="assistant", text="No results found from Knowledge Base.")]
|
||||
return [Message(role="assistant", contents=["No results found from Knowledge Base."])]
|
||||
return result_messages
|
||||
|
||||
def _extract_document_text(self, doc: dict[str, Any], doc_id: str | None = None) -> str:
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Azure AI Search integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"azure-search-documents>=11.7.0b2,<11.7.0b3",
|
||||
]
|
||||
|
||||
|
||||
@@ -1370,7 +1370,7 @@ class TestPrepareMessagesForKbSearch:
|
||||
assert len(result) == 0
|
||||
|
||||
def test_fallback_to_msg_text_when_no_contents(self) -> None:
|
||||
msg = Message(role="user", text="fallback text")
|
||||
msg = Message(role="user", contents=["fallback text"])
|
||||
result = AzureAISearchContextProvider._prepare_messages_for_kb_search([msg])
|
||||
assert len(result) == 1
|
||||
assert result[0].content[0].text == "fallback text"
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Azure Cosmos DB history provider integration for Microsoft Agent
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"azure-cosmos>=4.3.0,<5",
|
||||
]
|
||||
|
||||
|
||||
@@ -240,11 +240,11 @@ def build_agent_executor_response(
|
||||
Returns:
|
||||
AgentExecutorResponse with reconstructed conversation
|
||||
"""
|
||||
final_text = response_text
|
||||
final_text: str = response_text or ""
|
||||
if structured_response:
|
||||
final_text = json.dumps(structured_response)
|
||||
|
||||
assistant_message = Message(role="assistant", text=final_text)
|
||||
assistant_message = Message(role="assistant", contents=[final_text])
|
||||
|
||||
agent_response = AgentResponse(
|
||||
messages=[assistant_message],
|
||||
@@ -255,7 +255,7 @@ def build_agent_executor_response(
|
||||
if isinstance(previous_message, AgentExecutorResponse) and previous_message.full_conversation:
|
||||
full_conversation.extend(previous_message.full_conversation)
|
||||
elif isinstance(previous_message, str):
|
||||
full_conversation.append(Message(role="user", text=previous_message))
|
||||
full_conversation.append(Message(role="user", contents=[previous_message]))
|
||||
|
||||
full_conversation.append(assistant_message)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Azure Functions integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -22,7 +22,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"agent-framework-durabletask",
|
||||
"azure-functions>=1.24.0,<2",
|
||||
"azure-functions-durable>=1.3.1,<2",
|
||||
|
||||
@@ -357,7 +357,7 @@ class TestAgentEntityOperations:
|
||||
"""Test that entity can run agent operation."""
|
||||
mock_agent = Mock()
|
||||
mock_agent.run = AsyncMock(
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", text="Test response")])
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", contents=["Test response"])])
|
||||
)
|
||||
|
||||
entity = AgentEntity(mock_agent, state_provider=_InMemoryStateProvider(thread_id="test-conv-123"))
|
||||
@@ -374,7 +374,9 @@ class TestAgentEntityOperations:
|
||||
async def test_entity_stores_conversation_history(self) -> None:
|
||||
"""Test that the entity stores conversation history."""
|
||||
mock_agent = Mock()
|
||||
mock_agent.run = AsyncMock(return_value=AgentResponse(messages=[Message(role="assistant", text="Response 1")]))
|
||||
mock_agent.run = AsyncMock(
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", contents=["Response 1"])])
|
||||
)
|
||||
|
||||
entity = AgentEntity(mock_agent, state_provider=_InMemoryStateProvider(thread_id="conv-1"))
|
||||
|
||||
@@ -406,7 +408,9 @@ class TestAgentEntityOperations:
|
||||
async def test_entity_increments_message_count(self) -> None:
|
||||
"""Test that the entity increments the message count."""
|
||||
mock_agent = Mock()
|
||||
mock_agent.run = AsyncMock(return_value=AgentResponse(messages=[Message(role="assistant", text="Response")]))
|
||||
mock_agent.run = AsyncMock(
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", contents=["Response"])])
|
||||
)
|
||||
|
||||
entity = AgentEntity(mock_agent, state_provider=_InMemoryStateProvider(thread_id="conv-1"))
|
||||
|
||||
@@ -445,7 +449,9 @@ class TestAgentEntityFactory:
|
||||
def test_entity_function_handles_run_operation(self) -> None:
|
||||
"""Test that the entity function handles the run operation."""
|
||||
mock_agent = Mock()
|
||||
mock_agent.run = AsyncMock(return_value=AgentResponse(messages=[Message(role="assistant", text="Response")]))
|
||||
mock_agent.run = AsyncMock(
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", contents=["Response"])])
|
||||
)
|
||||
|
||||
entity_function = create_agent_entity(mock_agent)
|
||||
|
||||
@@ -470,7 +476,9 @@ class TestAgentEntityFactory:
|
||||
def test_entity_function_handles_run_agent_operation(self) -> None:
|
||||
"""Test that the entity function handles the deprecated run_agent operation for backward compatibility."""
|
||||
mock_agent = Mock()
|
||||
mock_agent.run = AsyncMock(return_value=AgentResponse(messages=[Message(role="assistant", text="Response")]))
|
||||
mock_agent.run = AsyncMock(
|
||||
return_value=AgentResponse(messages=[Message(role="assistant", contents=["Response"])])
|
||||
)
|
||||
|
||||
entity_function = create_agent_entity(mock_agent)
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ FuncT = TypeVar("FuncT", bound=Callable[..., Any])
|
||||
|
||||
def _agent_response(text: str | None) -> AgentResponse:
|
||||
"""Create an AgentResponse with a single assistant message."""
|
||||
message = Message(role="assistant", text=text) if text is not None else Message(role="assistant", text="")
|
||||
message = (
|
||||
Message(role="assistant", contents=[text]) if text is not None else Message(role="assistant", contents=[""])
|
||||
)
|
||||
return AgentResponse(messages=[message])
|
||||
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ class TestSerializationRoundtrip:
|
||||
|
||||
def test_roundtrip_chat_message(self) -> None:
|
||||
"""Test Message survives encode → decode roundtrip."""
|
||||
original = Message(role="user", text="Hello")
|
||||
original = Message(role="user", contents=["Hello"])
|
||||
encoded = serialize_value(original)
|
||||
decoded = deserialize_value(encoded)
|
||||
|
||||
@@ -216,7 +216,7 @@ class TestSerializationRoundtrip:
|
||||
def test_roundtrip_agent_executor_request(self) -> None:
|
||||
"""Test AgentExecutorRequest with nested Messages roundtrips."""
|
||||
original = AgentExecutorRequest(
|
||||
messages=[Message(role="user", text="Hi")],
|
||||
messages=[Message(role="user", contents=["Hi"])],
|
||||
should_respond=True,
|
||||
)
|
||||
encoded = serialize_value(original)
|
||||
@@ -231,8 +231,8 @@ class TestSerializationRoundtrip:
|
||||
"""Test AgentExecutorResponse with nested AgentResponse roundtrips."""
|
||||
original = AgentExecutorResponse(
|
||||
executor_id="test_exec",
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", text="Reply")]),
|
||||
full_conversation=[Message(role="assistant", text="Reply")],
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", contents=["Reply"])]),
|
||||
full_conversation=[Message(role="assistant", contents=["Reply"])],
|
||||
)
|
||||
encoded = serialize_value(original)
|
||||
decoded = deserialize_value(encoded)
|
||||
@@ -272,8 +272,8 @@ class TestSerializationRoundtrip:
|
||||
def test_roundtrip_list_of_objects(self) -> None:
|
||||
"""Test list of typed objects roundtrips."""
|
||||
original = [
|
||||
Message(role="user", text="Q"),
|
||||
Message(role="assistant", text="A"),
|
||||
Message(role="user", contents=["Q"]),
|
||||
Message(role="assistant", contents=["A"]),
|
||||
]
|
||||
encoded = serialize_value(original)
|
||||
decoded = deserialize_value(encoded)
|
||||
@@ -284,7 +284,7 @@ class TestSerializationRoundtrip:
|
||||
|
||||
def test_roundtrip_dict_of_objects(self) -> None:
|
||||
"""Test dict with typed values roundtrips (used for shared state)."""
|
||||
original = {"count": 42, "msg": Message(role="user", text="Hi")}
|
||||
original = {"count": 42, "msg": Message(role="user", contents=["Hi"])}
|
||||
encoded = serialize_value(original)
|
||||
decoded = deserialize_value(encoded)
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class TestAgentResponseHelpers:
|
||||
|
||||
# Simulate successful entity task completion
|
||||
entity_task.state = TaskState.SUCCEEDED
|
||||
entity_task.result = AgentResponse(messages=[Message(role="assistant", text="Test response")]).to_dict()
|
||||
entity_task.result = AgentResponse(messages=[Message(role="assistant", contents=["Test response"])]).to_dict()
|
||||
|
||||
# Clear pending_tasks to simulate that parent has processed the child
|
||||
task.pending_tasks.clear()
|
||||
@@ -197,7 +197,9 @@ class TestAgentResponseHelpers:
|
||||
|
||||
# Simulate successful entity task with JSON response
|
||||
entity_task.state = TaskState.SUCCEEDED
|
||||
entity_task.result = AgentResponse(messages=[Message(role="assistant", text='{"answer": "42"}')]).to_dict()
|
||||
entity_task.result = AgentResponse(
|
||||
messages=[Message(role="assistant", contents=['{"answer": "42"}'])]
|
||||
).to_dict()
|
||||
|
||||
# Clear pending_tasks to simulate that parent has processed the child
|
||||
task.pending_tasks.clear()
|
||||
|
||||
@@ -177,10 +177,10 @@ class TestBuildAgentExecutorResponse:
|
||||
# Create a previous response with conversation history
|
||||
previous = AgentExecutorResponse(
|
||||
executor_id="prev",
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", text="Previous")]),
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", contents=["Previous"])]),
|
||||
full_conversation=[
|
||||
Message(role="user", text="First"),
|
||||
Message(role="assistant", text="Previous"),
|
||||
Message(role="user", contents=["First"]),
|
||||
Message(role="assistant", contents=["Previous"]),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -211,8 +211,8 @@ class TestExtractMessageContent:
|
||||
"""Test extracting from AgentExecutorResponse with text."""
|
||||
response = AgentExecutorResponse(
|
||||
executor_id="exec",
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", text="Response text")]),
|
||||
full_conversation=[Message(role="assistant", text="Response text")],
|
||||
agent_response=AgentResponse(messages=[Message(role="assistant", contents=["Response text"])]),
|
||||
full_conversation=[Message(role="assistant", contents=["Response text"])],
|
||||
)
|
||||
|
||||
result = _extract_message_content(response)
|
||||
@@ -225,13 +225,13 @@ class TestExtractMessageContent:
|
||||
executor_id="exec",
|
||||
agent_response=AgentResponse(
|
||||
messages=[
|
||||
Message(role="user", text="First"),
|
||||
Message(role="assistant", text="Last message"),
|
||||
Message(role="user", contents=["First"]),
|
||||
Message(role="assistant", contents=["Last message"]),
|
||||
]
|
||||
),
|
||||
full_conversation=[
|
||||
Message(role="user", text="First"),
|
||||
Message(role="assistant", text="Last message"),
|
||||
Message(role="user", contents=["First"]),
|
||||
Message(role="assistant", contents=["Last message"]),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -244,8 +244,8 @@ class TestExtractMessageContent:
|
||||
"""Test extracting from AgentExecutorRequest."""
|
||||
request = AgentExecutorRequest(
|
||||
messages=[
|
||||
Message(role="user", text="First"),
|
||||
Message(role="user", text="Last request"),
|
||||
Message(role="user", contents=["First"]),
|
||||
Message(role="user", contents=["Last request"]),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Amazon Bedrock integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"boto3>=1.35.0,<2.0.0",
|
||||
"botocore>=1.35.0,<2.0.0",
|
||||
]
|
||||
|
||||
@@ -102,7 +102,7 @@ class ThreadItemConverter:
|
||||
|
||||
# If only text and no attachments, use text parameter for simplicity
|
||||
if text_content.strip() and not data_contents:
|
||||
user_message = Message(role="user", text=text_content.strip())
|
||||
user_message = Message(role="user", contents=[text_content.strip()])
|
||||
else:
|
||||
# Build contents list with both text and attachments
|
||||
contents: list[Content] = []
|
||||
@@ -116,7 +116,7 @@ class ThreadItemConverter:
|
||||
if item.quoted_text and is_last_message:
|
||||
quoted_context = Message(
|
||||
role="user",
|
||||
text=f"The user is referring to this in particular:\n{item.quoted_text}",
|
||||
contents=[f"The user is referring to this in particular:\n{item.quoted_text}"],
|
||||
)
|
||||
# Prepend quoted context before the main message
|
||||
messages.insert(0, quoted_context)
|
||||
@@ -211,9 +211,9 @@ class ThreadItemConverter:
|
||||
content="User's email: user@example.com",
|
||||
)
|
||||
message = converter.hidden_context_to_input(hidden_item)
|
||||
# Returns: Message(role=SYSTEM, text="<HIDDEN_CONTEXT>User's email: ...</HIDDEN_CONTEXT>")
|
||||
# Returns: Message(role=SYSTEM, contents=["<HIDDEN_CONTEXT>User's email: ...</HIDDEN_CONTEXT>"])
|
||||
"""
|
||||
return Message(role="system", text=f"<HIDDEN_CONTEXT>{item.content}</HIDDEN_CONTEXT>")
|
||||
return Message(role="system", contents=[f"<HIDDEN_CONTEXT>{item.content}</HIDDEN_CONTEXT>"])
|
||||
|
||||
def tag_to_message_content(self, tag: UserMessageTagContent) -> Content:
|
||||
"""Convert a ChatKit tag (@-mention) to Agent Framework content.
|
||||
@@ -292,7 +292,7 @@ class ThreadItemConverter:
|
||||
f"A message was displayed to the user that the following task was performed:\n<Task>\n{task_text}\n</Task>"
|
||||
)
|
||||
|
||||
return Message(role="user", text=text)
|
||||
return Message(role="user", contents=[text])
|
||||
|
||||
def workflow_to_input(self, item: WorkflowItem) -> Message | list[Message] | None:
|
||||
"""Convert a ChatKit WorkflowItem to Agent Framework Message(s).
|
||||
@@ -347,7 +347,7 @@ class ThreadItemConverter:
|
||||
f"<Task>\n{task_text}\n</Task>"
|
||||
)
|
||||
|
||||
messages.append(Message(role="user", text=text))
|
||||
messages.append(Message(role="user", contents=[text]))
|
||||
|
||||
return messages if messages else None
|
||||
|
||||
@@ -389,7 +389,7 @@ class ThreadItemConverter:
|
||||
try:
|
||||
widget_json = item.widget.model_dump_json(exclude_unset=True, exclude_none=True)
|
||||
text = f"The following graphical UI widget (id: {item.id}) was displayed to the user:{widget_json}"
|
||||
return Message(role="user", text=text)
|
||||
return Message(role="user", contents=[text])
|
||||
except Exception:
|
||||
# If JSON serialization fails, skip the widget
|
||||
return None
|
||||
@@ -415,7 +415,7 @@ class ThreadItemConverter:
|
||||
if not text_parts:
|
||||
return None
|
||||
|
||||
return Message(role="assistant", text="".join(text_parts))
|
||||
return Message(role="assistant", contents=["".join(text_parts)])
|
||||
|
||||
async def client_tool_call_to_input(self, item: ClientToolCallItem) -> Message | list[Message] | None:
|
||||
"""Convert a ChatKit ClientToolCallItem to Agent Framework Message(s).
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "OpenAI ChatKit integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -22,7 +22,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"openai-chatkit>=1.4.1,<2.0.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Claude Agent SDK integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"claude-agent-sdk>=0.1.36,<0.1.49",
|
||||
]
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Copilot Studio integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0b260330"
|
||||
version = "1.0.0b260402"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
@@ -23,7 +23,7 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-core>=1.0.0,<2",
|
||||
"microsoft-agents-copilotstudio-client>=0.3.1,<0.3.2",
|
||||
]
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ from agent_framework import BaseChatClient, ChatResponse, Message
|
||||
class MyClient(BaseChatClient):
|
||||
async def _inner_get_response(self, *, messages, options, **kwargs) -> ChatResponse:
|
||||
# Call your LLM here
|
||||
return ChatResponse(messages=[Message(role="assistant", text="Hi!")])
|
||||
return ChatResponse(messages=[Message(role="assistant", contents=["Hi!"])])
|
||||
|
||||
async def _inner_get_streaming_response(self, *, messages, options, **kwargs):
|
||||
yield ChatResponseUpdate(...)
|
||||
|
||||
@@ -13,11 +13,11 @@ Highlights
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
pip install agent-framework-core --pre
|
||||
pip install agent-framework-core
|
||||
# Optional: Add Azure AI Foundry integration
|
||||
pip install agent-framework-foundry --pre
|
||||
pip install agent-framework-foundry
|
||||
# Optional: Add OpenAI integration
|
||||
pip install agent-framework-openai --pre
|
||||
pip install agent-framework-openai
|
||||
```
|
||||
|
||||
Supported Platforms:
|
||||
|
||||
@@ -102,8 +102,6 @@ from ._middleware import (
|
||||
)
|
||||
from ._sessions import (
|
||||
AgentSession,
|
||||
BaseContextProvider, # type: ignore[reportDeprecated]
|
||||
BaseHistoryProvider, # type: ignore[reportDeprecated]
|
||||
ContextProvider,
|
||||
HistoryProvider,
|
||||
InMemoryHistoryProvider,
|
||||
@@ -280,9 +278,7 @@ __all__ = [
|
||||
"Annotation",
|
||||
"BaseAgent",
|
||||
"BaseChatClient",
|
||||
"BaseContextProvider",
|
||||
"BaseEmbeddingClient",
|
||||
"BaseHistoryProvider",
|
||||
"Case",
|
||||
"CharacterEstimatorTokenizer",
|
||||
"ChatAndFunctionMiddlewareTypes",
|
||||
|
||||
@@ -253,7 +253,8 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
|
||||
else:
|
||||
# Non-streaming implementation
|
||||
return ChatResponse(
|
||||
messages=[Message(role="assistant", text="Hello!")], response_id="custom-response"
|
||||
messages=[Message(role="assistant", contents=["Hello!"])],
|
||||
response_id="custom-response",
|
||||
)
|
||||
|
||||
|
||||
@@ -261,9 +262,9 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
|
||||
client = CustomChatClient()
|
||||
|
||||
# Use the client to get responses
|
||||
response = await client.get_response([Message(role="user", text="Hello, how are you?")])
|
||||
response = await client.get_response([Message(role="user", contents=["Hello, how are you?"])])
|
||||
# Or stream responses
|
||||
async for update in client.get_response([Message(role="user", text="Hello!")], stream=True):
|
||||
async for update in client.get_response([Message(role="user", contents=["Hello!"])], stream=True):
|
||||
print(update)
|
||||
"""
|
||||
|
||||
|
||||
@@ -877,7 +877,7 @@ class ToolResultCompactionStrategy:
|
||||
insertion_index = starts.get(group_id, 0)
|
||||
summary_message = Message(
|
||||
role="assistant",
|
||||
text=summary_text,
|
||||
contents=[summary_text],
|
||||
message_id=summary_id,
|
||||
additional_properties={
|
||||
GROUP_ANNOTATION_KEY: summary_annotation,
|
||||
@@ -1015,10 +1015,10 @@ class SummarizationStrategy:
|
||||
try:
|
||||
summary_response: ChatResponse[None] = await self.client.get_response(
|
||||
[
|
||||
Message(role="system", text=self.prompt),
|
||||
Message(role="system", contents=[self.prompt]),
|
||||
Message(
|
||||
role="user",
|
||||
text=_format_messages_for_summary(messages_to_summarize),
|
||||
contents=[_format_messages_for_summary(messages_to_summarize)],
|
||||
),
|
||||
],
|
||||
stream=False,
|
||||
@@ -1044,7 +1044,7 @@ class SummarizationStrategy:
|
||||
|
||||
summary_message = Message(
|
||||
role="assistant",
|
||||
text=summary_text,
|
||||
contents=[summary_text],
|
||||
message_id=summary_id,
|
||||
additional_properties={
|
||||
GROUP_ANNOTATION_KEY: summary_annotation,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user