mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Fix model override bug and add client REPL sample
- InputConverter: stop propagating request.Model to ChatOptions.ModelId Hosted agents use their own model; client-provided model values like 'hosted-agent' were being passed through and causing server errors. - Add FoundryResponsesRepl sample: interactive CLI client that connects to a Foundry Responses endpoint using ResponsesClient.AsAIAgent() - Bump package version to 0.9.0-hosted.260403.1 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<Solution>
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<BuildType Name="Debug" />
|
||||
<BuildType Name="Publish" />
|
||||
@@ -260,7 +260,9 @@
|
||||
<Project Path="samples/03-workflows/_StartHere/06_MixedWorkflowAgentsAndExecutors/06_MixedWorkflowAgentsAndExecutors.csproj" />
|
||||
<Project Path="samples/03-workflows/_StartHere/07_WriterCriticWorkflow/07_WriterCriticWorkflow.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Samples/04-hosting/" />
|
||||
<Folder Name="/Samples/04-hosting/">
|
||||
<Project Path="samples/04-hosting/FoundryResponsesRepl/FoundryResponsesRepl.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Samples/04-hosting/FoundryResponsesHosting/">
|
||||
<Project Path="samples/04-hosting/FoundryResponsesHosting/FoundryResponsesHosting.csproj" />
|
||||
</Folder>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' == ''">$(VersionPrefix)-preview.260402.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleased)' == 'true'">$(VersionPrefix)</PackageVersion>
|
||||
<!-- Branch-specific override to distinguish from mainline packages -->
|
||||
<PackageVersion>0.9.0-hosted.260402.2</PackageVersion>
|
||||
<PackageVersion>0.9.0-hosted.260403.1</PackageVersion>
|
||||
<GitTag>1.0.0</GitTag>
|
||||
|
||||
<Configurations>Debug;Release;Publish</Configurations>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
|
||||
<NoWarn>$(NoWarn);NU1903;NU1605</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Core" />
|
||||
<PackageReference Include="OpenAI" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,98 @@
|
||||
// Foundry Responses Client REPL
|
||||
//
|
||||
// Connects to a Foundry Responses agent running on a given endpoint
|
||||
// and provides an interactive multi-turn chat REPL.
|
||||
//
|
||||
// Usage:
|
||||
// dotnet run (connects to http://localhost:8088)
|
||||
// dotnet run -- --endpoint http://localhost:9090
|
||||
// dotnet run -- --endpoint https://my-foundry-project.services.ai.azure.com
|
||||
//
|
||||
// The endpoint should be running a Foundry Responses server (POST /responses).
|
||||
|
||||
using System.ClientModel;
|
||||
using Microsoft.Agents.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Responses;
|
||||
|
||||
// ── Parse args ────────────────────────────────────────────────────────────────
|
||||
|
||||
string endpointUrl = "http://localhost:8088";
|
||||
for (int i = 0; i < args.Length - 1; i++)
|
||||
{
|
||||
if (args[i] is "--endpoint" or "-e")
|
||||
{
|
||||
endpointUrl = args[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// ── Create an agent-framework agent backed by the remote Responses endpoint ──
|
||||
|
||||
// The OpenAI SDK's ResponsesClient can target any OpenAI-compatible endpoint.
|
||||
// We use a dummy API key since our local server doesn't require auth.
|
||||
var credential = new ApiKeyCredential(
|
||||
Environment.GetEnvironmentVariable("RESPONSES_API_KEY") ?? "no-key-needed");
|
||||
|
||||
var openAiClient = new OpenAIClient(
|
||||
credential,
|
||||
new OpenAIClientOptions { Endpoint = new Uri(endpointUrl) });
|
||||
|
||||
ResponsesClient responsesClient = openAiClient.GetResponsesClient();
|
||||
|
||||
// Wrap as an agent-framework AIAgent via the OpenAI extensions.
|
||||
// We pass an empty model since hosted agents use their own model configuration.
|
||||
AIAgent agent = responsesClient.AsAIAgent(
|
||||
model: "",
|
||||
name: "remote-agent");
|
||||
|
||||
// Create a session so multi-turn context is preserved via previous_response_id
|
||||
AgentSession session = await agent.CreateSessionAsync();
|
||||
|
||||
// ── REPL ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.WriteLine("╔══════════════════════════════════════════════════════════╗");
|
||||
Console.WriteLine("║ Foundry Responses Client REPL ║");
|
||||
Console.WriteLine($"║ Connected to: {endpointUrl,-41}║");
|
||||
Console.WriteLine("║ Type a message or 'quit' to exit ║");
|
||||
Console.WriteLine("╚══════════════════════════════════════════════════════════╝");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.Write("You> ");
|
||||
Console.ResetColor();
|
||||
|
||||
string? input = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(input)) continue;
|
||||
if (input.Equals("quit", StringComparison.OrdinalIgnoreCase) ||
|
||||
input.Equals("exit", StringComparison.OrdinalIgnoreCase))
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Write("Agent> ");
|
||||
Console.ResetColor();
|
||||
|
||||
// Stream the response token-by-token
|
||||
await foreach (var update in agent.RunStreamingAsync(input, session))
|
||||
{
|
||||
Console.Write(update);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("Goodbye!");
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"FoundryResponsesRepl": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:61980;http://localhost:61981"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,10 @@ internal static class InputConverter
|
||||
Temperature = (float?)request.Temperature,
|
||||
TopP = (float?)request.TopP,
|
||||
MaxOutputTokens = (int?)request.MaxOutputTokens,
|
||||
ModelId = request.Model,
|
||||
// Note: We intentionally do NOT set ModelId from request.Model here.
|
||||
// The hosted agent already has its own model configured, and passing
|
||||
// the client-provided model would override it (causing failures when
|
||||
// clients send placeholder values like "hosted-agent").
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ public class InputConverterTests
|
||||
Assert.Equal(0.7f, options.Temperature);
|
||||
Assert.Equal(0.9f, options.TopP);
|
||||
Assert.Equal(1000, options.MaxOutputTokens);
|
||||
Assert.Equal("gpt-4o", options.ModelId);
|
||||
Assert.Null(options.ModelId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -659,12 +659,13 @@ public class InputConverterTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertToChatOptions_ModelId_SetFromRequest()
|
||||
public void ConvertToChatOptions_ModelId_NotSetFromRequest()
|
||||
{
|
||||
var request = AzureAIAgentServerResponsesModelFactory.CreateResponse(model: "my-model");
|
||||
|
||||
var options = InputConverter.ConvertToChatOptions(request);
|
||||
|
||||
Assert.Equal("my-model", options.ModelId);
|
||||
// Model from the request is intentionally NOT propagated — the hosted agent uses its own model.
|
||||
Assert.Null(options.ModelId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user