feat: sync to upstream copilot-sdk v1.0.1 (open-canvases snapshot, schema 1.0.61)#136
Merged
Conversation
Sync to upstream copilot-sdk v1.0.1. Pinned @github/copilot schema
bumped from 1.0.57 to 1.0.61 (upstream PRs #1597, #1612). Regenerated
generated/event_specs.clj from the new session-events schema.
Schema diffs picked up:
- New CanvasClosedEvent + CanvasClosedData ({canvasId, extensionId,
instanceId}, ephemeral)
- ResumeData and ShutdownData gain optional eventsFileSizeBytes
- ScheduleCreatedData gains optional at, cron, tz; intervalMs becomes
optional
- AssistantMessageData gains optional apiCallId
- HookEndError gains optional source
- HookProgressData gains optional temporary
Project version bumped to 1.0.1.0 to match upstream parity.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a per-session in-memory snapshot of currently-open canvases, mirroring the upstream Node.js client's openCanvasInstances behavior. State machine - Initialize :open-canvases [] alongside :capabilities at session creation. - Internal mutators set-open-canvases! / upsert-open-canvas! / and validates strictly (mirrors upstream isOpenCanvasInstance: required :instance-id, :extension-id, :canvas-id, :reopen boolean, :availability "ready"|"stale"); bad payloads log a warn and no-op. Remove only requires :instance-id. - Public getter open-canvases returns the immutable snapshot vector. Wiring (client.clj) - session.canvas.opened -> upsert-open-canvas! before publishing event, so observers see consistent state (matches the capabilities.changed pattern at lines 612-614). - session.canvas.closed -> remove-open-canvas! before publishing. - session.resume responses populate the snapshot via set-open-canvases! on both sync and async resume paths. session.create does NOT populate it (matches upstream client.ts). - :open-canvases accepted in resume-session / join-session config to seed the snapshot when reconnecting (upstream ResumeSessionConfig). canvas-instance->wire produces an explicit camelCase keyword wire shape and stringifies caller-supplied :input keys deeply so they bypass csk on outbound — caller-defined opaque keys (e.g. :user_id) round-trip verbatim. Opaque :input preservation (protocol.clj) - session.canvas.opened event :input map is preserved verbatim through preserve-event-opaque-fields. - session.resume response openCanvases[] :input maps are restored positionally in normalize-incoming after wire->clj recursion. Specs - :copilot/session.canvas.closed added to the public ::event-type set. - ::open-canvas-instance / ::open-canvases (open-keys for forward-compat). - :open-canvases added to resume-session-config-keys, ::resume-session-config, ::join-session-config :opt-un. - ::at tightened to pos-int? (epoch-ms). - ::session.schedule_created-data: :interval-ms moved to :opt-un, plus new :at, :cron, :tz fields. - :events-file-size-bytes nat-int? on resume/shutdown :opt-un. - :api-call-id on assistant.message :opt-un. - :temporary boolean? on hook.progress :opt-un. Public surface (copilot_sdk.clj) - :copilot/session.canvas.closed added to event-types (not session-events, matching the existing canvas treatment from 1.0.0). - session/open-canvases re-exported at the top-level namespace. Tests (integration_test.clj) - 14 new canvas/v1.0.1 tests: - canvas.closed registration + idiom data spec - open-canvases initialized from resume - opened event upserts in place (same instanceId replaces) - closed event removes from snapshot - malformed payload no-op (idempotent) - session.create does NOT populate snapshot - schedule data with cron-only / :at variants pass spec - eventsFileSizeBytes / apiCallId / temporary accepted - opened event :input preserved verbatim (incl. snake_case) - resume response openCanvases[] :input preserved verbatim - upsert strict validation (4 rejection cases + 1 happy path) - outbound :open-canvases resume config wire shape preserves :input - ::at spec rejects non-positive / non-integer values - mock_server.clj: set-resume-response-extras! helper added for shaping resume responses with custom fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- API.md: open-canvases section explains the strict upsert contract (required fields per upstream isOpenCanvasInstance), :input verbatim preservation, and how to seed the snapshot via :open-canvases on resume-session / join-session. Adds :open-canvases row to the config table. - CHANGELOG.md: split v1.0.1 sync entries into the schema-driven baseline and the review-driven follow-up (strict upsert validation, :input preservation, ::at tightening, :open-canvases config). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Syncs the Clojure Copilot SDK to upstream github/copilot-sdk v1.0.1 / schema 1.0.61, adding the upstream per-session open-canvases snapshot API and updating event/spec coverage to match new schema fields.
Changes:
- Add per-session open-canvases snapshot (
open-canvasesgetter), initialize it fromsession.resume, and keep it updated viasession.canvas.opened/session.canvas.closedevents. - Extend resume/join config with
:open-canvasesand preserve opaque canvas:inputkeys verbatim across wire conversion. - Bump pinned schema/version artifacts and update generated wire specs, curated specs, docs, tests, changelog, and library version.
Show a summary per file
| File | Description |
|---|---|
test/github/copilot_sdk/mock_server.clj |
Allows tests to inject extra fields into session.resume responses (e.g. openCanvases). |
test/github/copilot_sdk/integration_test.clj |
Adds integration coverage for canvas snapshot lifecycle and new optional fields/spec relaxations. |
test/github/copilot_sdk/codegen_test.clj |
Updates schema-envelope fixtures to include session.canvas.closed. |
src/github/copilot_sdk/specs.clj |
Adds/relaxes curated idiom specs for new schema fields and canvas data structures. |
src/github/copilot_sdk/session.clj |
Introduces per-session :open-canvases state and snapshot mutation helpers + public accessor. |
src/github/copilot_sdk/protocol.clj |
Preserves opaque :input keys for canvas opened events and resume openCanvases[]. |
src/github/copilot_sdk/instrument.clj |
Adds fdef instrumentation for session/open-canvases. |
src/github/copilot_sdk/generated/event_specs.clj |
Regenerates wire specs to schema 1.0.61 (new event + optional fields). |
src/github/copilot_sdk/client.clj |
Applies canvas state mutations before publish; sends/receives open-canvases on resume/join. |
src/github/copilot_sdk.clj |
Exposes new event type and public open-canvases API entry point. |
schemas/session-events.schema.json |
Updates vendored schema JSON (1.0.61) including canvas.closed + new fields. |
schemas/README.md |
Updates pinned schema version note. |
README.md |
Bumps dependency version to 1.0.1.0. |
doc/reference/API.md |
Documents :open-canvases config and the open-canvases accessor + event semantics. |
doc/getting-started.md |
Bumps dependency version to 1.0.1.0. |
CHANGELOG.md |
Adds v1.0.1 sync + follow-up entries describing canvases and schema changes. |
build.clj |
Bumps project version to 1.0.1.0. |
.copilot-schema-version |
Bumps pinned @github/copilot schema version to 1.0.61. |
Copilot's findings
- Files reviewed: 17/19 changed files
- Comments generated: 2
Address GitHub Copilot Code Review feedback on PR #136: 1. canvas-instance->wire (client.clj): keep wrapping fields in idiomatic kebab-case keywords so util/clj->wire camelCases them exactly once, instead of relying on csk's idempotence on already-camelCase keys. Behavior unchanged; opaque :input keys still preserved verbatim via stringify-keys-deep. 2. remove-open-canvas! (session.clj): tighten validation to require a non-blank string :instance-id, matching the strict check in upsert-open-canvas! and the ::instance-id non-blank-string spec. A non-string (e.g. numeric) :instance-id now logs a warn and no-ops instead of being silently treated as a valid removal key. 3. Regression test for the non-string :instance-id rejection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address GitHub Copilot Code Review feedback round 2 on PR #136: build-resume-session-params now gates on (contains? config :open-canvases) instead of (seq …), so an explicit empty vector is sent verbatim — matching upstream client.ts which forwards config.openCanvases directly. Allows callers to deliberately seed/clear the snapshot on resume. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address GitHub Copilot Code Review feedback round 3 on PR #136: * stringify-keys-deep now uses (subs (str k) 1) instead of (name k) so namespaced keyword keys in opaque :input payloads (e.g. :my.app/user_id) are preserved as 'my.app/user_id' on the wire — not silently truncated to 'user_id'. This honors the verbatim-keys contract for caller-supplied data. Added regression test test-resume-config-open-canvases-namespaced-input-keys. * test/mock_server.clj handle-session-resume now merges :resume-response-extras before {:sessionId session-id} so the canonical response key wins — prevents tests from accidentally producing invalid responses by including :sessionId in extras. * instrument.clj: tightened session/open-canvases fdef :ret from (s/coll-of map?) to ::specs/open-canvases so instrumentation enforces the canvas-instance shape on the snapshot getter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address GitHub Copilot Code Review feedback round 4 on PR #136: set-open-canvases! (called after session.resume) was storing the CLI's openCanvases payload verbatim, bypassing the same valid-open-canvas-instance? check that gates live session.canvas.opened upserts. A malformed CLI response could leak invalid entries into the snapshot and trip instrumentation on (open-canvases session). Now: non-sequential values become [], and entries failing valid-open-canvas-instance? are dropped with a single warning carrying the dropped count. Snapshot invariant holds for all callers. Added regression test test-open-canvases-resume-sanitizes-invalid-entries mixing missing :reopen, missing :availability, and bad availability values. 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.
Syncs the Clojure SDK to upstream
github/copilot-sdkv1.0.1(CLI@github/copilot1.0.61). The marquee port is the per-session open-canvases snapshot from upstream PR #1604; the rest is schema-driven codegen and a few reactive spec adds.What this PR does
(copilot/open-canvases session)getter returns the in-memory vector of currently-open canvases for a session, mirroring upstreamCopilotSession.openCanvases. Initialized from thesession.resumeRPC response (session.createdoes NOT populate it — matches upstreamclient.ts); maintained by thesession.canvas.opened(upsert by:instance-id, position-preserving) andsession.canvas.closed(remove) event handlers; mutations happen before event publish so observers see consistent state.:open-canvasesresume config. Callers can seed the snapshot when reconnecting via:open-canvasesonresume-session/join-session, matching upstreamResumeSessionConfig.openCanvases.:copilot/session.canvas.closedevent (added to publicevent-types, kept offsession-eventsto match the existing canvas treatment). Reactive spec follow-ups for new optional fields::events-file-size-byteson resume/shutdown,:api-call-idon assistant.message,:temporaryon hook.progress,:at/:cron/:tzon schedule_created (with:interval-msrelaxed to optional).Non-obvious nuance reviewers will want
isOpenCanvasInstance). Asession.canvas.openedpayload missing any of:instance-id,:extension-id,:canvas-id,:reopen(must be boolean), or:availability(must be"ready"or"stale") is a no-op with a warn log. Upstream is strict here precisely because the snapshot drives reconnect behavior; lax acceptance would let half-formed entries leak across resumes.remove-open-canvas!only requires:instance-id(a closed event with junk extra fields should still close cleanly).:inputkeys preserved verbatim, in both directions. The canvas:inputmap is opaque caller data ({ [k: string]: unknown }) — kebab-casing the keys would silently corrupt it. Inbound:protocol/preserve-event-opaque-fieldscarves:inputout beforewire->cljrecurses, both for thesession.canvas.openedevent and for each entry insession.resume'sopenCanvases[]. Outbound:client/canvas-instance->wiredeep-stringifies:inputkeys before they enterclj->wire, sincecske/transform-keysonly transforms keyword keys (string keys pass through). Net result::user_id,:myKey, and nested mixed-case keys round-trip through the CLI unchanged.session.createdoes not populate the snapshot. Onlyresume. This matches upstreamclient.ts:1340-1360exactly — a fresh session has no canvases by definition, and adding the wire field at create-time would diverge from upstream.::atispos-int?, notnumber?.atis an epoch-ms timestamp; non-integer or non-positive values are invalid by construction. Tighter than the raw schema'snumberbecause the schema can't express "positive integer ms" but the contract does.Validation
bb ci:full(incl. E2E + examples) green. 14 new canvas/v1.0.1 integration tests cover the snapshot lifecycle, strict-validation rejection cases,:inputpreservation in both directions, the new optional event-data fields, and the outbound resume config wire shape.Upstream PRs