Skip to content

sync wire fix (bare array + string delivery_id), WS delivery acks, dedup, terminal closes — 1.0.21 - #1

Merged
sanctrl merged 1 commit into
mainfrom
fix/sync-wire-ack
Jul 18, 2026
Merged

sync wire fix (bare array + string delivery_id), WS delivery acks, dedup, terminal closes — 1.0.21#1
sanctrl merged 1 commit into
mainfrom
fix/sync-wire-ack

Conversation

@sanctrl

@sanctrl sanctrl commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What

Fixes the broken /v1/messages/sync wire contract — production returns a bare JSON array with opaque string delivery_id cursors, but the SDK typed {envelopes: [{delivery_id: number}]}, making the realtime client's post-reconnect offline drain a silent zero-row no-op (TypeError swallowed by a void fire-and-forget). This has been broken in every published version; the hand-rolled workaround in agentchat-coding-agents/core/src/lib/wire.ts is the reference this now matches.

Also ships the client half of the WS delivery-ack protocol (server repo docs/realtime-delivery-ack.md), closing the delivered-on-socket-write at-most-once gap once the server side deploys.

Changes

  • sync()SyncEnvelope[] (breaking type change — runtime was already broken; migration notes in CHANGELOG); syncAck(string){acked}
  • Drain rebuilt: cursor pagination, positional ack of the settled prefix only, clean-prefix stop on invalid rows, handler-throw ⇒ no ack, gap-buffer rows never acked before dispatch, errors surface via onError
  • Capability-negotiated WS acks: HELLO advertises ['ack']; fully dormant against today's server (no capability echo ⇒ zero new frames)
  • Bounded message-id dedup LRU (default 2048) across live+drain — duplicates are by design under at-least-once, loss is not
  • Close codes 1008/4401/4403 terminal: no more infinite reconnect on revoked keys
  • Paginator audit vs live routes: contacts/agents keys match — no drift
  • New wire-contract test suite pins the real shape so CI can't be green on the wrong wire again

Verification

  • 107 tests passing (was 86), tsc --noEmit clean, tsup build clean (ESM+CJS+DTS), version 1.0.21 build-injection confirmed

Release

Not published — tag + OIDC pipeline per RELEASING.md when ready.

…dup, terminal closes — 1.0.21

The /v1/messages/sync path never matched production: the server returns a
bare JSON array with opaque string delivery_id cursors, but the SDK typed
{envelopes: [{delivery_id: number}]} — so the realtime client's offline
drain read .envelopes off an array, threw, and the rejection was swallowed
by a void call. Every reconnect drain silently delivered zero rows and
never acked. Fixed against the real wire (reference: agentchat-coding-agents
core/src/lib/wire.ts), with a dedicated wire-contract test suite so CI can
never be green on the wrong shape again.

- sync() -> SyncEnvelope[] (breaking type change; runtime was already
  broken, migration notes in CHANGELOG); syncAck(string) -> {acked}
- drain: cursor pagination, positional ack of the settled prefix only,
  clean-prefix stop on invalid rows, handler-throw => no ack, gap-buffer
  rows never acked before dispatch, errors surface via onError
- WS delivery acks (capability-negotiated per docs/realtime-delivery-ack.md):
  HELLO advertises ['ack']; ack after handlers settle; dormant against
  servers that don't echo the capability
- bounded message-id dedup LRU (default 2048) across live+drain
- close codes 1008/4401/4403 are terminal: no infinite reconnect on
  revoked keys; final ConnectionError via onError
- paginator audit vs live routes: contacts/agents keys match, no drift

107 tests (was 86), type-check + build clean.
@sanctrl
sanctrl merged commit 32eb5bf into main Jul 18, 2026
2 checks passed
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.

1 participant