dotnet-server: Rich Interactions runtime + choices kind (AskUserQuestion) - #484
Merged
Conversation
…ion) Wave 2 of the polyglot Rich Interactions effort — mirror the merged Rust reference (#475) on the .NET (C#) server, Brent's tsx-dev-agent host. Framework (generalizes the write-confirmation park/resume kind-agnostically): - IInteractionKind / InteractionCatalog — the kind catalog (default = choices). - InteractionParkRegistry — session-keyed park store (peek vs resolve, so an invalid submit re-prompts without consuming the park), the interaction analog of ConfirmationRegistry. - RequestInteractionTool / SubmitInteractionTool — the per-kind request_<kind> raise tool (rich = park + interaction_required; fallback = conversational directive) and the generic submit_interaction fallback tool. - ProtocolEvents.InteractionRequired / InteractionInvalid — the double-nested data.data envelopes matching spec/events/*.schema.json. The choices kind (mirrors choices.rs exactly): request_choices (1–4 questions, header ≤12 unique, 2–4 options, optional multiSelect), validate_choices (all-answered; labels ∈ options; single = one label XOR other, multi = ≥1; blank other dropped; one-pass errors), fallback directive, capability id choice_chips. Server wiring: submit_interaction dispatch (validate → resume, invalid → retryable interaction_invalid, decline path, INTERACTION_MISMATCH / NO_PENDING_INTERACTION guards, ownership-scoped); per-connection `supports` capture at create_conversation_session drives the rich-vs-fallback branch; teardown/cancel unpark. The catalog is a DI-provided capability (AddSmoothOperatorServer registers InteractionCatalog.Default), so direct FrameDispatcher construction is unchanged. Tests: xUnit validator unit tests (ported from choices.rs, + the shared choices_* conformance fixtures through the C# validator) and a WS park/resume integration suite (raise → interaction_required → submit → resume; invalid → stays parked → resubmit; decline; text-only fallback; no-pending error). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YbN45JeWDbcjvFqGJvmVD3
🦋 Changeset detectedLatest commit: 0ffc075 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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.
Problem
Wave 2 of the polyglot Rich Interactions effort. The Rust reference merged (#475); the .NET (C#) server — Brent's
tsx-dev-agenthost — needs the same runtime + thechoiceskind. Until now the C# server had only the write-confirmation park/resume, not the generalized kind-agnostic interaction framework.Solution
Mirror the Rust reference (
interaction.rs+tools/interaction.rs+choices.rs+ the server wiring) idiomatically in C#, reusing the existingConfirmationRegistrypark/resume pattern generalized.Framework (
dotnet/server/src/Interactions.cs)IInteractionKind/InteractionCatalog— the extension seam + kind catalog (default =choices).InteractionParkRegistry— session-keyed park store with peek vs resolve (an invalid submit re-prompts without consuming the park), the interaction analog ofConfirmationRegistry.RequestInteractionTool/SubmitInteractionTool(bothAIFunction) — the per-kindrequest_<kind>raise tool (rich → park +interaction_required; fallback → conversational directive) and the genericsubmit_interactionfallback tool.The
choiceskind (dotnet/server/src/ChoicesKind.cs, mirrorschoices.rs)request_choices(1–4 questions, header ≤12 unique, 2–4 options, optionalmultiSelect),ChoicesValidator.Validate(all-answered; labels ∈ options; single = one label XORother, multi = ≥1; blankotherdropped; one-pass errors), fallback directive, capability idchoice_chips.Server wiring
ProtocolEvents.InteractionRequired/InteractionInvalid— double-nesteddata.dataenvelopes matchingspec/events/*.schema.json.submit_interactiondispatch inFrameDispatcher(validate → resume; invalid → retryableinteraction_invalid, turn stays parked; decline path;INTERACTION_MISMATCH/NO_PENDING_INTERACTION; ownership-scoped).supportscapture atcreate_conversation_sessiondrives the rich-vs-fallback branch; teardown/cancel unpark the park.AddSmoothOperatorServerregistersInteractionCatalog.Default), so directFrameDispatcherconstruction stays unchanged.Verification
ChoicesInteractionTests, 14): ported fromchoices.rs's#[cfg(test)]block, plus the sharedchoices_spec/choices_values/choices_payloadconformance fixtures fed through the C# validator (canonical payload must equal the fixture).SubmitInteractionTests, 5) over the real WS harness: raise →interaction_required→submit_interaction→ resume; invalid → stays parked → resubmit; decline; text-only fallback (no capability → no card, conversational directive); no-pending error.dotnet test: server unit 371, integration 90, conformance 36 (1 skipped), host 6 — all green.spec/interactions/choices.schema.jsonconformance already validated by the sharedConformanceTests.🤖 Generated with Claude Code
https://claude.ai/code/session_01YbN45JeWDbcjvFqGJvmVD3