Expose exp_assignments injection on session create/resume across all SDKs#1750
Expose exp_assignments injection on session create/resume across all SDKs#1750ellismg wants to merge 3 commits into
Conversation
Expose ExP assignment ("flight") data on the SDK's session-open and
session-resume paths so an out-of-process integrator can inject the same
CopilotExpAssignmentResponse payload the CLI fetches itself. The runtime
already accepts expAssignments on the wire, but the hand-written
SessionCreateWire / SessionResumeWire structs (and their public configs)
did not carry it.
- SessionConfig / ResumeSessionConfig: add doc-hidden exp_assignments
field (serde_json::Value) plus a doc-hidden with_exp_assignments builder
- SessionCreateWire / SessionResumeWire: add exp_assignments, serialized
as camelCase expAssignments and omitted when None
- Forward the field through both into_wire paths
- Unit tests asserting expAssignments is emitted on create and resume and
omitted when unset
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Even if the main known consumer at present is the GH Copilot App, I'd like to see us add whatever we need here consistently across all 6 languages. I'd like to avoid having to keep track of differences in exposed functionality by language. And presumably other languages will end up needing this, too. |
…SDKs
Mirror the Rust SDK change in the remaining five SDKs so out-of-process
integrators can inject ExP ("flight") assignment data into session create
and resume. Adds an internal/trusted-integrator config field that forwards
to the wire key `expAssignments` (omitted when unset), in the opaque JSON
shape of `CopilotExpAssignmentResponse`:
- Node: `expAssignments?: Record<string, unknown>` on `SessionConfigBase`
(`@internal`), forwarded in the inline session.create/session.resume
payloads in client.ts.
- Python: `exp_assignments: dict[str, Any] | None = None` kwarg on
`create_session`/`resume_session`, mapped to `payload["expAssignments"]`.
- Go: `ExpAssignments any` on `SessionConfig`/`ResumeSessionConfig`
(documented Internal:), forwarded into the create/resume wire structs
with `json:"expAssignments,omitempty"`.
- .NET: `JsonElement? ExpAssignments` on `SessionConfigBase`
(`[EditorBrowsable(Never)]`), wired through the internal
CreateSessionRequest/ResumeSessionRequest records.
- Java: `JsonNode expAssignments` field + fluent setter/getter on
SessionConfig/ResumeSessionConfig, mapped through
CreateSessionRequest/ResumeSessionRequest in SessionRequestBuilder.
Each language gains create+resume serialization tests asserting the field
serializes to `expAssignments` when set and is omitted when unset.
Part of github/github-app epic #7452; mirrors the runtime contract added
in github/copilot-agent-runtime#9955.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…signments # Conflicts: # nodejs/test/client.test.ts
Cross-SDK Consistency Review ✅Reviewed all 6 SDK implementations for
No consistency issues found. The null-omission mechanisms are all idiomatic: Rust uses
|
What
Adds an internal/trusted-integrator option to inject ExP ("flight") assignment data into session create and resume, forwarded to the wire key
expAssignmentsand omitted entirely when unset. The payload is opaque JSON in the exact shape ofCopilotExpAssignmentResponse(matching the runtime contract and each SDK's already-generatedSessionOpenOptions.expAssignmentsfield — no typed schema struct introduced).Implemented consistently across all six SDKs. Per-language surface:
#[doc(hidden)] pub fn with_exp_assignments(serde_json::Value) -> Self+#[doc(hidden)] pub exp_assignments: Option<serde_json::Value>onSessionConfig/ResumeSessionConfig; forwarded through the hand-writtenSessionCreateWire/SessionResumeWire(skip_serializing_if = "Option::is_none").@internal expAssignments?: Record<string, unknown>onSessionConfigBase; forwarded in the inlinesession.create/session.resumepayloads inclient.ts.exp_assignments: dict[str, Any] | None = Nonekwarg oncreate_session/resume_session; mapped topayload["expAssignments"]when set.ExpAssignments any(documentedInternal:) onSessionConfig/ResumeSessionConfig; forwarded into the create/resume wire structs withjson:"expAssignments,omitempty".[EditorBrowsable(Never)] JsonElement? ExpAssignmentsonSessionConfigBase; wired through the internalCreateSessionRequest/ResumeSessionRequestrecords ([JsonPropertyName("expAssignments")], null auto-omitted).JsonNode expAssignmentsfield + fluentsetExpAssignments/getExpAssignmentsonSessionConfig/ResumeSessionConfig; mapped throughCreateSessionRequest/ResumeSessionRequestinSessionRequestBuilder(@JsonProperty("expAssignments"),@JsonInclude(NON_NULL)).Why
Lets out-of-process integrators — the GitHub Copilot desktop app — inject ExP flight data over JSON-RPC, mirroring the runtime contract added in github/copilot-agent-runtime#9955. The runtime already feeds supplied
expAssignmentsthrough the sameFeatureFlagService.setExpAssignments()path as CLI-fetched flights, stampsexp_assignment_contexton telemetry, sets the CAPI headerX-Copilot-Exp-Assignment-Context, and is non-blocking / fail-open when absent. Injection is supported on both create and resume.Each SDK's generated
SessionOpenOptionsalready reflects the field, but the create/resume paths serialize hand-written config + wire structs, so an out-of-process consumer had no way to send it. The desktop app is the first out-of-process consumer (starting with the Rust SDK); in-process callers already had the capability. Adding it to every SDK keeps the surface consistent per review feedback. Part of the github/github-app ExP onboarding epic #7452.Internal posture
The field/builder are marked internal in each language's idiom (Rust
#[doc(hidden)], Node@internal, GoInternal:doc, .NET[EditorBrowsable(Never)], Java doc note; Python documents it as a trusted-integrator option) to mirror upstream's.asInternal()posture — a trusted-integrator API, not broadly advertised public surface.Validation
All six SDKs add create + resume serialization tests asserting
expAssignmentsis emitted on both paths and omitted when unset.cargo +nightly-2026-04-14 fmt --checkclean;cargo clippy --all-features --all-targets -- -D warningsclean;cargo test --all-features --lib→ 166 passed.npm run typecheckclean; new unit tests pass.ruff check/ruff format --checkclean.gofmtclean;go build ./...+go test ./...pass.SessionRequestBuilderTesttests pass (incl. 2 new);mvn spotless:applyapplied.Also verified the github-app consumer compiles against the synced Rust shape (
cargo check -p copilot-taurigreen);with_exp_assignmentsis reachable from the inject call site.Notes
Opening as a draft pending the paired github-app consumer work. The vendored sync into github-app will follow via the auto-sync agent after merge.
cc @criemen — he asked to be kept in the loop on this.