Skip to content

Upstream sync: post-v1.0.0-beta.4 round 2 (#1299, #1315) + schema 1.0.49#108

Merged
krukow merged 2 commits into
mainfrom
upstream-sync/post-v1.0.0-beta.4-round-2
May 20, 2026
Merged

Upstream sync: post-v1.0.0-beta.4 round 2 (#1299, #1315) + schema 1.0.49#108
krukow merged 2 commits into
mainfrom
upstream-sync/post-v1.0.0-beta.4-round-2

Conversation

@krukow
Copy link
Copy Markdown
Collaborator

@krukow krukow commented May 20, 2026

Ports the SessionFs SQLite support from upstream PR #1299, updates examples/permission_bash.clj per upstream PR #1315, and bumps the pinned schema version from 1.0.49-1 to 1.0.49.

Changes

SessionFs SQLite support (upstream PR #1299)

  • New optional :sqlite {:query :exists} sub-provider for the provider-style createSessionFsHandler factory. Low-level handlers expose flat :sqlite-query / :sqlite-exists keys; the adapter bridges between them.
  • Clients advertise support via :capabilities {:sqlite true} under :session-fs; the value is forwarded on sessionFs.setProvider and validated at session creation (throws when capabilities.sqlite is declared but the provider lacks :sqlite).
  • queryType is coerced from the wire string to an idiomatic keyword (#{:exec :query :run}) before reaching the handler.
  • SQL bind-parameter map keys (e.g. $userId) bypass kebab-case conversion via an escape hatch in protocol/normalize-incoming.
  • Result row column-name keys (e.g. :user_id, :created_at) round-trip verbatim on the outgoing wire path via a new preserve-outgoing-opaque-fields escape hatch in protocol.clj, matching upstream Node.js semantics. (Found via multi-model code review.)
  • SQLite handler exceptions propagate as JSON-RPC errors, matching upstream Node behavior.

Schema 1.0.49

  • .copilot-schema-version advanced from 1.0.49-1 to 1.0.49
  • Additive only: new named enum types, format annotations, and the new sqlite RPC methods
  • Regenerated event_specs.clj reflects the new enums (upstream PRs #1305, #1307, #1327, #1333)

Examples

  • Updated examples/permission_bash.clj from deprecated :approved to current :approve-once (upstream PR #1315)

Validation

Check Result
bb test ✅ 269 tests / 1275 assertions, 0 failures
bb validate-docs ✅ 13 files, 0 warnings
./run-all-examples.sh ✅ all examples completed
E2E ⚠️ 2 pre-existing failures unrelated to this PR — local CLI 1.0.51-2 drift from pinned schema 1.0.49

Multi-model code review

Parallel reviews via Claude Opus 4.7 and GPT-5.5 both independently identified a HIGH severity bug:

# Finding Source Severity Decision
1 Outgoing SQL row column names mangled by recursive kebab→camelCase Opus + GPT HIGH Fixedpreserve-outgoing-opaque-fields escape hatch + regression test
2 capabilities.sqlite validation only checks :sqlite-query GPT MEDIUM Dismissedsession-fs-provider? already validates both arities; mirrors upstream client.ts:466
3 Channel-returned exceptions in await-session-fs-result GPT MEDIUM Out of scope — pre-existing, applies to all FS handlers
4 Unused ::sqlite-rows/::sqlite-columns used wrong seq? predicate Opus LOW Fixed — changed to (s/coll-of …)

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Ports the SessionFs SQLite support (upstream PR #1299) and bumps the
pinned schema version from 1.0.49-1 to 1.0.49.

### SessionFs SQLite (upstream PR #1299)

- New optional `:sqlite {:query :exists}` sub-provider for the
  provider-style `createSessionFsHandler` factory. Low-level handlers
  expose flat `:sqlite-query` / `:sqlite-exists` keys; the adapter
  bridges between them.
- Clients advertise support via `:capabilities {:sqlite true}` under
  `:session-fs`; the value is forwarded on `sessionFs.setProvider` and
  validated at session creation (throws when capabilities.sqlite is
  declared but the provider lacks :sqlite).
- `queryType` is coerced from the wire string to an idiomatic
  keyword (`#{:exec :query :run}`) before reaching the handler.
- SQL bind-parameter map keys (e.g. `$userId`) bypass kebab-case
  conversion via a new escape hatch in `protocol/normalize-incoming`.
- Result row column-name keys (e.g. `:user_id`, `:created_at`)
  round-trip verbatim on the outgoing wire path via a new
  `preserve-outgoing-opaque-fields` escape hatch in `protocol/`,
  matching upstream Node.js semantics where provider rows are forwarded
  untouched. (review feedback)
- SQLite handler exceptions propagate as JSON-RPC errors (not wrapped
  as SessionFsError result maps), matching upstream Node behavior.

### Schema 1.0.49

- `.copilot-schema-version` advanced from `1.0.49-1` to `1.0.49`
- Additive only: new named enum types, format annotations, and the
  new sessionFs.sqliteQuery / sessionFs.sqliteExists RPC methods
- Regenerated event_specs.clj reflects the new enums
- (upstream PRs #1305, #1307, #1327, #1333)

### Other

- Updated `examples/permission_bash.clj` from deprecated `:approved`
  to current `:approve-once` (carried from upstream PR #1315)
- Added integration tests covering the SQLite adapter, RPC dispatch,
  capability forwarding, validation throw, opaque param keys, and
  the new snake_case column-name round-trip regression test

### Validation

- bb test: 269 tests / 1275 assertions pass
- bb validate-docs: 0 warnings
- ./run-all-examples.sh: all examples pass
- E2E: 2 pre-existing failures (test-e2e-connection ping timestamp,
  test-e2e-blob-attachment timeout) due to local CLI 1.0.51-2 drift
  from the pinned 1.0.49 schema; unrelated to these changes

### Multi-model code review

Parallel reviews via Claude Opus 4.7 and GPT-5.5 both flagged the same
HIGH severity bug: outgoing SQL row column names were being mangled by
recursive kebab→camelCase conversion (`util/clj->wire`). Fixed by
adding `preserve-outgoing-opaque-fields` in protocol.clj, mirroring the
existing incoming escape hatch for bind params. Regression test added.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 20, 2026 12:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports upstream SessionFs SQLite support (PR #1299), updates an example per upstream (PR #1315), and bumps pinned Copilot schema assets to 1.0.49 to keep the Clojure SDK wire layer aligned with upstream.

Changes:

  • Add SessionFs SQLite RPC support (sessionFs.sqliteQuery, sessionFs.sqliteExists) including capability advertisement and handler/provider adaptation.
  • Add protocol escape hatches to preserve opaque SQL bind-parameter keys on incoming requests and preserve row column keys on outgoing sqlite results.
  • Bump pinned schema version to 1.0.49 and regenerate generated event specs; update permission_bash example and changelog/docs accordingly.
Show a summary per file
File Description
test/github/copilot_sdk/mock_server.clj Mock server now responds to sessionFs.setProvider for new capability forwarding tests.
test/github/copilot_sdk/integration_test.clj Adds integration tests covering sqlite adapter behavior, RPC dispatch, capability forwarding, and opaque key preservation.
src/github/copilot_sdk/specs.clj Extends specs with session-fs capabilities, optional sqlite handler keys, and sqlite query type/result shapes.
src/github/copilot_sdk/session.clj Implements sqlite adapter wiring, queryType coercion, and capability validation on handler installation.
src/github/copilot_sdk/protocol.clj Adds incoming/outgoing opaque-field preservation for sqlite bind params and result row keys.
src/github/copilot_sdk/generated/event_specs.clj Regenerated specs from updated schemas (enum tightening, etc.).
src/github/copilot_sdk/client.clj Routes new sqlite RPC methods and forwards :session-fs.capabilities on sessionFs.setProvider.
schemas/session-events.schema.json Upstream schema refresh (formats/enums/refs) as part of 1.0.49 bump.
schemas/api.schema.json Upstream API schema refresh adding sqlite RPCs and related type refactors as part of 1.0.49 bump.
schemas/README.md Updates pinned schema version text to 1.0.49.
.copilot-schema-version Bumps pinned schema version to 1.0.49.
examples/permission_bash.clj Updates permission decision kind to :approve-once.
doc/reference/API.md Documents optional sqlite support for SessionFs providers/handlers.
CHANGELOG.md Adds Unreleased entries for sqlite support + schema bump + example fix.

Copilot's findings

  • Files reviewed: 13/14 changed files
  • Comments generated: 2

Comment thread src/github/copilot_sdk/session.clj Outdated
Comment thread doc/reference/API.md Outdated
@krukow krukow marked this pull request as ready for review May 20, 2026 16:23
- session.clj: capabilities.sqlite validation now requires BOTH :sqlite-query
  and :sqlite-exists (previously only :sqlite-query). A low-level handler
  declaring only :sqlite-query would have passed validation but failed at
  runtime with an opaque "Unknown sessionFs method" error when
  sessionFs.sqliteExists arrived. The throw now reports which handler
  keys are missing.
- doc/reference/API.md: clarify that the low-level handler map requires
  the 10 core FS operations and the two :sqlite-* keys are optional
  (only required when :capabilities {:sqlite true} is advertised).
- integration_test.clj: regression test that create-session throws when
  capabilities.sqlite=true and the low-level handler has :sqlite-query
  but not :sqlite-exists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@krukow krukow merged commit 07af9e0 into main May 20, 2026
2 checks passed
@krukow krukow deleted the upstream-sync/post-v1.0.0-beta.4-round-2 branch May 20, 2026 19:25
krukow added a commit that referenced this pull request May 21, 2026
Add explicit 'sync local main first' step in Phase 1 (Discovery) and
Phase 8 (PR Creation) of the update-upstream skill. A stale local main
caused this round-3 PR to be rebased post-hoc against origin/main after
PR #108 (round 2) was merged.

Also document the post-hoc remedy: when an already-squash-merged commit
shows up during rebase, 'git rebase --skip' is the correct action and
Git's 'patch contents already upstream' detection will handle subsequent
duplicates automatically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
krukow added a commit that referenced this pull request May 21, 2026
…0) (#109)

* Schema bump 1.0.49 → 1.0.51 + regenerate event specs

Pin .copilot-schema-version to 1.0.51 (latest GA on npm), re-fetch
schemas/, and regenerate src/github/copilot_sdk/generated/event_specs.clj
via 'bb codegen'.

Notable generated diffs:
- :ttft-ms removed, :time-to-first-token-ms added in assistant.usage-data
  (wire field 'ttftMs' → 'timeToFirstTokenMs' upstream).
- Many predicates change from number? → integer? (upstream PR #1329 uses
  32-bit types for bounded schema integers).
- Cosmetic gensym renumbering on anyOf-derived specs.

No new event types, no new top-level event-data fields beyond the rename.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* MCP stdio: :mcp-args is now optional (upstream PR #1347)

Upstream PR #1347 made MCPStdioServerConfig.args optional across all
SDKs. Move ::mcp-args from :req-un to :opt-un on ::mcp-local-server
(aliased as ::mcp-stdio-server). Add red-then-green test asserting
{:mcp-command "true" :mcp-tools ["read"]} validates with no :mcp-args.
Update doc/mcp/overview.md to mark :mcp-args optional and document the
CLI 1.0.51 origin.

Also extend ::assistant.usage-data to accept :time-to-first-token-ms
(new wire name from CLI 1.0.51 schema rename of ttftMs →
timeToFirstTokenMs) alongside legacy :ttft-ms, so events from older
and newer CLIs both validate. Add a focused test for both shapes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ping: :timestamp is now an ISO 8601 string (upstream PR #1340)

CLI 1.0.51 changed the 'ping' RPC result timestamp field from epoch
millis number to an ISO 8601 date-time string. The SDK forwards the
field verbatim, so callers of sdk/ping now receive a string :timestamp.

- Update the mock test server to return (.toString (Instant/now)).
- Update test-ping and ^:e2e test-e2e-connection assertions to expect
  a string, and also parse it as Instant to assert ISO 8601 shape.
- Update docstrings on sdk/ping and client/ping to document the new
  shape and note that earlier CLI versions returned a number.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Bump version to 1.0.0-beta.4.1 + CHANGELOG round 3

Document the sync of CLI schema 1.0.49 → 1.0.51, including the three
behavioural changes ported (PR #1347, the ttftMs rename, and the
ping timestamp shape change) and the items deliberately tracked but
not ported (PR #1316 packaging-only, PR #1327 ToolBinaryResult tighten).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* skill(update-upstream): sync local main before branching

Add explicit 'sync local main first' step in Phase 1 (Discovery) and
Phase 8 (PR Creation) of the update-upstream skill. A stale local main
caused this round-3 PR to be rebased post-hoc against origin/main after
PR #108 (round 2) was merged.

Also document the post-hoc remedy: when an already-squash-merged commit
shows up during rebase, 'git rebase --skip' is the correct action and
Git's 'patch contents already upstream' detection will handle subsequent
duplicates automatically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Copilot review: relax ::timestamp, fix typo, test legacy ttft-ms

- ::specs/timestamp now accepts both ISO 8601 strings (CLI ≥ 1.0.51) and
  numeric epoch-millis (older CLIs), making the spec consistent with the
  ping docstring contract. The ping fdef return spec no longer fails
  instrumentation against older CLIs.
- Fix "Reflecing" → "Reflecting" typo in update-upstream SKILL.md.
- Add backward-compat assertion for legacy :ttft-ms key in
  test-assistant-usage-time-to-first-token-ms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Copilot review round 2: tighten timestamp spec, fix doc comments

- ::timestamp epoch-ms branch is now nat-int? (epoch-millis are non-negative
  integers, not arbitrary numbers).
- Fix misleading comment that implied event :timestamp is coerced to Instant
  at the coercion layer; actually only certain event-data fields are coerced.
- Drop POSIX-specific 'true' example from MCP overview (not portable to
  Windows).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Copilot review round 3: clarify changelog ping entry

Reword the round-3 'Changed' bullet to make clear that CLI 1.0.51 (not the
SDK) changed the ping :timestamp field type, and that the SDK accepts both
shapes via ::specs/timestamp so callers see a string on CLI ≥ 1.0.51 and a
number on older CLIs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Copilot review round 4: assert legacy epoch-ms timestamp validates

Add explicit assertions that ::specs/timestamp accepts both an ISO 8601
string and a System/currentTimeMillis-sized long, plus boundary checks
(negative rejected, fractional number rejected). Locks in backward
compatibility with older CLIs that still return numeric :timestamp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address Copilot review round 5: clarify ::timestamp doc; tighten E2E ping assertion

- ::timestamp doc comment now explicitly mentions both Instant/parse for the
  string form and Instant/ofEpochMilli for the numeric form, so the comment
  matches the spec's two-branch nature.
- E2E ping test now also asserts the :timestamp parses as an ISO 8601 instant
  (mirroring the integration test), so a stringified epoch-millis from a
  misbehaving CLI would not silently pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants