chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.Projects" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net10.0'))">
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
|
||||
<PackageReference Include="System.Linq.AsyncEnumerable" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Hosting.A2A.AspNetCore\Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Hosting.A2A\Microsoft.Agents.AI.Hosting.A2A.csproj" />
|
||||
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.A2A\Microsoft.Agents.AI.A2A.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,85 @@
|
||||
### Each A2A agent is available at a different host address
|
||||
@hostInvoice = http://localhost:5000
|
||||
@hostPolicy = http://localhost:5001
|
||||
@hostLogistics = http://localhost:5002
|
||||
|
||||
### Query agent card for the invoice agent
|
||||
GET {{hostInvoice}}/.well-known/agent-card.json
|
||||
|
||||
### Send a message to the invoice agent
|
||||
POST {{hostInvoice}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": "1",
|
||||
"jsonrpc": "2.0",
|
||||
"method": "message/send",
|
||||
"params": {
|
||||
"id": "12345",
|
||||
"message": {
|
||||
"kind": "message",
|
||||
"role": "user",
|
||||
"messageId": "msg_1",
|
||||
"parts": [
|
||||
{
|
||||
"kind": "text",
|
||||
"text": "Show me all invoices for Contoso?"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### Query agent card for the policy agent
|
||||
GET {{hostPolicy}}/.well-known/agent-card.json
|
||||
|
||||
### Send a message to the policy agent
|
||||
POST {{hostPolicy}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": "1",
|
||||
"jsonrpc": "2.0",
|
||||
"method": "message/send",
|
||||
"params": {
|
||||
"id": "12345",
|
||||
"message": {
|
||||
"kind": "message",
|
||||
"role": "user",
|
||||
"messageId": "msg_1",
|
||||
"parts": [
|
||||
{
|
||||
"kind": "text",
|
||||
"text": "What is the policy for short shipments?"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### Query agent card for the logistics agent
|
||||
GET {{hostLogistics}}/.well-known/agent-card.json
|
||||
|
||||
### Send a message to the logistics agent
|
||||
POST {{hostLogistics}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": "1",
|
||||
"jsonrpc": "2.0",
|
||||
"method": "message/send",
|
||||
"params": {
|
||||
"id": "12345",
|
||||
"message": {
|
||||
"kind": "message",
|
||||
"role": "user",
|
||||
"messageId": "msg_1",
|
||||
"parts": [
|
||||
{
|
||||
"kind": "text",
|
||||
"text": "What is the status for SHPMT-SAP-001?"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using A2A;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Agents;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Chat;
|
||||
using AgentCard = A2A.AgentCard;
|
||||
|
||||
namespace A2AServer;
|
||||
|
||||
internal static class HostAgentFactory
|
||||
{
|
||||
internal static async Task<(AIAgent, AgentCard)> CreateFoundryHostAgentAsync(string agentType, string model, string endpoint, string agentName, string[] agentUrls, IList<AITool>? tools = null)
|
||||
{
|
||||
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
|
||||
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
|
||||
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
ProjectsAgentRecord agentRecord = await aiProjectClient.AgentAdministrationClient.GetAgentAsync(agentName);
|
||||
AIAgent agent = aiProjectClient.AsAIAgent(agentRecord, tools: tools);
|
||||
|
||||
AgentCard agentCard = agentType.ToUpperInvariant() switch
|
||||
{
|
||||
"INVOICE" => GetInvoiceAgentCard(agentUrls),
|
||||
"POLICY" => GetPolicyAgentCard(agentUrls),
|
||||
"LOGISTICS" => GetLogisticsAgentCard(agentUrls),
|
||||
_ => throw new ArgumentException($"Unsupported agent type: {agentType}"),
|
||||
};
|
||||
|
||||
return new(agent, agentCard);
|
||||
}
|
||||
|
||||
internal static async Task<(AIAgent, AgentCard)> CreateChatCompletionHostAgentAsync(string agentType, string model, string apiKey, string name, string instructions, string[] agentUrls, IList<AITool>? tools = null)
|
||||
{
|
||||
AIAgent agent = new OpenAIClient(apiKey)
|
||||
.GetChatClient(model)
|
||||
.AsAIAgent(instructions, name, tools: tools);
|
||||
|
||||
AgentCard agentCard = agentType.ToUpperInvariant() switch
|
||||
{
|
||||
"INVOICE" => GetInvoiceAgentCard(agentUrls),
|
||||
"POLICY" => GetPolicyAgentCard(agentUrls),
|
||||
"LOGISTICS" => GetLogisticsAgentCard(agentUrls),
|
||||
_ => throw new ArgumentException($"Unsupported agent type: {agentType}"),
|
||||
};
|
||||
|
||||
return new(agent, agentCard);
|
||||
}
|
||||
|
||||
#region private
|
||||
private static AgentCard GetInvoiceAgentCard(string[] agentUrls)
|
||||
{
|
||||
var capabilities = new AgentCapabilities()
|
||||
{
|
||||
Streaming = false,
|
||||
PushNotifications = false,
|
||||
};
|
||||
|
||||
var invoiceQuery = new A2A.AgentSkill()
|
||||
{
|
||||
Id = "id_invoice_agent",
|
||||
Name = "InvoiceQuery",
|
||||
Description = "Handles requests relating to invoices.",
|
||||
Tags = ["invoice", "semantic-kernel"],
|
||||
Examples =
|
||||
[
|
||||
"List the latest invoices for Contoso.",
|
||||
],
|
||||
};
|
||||
|
||||
return new()
|
||||
{
|
||||
Name = "InvoiceAgent",
|
||||
Description = "Handles requests relating to invoices.",
|
||||
Version = "1.0.0",
|
||||
DefaultInputModes = ["text"],
|
||||
DefaultOutputModes = ["text"],
|
||||
Capabilities = capabilities,
|
||||
Skills = [invoiceQuery],
|
||||
SupportedInterfaces = CreateAgentInterfaces(agentUrls)
|
||||
};
|
||||
}
|
||||
|
||||
private static AgentCard GetPolicyAgentCard(string[] agentUrls)
|
||||
{
|
||||
var capabilities = new AgentCapabilities()
|
||||
{
|
||||
Streaming = false,
|
||||
PushNotifications = false,
|
||||
};
|
||||
|
||||
var policyQuery = new A2A.AgentSkill()
|
||||
{
|
||||
Id = "id_policy_agent",
|
||||
Name = "PolicyAgent",
|
||||
Description = "Handles requests relating to policies and customer communications.",
|
||||
Tags = ["policy", "semantic-kernel"],
|
||||
Examples =
|
||||
[
|
||||
"What is the policy for short shipments?",
|
||||
],
|
||||
};
|
||||
|
||||
return new AgentCard()
|
||||
{
|
||||
Name = "PolicyAgent",
|
||||
Description = "Handles requests relating to policies and customer communications.",
|
||||
Version = "1.0.0",
|
||||
DefaultInputModes = ["text"],
|
||||
DefaultOutputModes = ["text"],
|
||||
Capabilities = capabilities,
|
||||
Skills = [policyQuery],
|
||||
SupportedInterfaces = CreateAgentInterfaces(agentUrls)
|
||||
};
|
||||
}
|
||||
|
||||
private static AgentCard GetLogisticsAgentCard(string[] agentUrls)
|
||||
{
|
||||
var capabilities = new AgentCapabilities()
|
||||
{
|
||||
Streaming = false,
|
||||
PushNotifications = false,
|
||||
};
|
||||
|
||||
var logisticsQuery = new A2A.AgentSkill()
|
||||
{
|
||||
Id = "id_logistics_agent",
|
||||
Name = "LogisticsQuery",
|
||||
Description = "Handles requests relating to logistics.",
|
||||
Tags = ["logistics", "semantic-kernel"],
|
||||
Examples =
|
||||
[
|
||||
"What is the status for SHPMT-SAP-001",
|
||||
],
|
||||
};
|
||||
|
||||
return new AgentCard()
|
||||
{
|
||||
Name = "LogisticsAgent",
|
||||
Description = "Handles requests relating to logistics.",
|
||||
Version = "1.0.0",
|
||||
DefaultInputModes = ["text"],
|
||||
DefaultOutputModes = ["text"],
|
||||
Capabilities = capabilities,
|
||||
Skills = [logisticsQuery],
|
||||
SupportedInterfaces = CreateAgentInterfaces(agentUrls)
|
||||
};
|
||||
}
|
||||
|
||||
private static List<AgentInterface> CreateAgentInterfaces(string[] agentUrls)
|
||||
{
|
||||
List<AgentInterface> agentInterfaces = [];
|
||||
|
||||
agentInterfaces.AddRange(agentUrls.Select(url => new AgentInterface
|
||||
{
|
||||
Url = url,
|
||||
ProtocolBinding = ProtocolBindingNames.JsonRpc,
|
||||
ProtocolVersion = "1.0",
|
||||
}));
|
||||
|
||||
agentInterfaces.AddRange(agentUrls.Select(url => new AgentInterface
|
||||
{
|
||||
Url = url,
|
||||
ProtocolBinding = ProtocolBindingNames.HttpJson,
|
||||
ProtocolVersion = "1.0",
|
||||
}));
|
||||
|
||||
return agentInterfaces;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace A2A;
|
||||
|
||||
/// <summary>
|
||||
/// A simple invoice plugin that returns mock data.
|
||||
/// </summary>
|
||||
public class Product
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public decimal Price { get; set; } // Price per unit
|
||||
|
||||
public Product(string name, int quantity, decimal price)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Quantity = quantity;
|
||||
this.Price = price;
|
||||
}
|
||||
|
||||
public decimal TotalPrice() => this.Quantity * this.Price; // Total price for this product
|
||||
}
|
||||
|
||||
public class Invoice
|
||||
{
|
||||
public string TransactionId { get; set; }
|
||||
public string InvoiceId { get; set; }
|
||||
public string CompanyName { get; set; }
|
||||
public DateTime InvoiceDate { get; set; }
|
||||
public List<Product> Products { get; set; } // List of products
|
||||
|
||||
public Invoice(string transactionId, string invoiceId, string companyName, DateTime invoiceDate, List<Product> products)
|
||||
{
|
||||
this.TransactionId = transactionId;
|
||||
this.InvoiceId = invoiceId;
|
||||
this.CompanyName = companyName;
|
||||
this.InvoiceDate = invoiceDate;
|
||||
this.Products = products;
|
||||
}
|
||||
|
||||
public decimal TotalInvoicePrice() => this.Products.Sum(product => product.TotalPrice()); // Total price of all products in the invoice
|
||||
}
|
||||
|
||||
public class InvoiceQuery
|
||||
{
|
||||
private readonly List<Invoice> _invoices;
|
||||
|
||||
public InvoiceQuery()
|
||||
{
|
||||
// Extended mock data with quantities and prices
|
||||
this._invoices =
|
||||
[
|
||||
new("TICKET-XYZ987", "INV789", "Contoso", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 150, 10.00m),
|
||||
new("Hats", 200, 15.00m),
|
||||
new("Glasses", 300, 5.00m)
|
||||
]),
|
||||
new("TICKET-XYZ111", "INV111", "XStore", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 2500, 12.00m),
|
||||
new("Hats", 1500, 8.00m),
|
||||
new("Glasses", 200, 20.00m)
|
||||
]),
|
||||
new("TICKET-XYZ222", "INV222", "Cymbal Direct", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 1200, 14.00m),
|
||||
new("Hats", 800, 7.00m),
|
||||
new("Glasses", 500, 25.00m)
|
||||
]),
|
||||
new("TICKET-XYZ333", "INV333", "Contoso", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 400, 11.00m),
|
||||
new("Hats", 600, 15.00m),
|
||||
new("Glasses", 700, 5.00m)
|
||||
]),
|
||||
new("TICKET-XYZ444", "INV444", "XStore", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 800, 10.00m),
|
||||
new("Hats", 500, 18.00m),
|
||||
new("Glasses", 300, 22.00m)
|
||||
]),
|
||||
new("TICKET-XYZ555", "INV555", "Cymbal Direct", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 1100, 9.00m),
|
||||
new("Hats", 900, 12.00m),
|
||||
new("Glasses", 1200, 15.00m)
|
||||
]),
|
||||
new("TICKET-XYZ666", "INV666", "Contoso", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 2500, 8.00m),
|
||||
new("Hats", 1200, 10.00m),
|
||||
new("Glasses", 1000, 6.00m)
|
||||
]),
|
||||
new("TICKET-XYZ777", "INV777", "XStore", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 1900, 13.00m),
|
||||
new("Hats", 1300, 16.00m),
|
||||
new("Glasses", 800, 19.00m)
|
||||
]),
|
||||
new("TICKET-XYZ888", "INV888", "Cymbal Direct", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 2200, 11.00m),
|
||||
new("Hats", 1700, 8.50m),
|
||||
new("Glasses", 600, 21.00m)
|
||||
]),
|
||||
new("TICKET-XYZ999", "INV999", "Contoso", GetRandomDateWithinLastTwoMonths(),
|
||||
[
|
||||
new("T-Shirts", 1400, 10.50m),
|
||||
new("Hats", 1100, 9.00m),
|
||||
new("Glasses", 950, 12.00m)
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
public static DateTime GetRandomDateWithinLastTwoMonths()
|
||||
{
|
||||
// Get the current date and time
|
||||
DateTime endDate = DateTime.UtcNow;
|
||||
|
||||
// Calculate the start date, which is two months before the current date
|
||||
DateTime startDate = endDate.AddMonths(-2);
|
||||
|
||||
// Generate a random number of days between 0 and the total number of days in the range
|
||||
int totalDays = (endDate - startDate).Days;
|
||||
int randomDays = Random.Shared.Next(0, totalDays + 1); // +1 to include the end date
|
||||
|
||||
// Return the random date
|
||||
return startDate.AddDays(randomDays);
|
||||
}
|
||||
|
||||
[Description("Retrieves invoices for the specified company and optionally within the specified time range")]
|
||||
public IEnumerable<Invoice> QueryInvoices(string companyName, DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
var query = this._invoices.Where(i => i.CompanyName.Equals(companyName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (startDate.HasValue)
|
||||
{
|
||||
query = query.Where(i => i.InvoiceDate >= startDate.Value);
|
||||
}
|
||||
|
||||
if (endDate.HasValue)
|
||||
{
|
||||
query = query.Where(i => i.InvoiceDate <= endDate.Value);
|
||||
}
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
[Description("Retrieves invoice using the transaction id")]
|
||||
public IEnumerable<Invoice> QueryByTransactionId(string transactionId)
|
||||
{
|
||||
var query = this._invoices.Where(i => i.TransactionId.Equals(transactionId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
[Description("Retrieves invoice using the invoice id")]
|
||||
public IEnumerable<Invoice> QueryByInvoiceId(string invoiceId)
|
||||
{
|
||||
var query = this._invoices.Where(i => i.InvoiceId.Equals(invoiceId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
using A2A;
|
||||
using A2A.AspNetCore;
|
||||
using A2AServer;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
string agentName = string.Empty;
|
||||
string agentType = string.Empty;
|
||||
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (args[i].Equals("--agentName", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
|
||||
{
|
||||
agentName = args[++i];
|
||||
}
|
||||
else if (args[i].Equals("--agentType", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
|
||||
{
|
||||
agentType = args[++i];
|
||||
}
|
||||
}
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddHttpClient().AddLogging();
|
||||
|
||||
IConfigurationRoot configuration = new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<Program>()
|
||||
.Build();
|
||||
|
||||
string? apiKey = configuration["OPENAI_API_KEY"];
|
||||
string model = configuration["OPENAI_CHAT_MODEL_NAME"] ?? "gpt-5.4-mini";
|
||||
string? endpoint = configuration["FOUNDRY_PROJECT_ENDPOINT"];
|
||||
string[] agentUrls = (builder.Configuration["urls"] ?? "http://localhost:5000").Split(';');
|
||||
|
||||
var invoiceQueryPlugin = new InvoiceQuery();
|
||||
IList<AITool> tools =
|
||||
[
|
||||
AIFunctionFactory.Create(invoiceQueryPlugin.QueryInvoices),
|
||||
AIFunctionFactory.Create(invoiceQueryPlugin.QueryByTransactionId),
|
||||
AIFunctionFactory.Create(invoiceQueryPlugin.QueryByInvoiceId)
|
||||
];
|
||||
|
||||
AIAgent hostA2AAgent;
|
||||
AgentCard hostA2AAgentCard;
|
||||
|
||||
if (!string.IsNullOrEmpty(endpoint) && !string.IsNullOrEmpty(agentName))
|
||||
{
|
||||
(hostA2AAgent, hostA2AAgentCard) = agentType.ToUpperInvariant() switch
|
||||
{
|
||||
"INVOICE" => await HostAgentFactory.CreateFoundryHostAgentAsync(agentType, model, endpoint, agentName, agentUrls, tools),
|
||||
"POLICY" => await HostAgentFactory.CreateFoundryHostAgentAsync(agentType, model, endpoint, agentName, agentUrls),
|
||||
"LOGISTICS" => await HostAgentFactory.CreateFoundryHostAgentAsync(agentType, model, endpoint, agentName, agentUrls),
|
||||
_ => throw new ArgumentException($"Unsupported agent type: {agentType}"),
|
||||
};
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(apiKey))
|
||||
{
|
||||
(hostA2AAgent, hostA2AAgentCard) = agentType.ToUpperInvariant() switch
|
||||
{
|
||||
"INVOICE" => await HostAgentFactory.CreateChatCompletionHostAgentAsync(
|
||||
agentType, model, apiKey, "InvoiceAgent",
|
||||
"""
|
||||
You specialize in handling queries related to invoices.
|
||||
""", agentUrls, tools),
|
||||
"POLICY" => await HostAgentFactory.CreateChatCompletionHostAgentAsync(
|
||||
agentType, model, apiKey, "PolicyAgent",
|
||||
"""
|
||||
You specialize in handling queries related to policies and customer communications.
|
||||
|
||||
Always reply with exactly this text:
|
||||
|
||||
Policy: Short Shipment Dispute Handling Policy V2.1
|
||||
|
||||
Summary: "For short shipments reported by customers, first verify internal shipment records
|
||||
(SAP) and physical logistics scan data (BigQuery). If discrepancy is confirmed and logistics data
|
||||
shows fewer items packed than invoiced, issue a credit for the missing items. Document the
|
||||
resolution in SAP CRM and notify the customer via email within 2 business days, referencing the
|
||||
original invoice and the credit memo number. Use the 'Formal Credit Notification' email
|
||||
template."
|
||||
""", agentUrls),
|
||||
"LOGISTICS" => await HostAgentFactory.CreateChatCompletionHostAgentAsync(
|
||||
agentType, model, apiKey, "LogisticsAgent",
|
||||
"""
|
||||
You specialize in handling queries related to logistics.
|
||||
|
||||
Always reply with exactly:
|
||||
|
||||
Shipment number: SHPMT-SAP-001
|
||||
Item: TSHIRT-RED-L
|
||||
Quantity: 900
|
||||
""", agentUrls),
|
||||
_ => throw new ArgumentException($"Unsupported agent type: {agentType}"),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Either A2AServer:ApiKey or A2AServer:ConnectionString & agentName must be provided");
|
||||
}
|
||||
|
||||
// IMPORTANT: In production, register a SessionIsolationKeyProvider to isolate sessions by authenticated caller.
|
||||
// Without this, contextId alone is the session key — any caller who knows a contextId can access that session.
|
||||
// Example using claims-based identity:
|
||||
// builder.Services.UseClaimsBasedSessionIsolation(new() { ClaimType = ClaimTypes.NameIdentifier });
|
||||
|
||||
// By default, NoopAgentSessionStore is used — sessions are not persisted across requests.
|
||||
// To enable multi-turn conversations, register a session store explicitly, e.g.:
|
||||
// builder.Services.AddKeyedSingleton<AgentSessionStore>(hostA2AAgent.Name, new InMemoryAgentSessionStore());
|
||||
|
||||
builder.AddA2AServer(hostA2AAgent);
|
||||
|
||||
var app = builder.Build();
|
||||
app.MapA2AHttpJson(hostA2AAgent, "/");
|
||||
app.MapA2AJsonRpc(hostA2AAgent, "/");
|
||||
|
||||
app.MapWellKnownAgentCard(hostA2AAgentCard);
|
||||
|
||||
await app.RunAsync();
|
||||
Reference in New Issue
Block a user