Add Responses web-service sample + integration tests for C# SDK#681
Draft
Add Responses web-service sample + integration tests for C# SDK#681
Conversation
Implements `OpenAIResponsesClient` for the OpenAI Responses API surface in the C# SDK, mirroring the Python (#670) and JS (#671) SDKs and incorporating their resolved review feedback up front. - New `Microsoft.AI.Foundry.Local.OpenAI.OpenAIResponsesClient` (HTTP-only, `HttpClient`-based, no FFI) - Non-streaming + IAsyncEnumerable streaming (`Channel<T>` SSE pipeline) - Full CRUD: `GetAsync`, `DeleteAsync`, `CancelAsync`, `GetInputItemsAsync`, `ListAsync(limit, order, after)` - Polymorphic content parts and response items via `[JsonPolymorphic]` + source-gen context - Streaming events for lifecycle, output, text deltas, function calls, and reasoning - Vision helpers: `InputImageContent.FromFile/FromUrl/FromBytes` - `FoundryLocalManager.GetResponsesClient(modelId?)` and `IModel.GetResponsesClientAsync` Pre-applied PR review feedback from the Python and JS PRs: - `Settings.Store` defaults to `null` (omit) instead of forcing `store=true` - `InputImageContent.MediaType` is optional; unknown extensions omit the field so the server infers - `InputImageContent.FromFile` throws `FileNotFoundException` on missing path - `HttpClient.Timeout = Timeout.InfiniteTimeSpan`; callers use `CancellationToken` for deadlines (avoids 100s default cutting off SSE) - `ListAsync` accepts `limit`, `order`, `after`; `ListResponsesResult` exposes `first_id`, `last_id`, `has_more` - `InputImageContent.Validate()` enforces mutual exclusivity of `ImageUrl` / `ImageData` at request build time - BMP supported in `DetectMediaType` alongside png/jpg/jpeg/gif/webp - Uses shared `FoundryLocalException` for transport/parse errors, no dedicated `ResponsesException` Tests: 22 unit tests (mocked HTTP) + integration tests gated on a running service. `dotnet build sdk/cs/src` clean; all Responses tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Replaces the hand-rolled Responses DTO/SSE/serialization layer with the official `OpenAI` 2.10.0 NuGet package's `OpenAI.Responses.ResponsesClient` while keeping `Microsoft.AI.Foundry.Local.OpenAIResponsesClient` as the public Foundry Local-shaped wrapper. - Public surface unchanged: `OpenAIResponsesClient` ctor, `Settings`, `CreateAsync` / `CreateStreamingAsync` / `GetAsync` / `DeleteAsync` / `CancelAsync` / `GetInputItemsAsync` / `ListAsync` - Endpoints come from `OpenAI.Responses.ResponsesClient` configured with the Foundry Local web service URL via `OpenAIClientOptions.Endpoint`; only `ListAsync` keeps a small `HttpClient` shim for Foundry Local's list-responses extension (the official client doesn't expose that yet) - `ResponsesClientSettings` keeps the same Foundry Local-shaped knobs but applies them onto official `CreateResponseOptions` (`MaxOutputTokenCount`, `StoredOutputEnabled`, `ParallelToolCallsEnabled`, etc.) - New `ResponseContentPartHelpers` produces official `ResponseContentPart` instances for vision: file (auto-detect MIME, throws on missing/unknown extension), bytes (data URI), and URL - Vision now uses official OpenAI shape (`input_image` + `image_url` data URI) rather than Foundry Local's `image_data` + `media_type` extension - Deleted the hand-rolled `ResponsesTypes.cs` polymorphic DTO surface and the source-gen `ResponsesSerializationContext` Bug fixes: - Avoid `op_Implicit(null)` on `ResponseImageDetailLevel` and `ResponseItemCollectionOrder` value-type structs when callers pass null/empty options - Map `ClientResultException` -> `FoundryLocalException` consistently across CRUD methods Tests: - Unit tests rewritten for the official surface; cover settings defaults, input validation, image helper factories, MIME detection, and `ListResponsesResult.FromJson` parsing - Integration tests updated to use `CreateResponseOptions` / `ResponseItem` / `StreamingResponseUpdate` types - `dotnet build` clean; all Responses tests pass (51/61 overall, the 10 failures are pre-existing `EmbeddingClientTests` infra) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This PR pivots away from adding a Responses API client to the C# SDK and instead adds a focused sample and integration tests that exercise the OpenAI Responses API against the Foundry Local web service, mirroring how `samples/cs/foundry-local-web-server` calls chat completions. Reverted on this branch: - `sdk/cs/src/OpenAI/ResponsesClient.cs` and `ResponsesTypes.cs` (deleted) - `ResponsesClientSettings`, factory methods, `IModel.GetResponsesClientAsync`, `Detail/Model.cs` and `Detail/ModelVariant.cs` additions - `OpenAI` PackageReference on the SDK project - `Utils.cs` test-side change - Earlier `ResponsesClientTests.cs` and `ResponsesIntegrationTests.cs` Added: - `samples/cs/responses-foundry-local-web-server/` (Program.cs + csproj) - Loads `qwen2.5-0.5b` via `FoundryLocalManager`, starts the web service - Uses `OpenAI.Responses.ResponsesClient` (official OpenAI .NET package, 2.10.0) pointed at `<service-url>/v1` - Demonstrates non-streaming, streaming (`StreamingResponseOutputTextDeltaUpdate`), and a full function-calling round-trip via `previous_response_id` - `sdk/cs/test/FoundryLocal.Tests/ResponsesIntegrationTests.cs` - Three integration tests: NonStreaming, Streaming, and FunctionCalling round-trip - Skips automatically when `qwen2.5-0.5b` is not in the local cache - Cleans up: stops web service and unloads model in `[After(Class)]` - Bumped centrally-managed `OpenAI` package version 2.5.0 -> 2.10.0 (needed for stable `ResponsesClient`); added `OpenAI 2.10.0` to test project - Updated `samples/cs/README.md` with a row for the new sample Validation: - `dotnet build samples/cs/responses-foundry-local-web-server -c Release`: 0 warnings, 0 errors - `dotnet build sdk/cs/test/FoundryLocal.Tests -c Release`: 0 errors (2 unrelated pre-existing nullable warnings) - Local test run is currently blocked by a pre-existing `GetRepoRoot()` issue in worktrees (`Utils.AssemblyInit` throws when `.git` is a file rather than a directory); affects every test in the project, not Responses-specific Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… locally Cross-references the JS Responses sample/tests (PR #671) to keep the C# pattern consistent. Sample (samples/cs/responses-foundry-local-web-server): - Added README.md mirroring the JS sample (prereqs, run, expected output, troubleshooting) - Tool now uses an empty-params schema (matches JS PR), which the small qwen2.5-0.5b reliably calls - Single ResponseTool reused on the follow-up call; deterministic options (Temperature=0, MaxOutputTokenCount=64) - Cleanup wrapped in try/finally so StopWebService/Unload run even on exceptions Integration tests (sdk/cs/test/FoundryLocal.Tests/ResponsesIntegrationTests.cs): - Mirrors the JS suite responsesWebService.test.ts (NonStreaming, Streaming, FunctionCalling) - Skips when Utils.IsRunningInCI() is true and when qwen2.5-0.5b is not pre-cached - Streaming asserts response.created, response.output_text.delta, and response.completed events (parity with JS) - Tool-calling test reuses the same get_weather empty-params definition - Streaming options include StreamingEnabled = true so the official ResponsesClient allows the call Pre-existing fix (test infra only): - Utils.GetRepoRoot() previously failed in git worktrees because .git is a file, not a directory; now accepts either form. This unblocked test execution in worktree checkouts. Validation: - dotnet build samples/cs/responses-foundry-local-web-server -c Release: 0 warnings, 0 errors - dotnet build sdk/cs/test/FoundryLocal.Tests -c Release: 0 errors - dotnet test --filter ResponsesIntegration: all 3 Responses tests pass end-to-end against a real local model - The 10 remaining failures across the project are pre-existing EmbeddingClientTests infra (different model not cached), unrelated to this PR Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pivoted approach: The C# SDK does not gain a new Responses API client surface. Instead, this PR adds a focused sample and integration tests that exercise the OpenAI Responses API against the Foundry Local web service, mirroring how
samples/cs/foundry-local-web-servercalls chat completions.What's in this PR
New sample
samples/cs/responses-foundry-local-web-server/Program.csloadsqwen2.5-0.5bviaFoundryLocalManager, starts the local web service, and pointsOpenAI.Responses.ResponsesClientat<service-url>/v1CreateResponse, streaming withStreamingResponseOutputTextDeltaUpdate, and a full function-calling round-trip viaprevious_response_idResponsesFoundryLocalWebServer.csprojmirrors the existingFoundryLocalWebServer.csprojsamples/cs/README.mdupdated with a row for the new sampleIntegration tests
sdk/cs/test/FoundryLocal.Tests/ResponsesIntegrationTests.csNonStreaming_SimplePrompt_ReturnsTextStreaming_EmitsTextDeltaAndCompletionEventsFunctionCalling_FullRoundTrip_ProducesAssistantTextSkip.Test(...)whenqwen2.5-0.5bis not cached locally[After(Class)]cleanup stops the web service and unloads the modelOpenAI 2.10.0added to the test csproj onlyPackage bump
samples/cs/Directory.Packages.props: centrally-managedOpenAI2.5.0 → 2.10.0 (needed for stableResponsesClient)What's NOT in this PR
Microsoft.AI.Foundry.LocalResponsesClient.cs,ResponsesTypes.cs, managerGetResponsesClient*methods,IModelextension, customResponsesClientSettings) are revertedValidation
dotnet build samples/cs/responses-foundry-local-web-server -c Release— cleandotnet build sdk/cs/test/FoundryLocal.Tests -c Release— clean (2 unrelated pre-existing nullable warnings)GetRepoRoot()issue when this repo is checked out as a git worktree (Utils.AssemblyInitthrows because.gitis a file rather than a directory in worktrees) — this affects every test in the project, not just Responses1.1.0-dev.202605010202from the ORT-Nightly feed if the stable bits are staleCo-authored-by: Copilot 223556219+Copilot@users.noreply.github.com