Skip to content

fix: close tool-stream lifecycle and contract audit gaps - #58

Merged
austinchennn merged 4 commits into
EmergentExit:mainfrom
wangyeyu1129:chore/tool-stream-contract-audit
Oct 19, 2026
Merged

austinchennn merged 4 commits into
EmergentExit:mainfrom
wangyeyu1129:chore/tool-stream-contract-audit

Conversation

@wangyeyu1129

@wangyeyu1129 wangyeyu1129 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

Audits the existing draft tool-stream contract and closes two concrete lifecycle gaps without replacing its architecture. A synchronous client stream listener can interrupt/close before its derived legacy preview; that preview is now suppressed. A late model argument fragment can reopen a settled core stream after its 256-entry tombstone is evicted; the session now consults its already-retained issued-call record.

Issue association

Refs #49, Refs #22. Related coverage: #17/#50. Independent branch from current upstream main f5e0825; #29/#30/#34/#41 and #35–#48 are already merged. Existing negotiation, lifecycle tracking, local cancellation and server black-box coverage are credited, not reimplemented.

Normative discrepancy is separately recorded in #57: §3.3 still says no capabilities exist despite the registry/§7.5. Spec, schema, shared vectors and draft status remain unchanged. The newer cross-session identifier proposal #56 is not folded into this audit.

Behaviours Completed

  • Public client callback regression: observe epoch 1, receive delta/progress, call interrupt()/close() synchronously inside its tool.stream listener. Recheck closing/gate after dispatch before producing tool.preview. Already-dispatched stream events are not retroactively cancelled for other listeners.
  • Public core/session regression: complete 257 distinct server tools in a single still-live model response, then emit a late c0 delta. The response's existing CallRecord suppresses the delta before either legacy preview or new stream dispatch. A fresh collecting call in that same response remains accepted. No cache growth, new public API or provider-ID mapping.
  • The short coverage index maps normative/API/local-policy/application boundaries to implementation paths, exact tests/case IDs and unit/session/e2e/independent-black-box evidence levels.
  • Documents session-ended terminal exceptions, final-close application cleanup, async server-tool cancellation policy, cooperative side effects, negotiated capability vs provider argumentStreaming, and draft promotion requirements.
  • Explicit resource accounting: 256 bounds recently ended stream IDs, not open-call Maps, session bytes, durable idempotency or arbitrary late invalid sender traffic. Open collecting/running calls retain state until their defined lifecycle cleanup. No undefined resource/eviction policy is silently introduced.

Files Changed

  • packages/client/src/session.ts, packages/client/test/tool-streams.test.ts: two-line guard and four public API regression cases.
  • packages/core/src/session.ts, packages/core/test/tool-stream.test.ts: reuse existing issued-call records and one public session/model regression across tombstone eviction.
  • docs/TOOL_STREAM_CONTRACT.md, docs/ARCHITECTURE.md: 94-line contract/evidence index plus navigation.
  • packages/server/src/capabilities.ts: correct explanatory comment only; runtime capability rules unchanged.
  • Three website tools/client pages: terminal exception and cleanup/cooperative-cancellation clarifications.

Brief Explanation

Core ToolStreams still owns server lifecycle transitions; AgentSession owns invocation/response records; server only maps negotiated/legacy traffic; client owns local display cancellation and derives previews. Both repairs use existing state at the point where it can change or remain authoritative, rather than adding another tracker, unbounded cache or abstraction.

Separate reviewable commits: 4a3ec78 client fix, 46518f6 core fix, 879846a coverage/docs. No dependencies, manifests, lockfiles, schemas, normative prose, registry state, wire/API shapes, conformance profile or application-specific feature changed.

Testing

macOS 26.6.2 arm64; Node 22.23.3. All final runs below were in /Users/wangyeyu/Desktop/vRealTime, with native installed build tools; no temporary source copy or binary override.

  • Red before fixes: four client callback tests failed (one derived preview instead of none); the core regression failed with c0 phases start, arguments-complete, settled, start, arguments-delta. No private state injection or sleep was used. Both regressions then passed (25 tool-stream tests across two files).
  • npm test: 470 passed, 26 files (465 baseline + five regression cases).
  • npm run test:conformance: 168 passed, including existing five-case server-tool-stream positive/fault/replay/cleanup tests and all merged profiles; build and conformance typecheck included. No test(conformance): 客户端工具流预览、取消与重放观察一致性 #50 profile is claimed.
  • npm run test:e2e: 7 passed.
  • npm run typecheck: passed. npm run check:spec: passed, 23 schemas/1 capability/156 control vectors/9 audio vectors.
  • npm run check:budgets: passed, dependency/Node boundaries intact. Protocol 2.16 KB gzip/5 KB; core 5.11/15; client 5.26/20 (rounded; not a claim of byte-identical bundles).
  • npm run test:conformance:consumer: actual tarball outside the checkout, embedded official SDK drivers and all profiles/inventory checks passed; fullSuite remains incomplete.
  • npm run build --prefix website: passed, 38 pages, all internal links valid. Initial attempt lacked Astro; npm ci --prefix website --ignore-scripts --no-audit --no-fund installed the existing lockfile dependencies, then build passed. No manifest/lock change.
  • Coverage index relative paths and cited regression/duplicate test titles checked; git diff --check passed. No separate lint/format script is configured.
  • Python, standalone workerd, production SDK pack/consumer and publication/release dry-run not rerun: no Python/Workers/exports/package metadata changes; SDK source tests, e2e, normal build/budgets and actual conformance package installation were exercised. Nothing published. Hosted CI is separate evidence.

Unsure About

Implementation Order and Acceptance

All five #49 audit items are locally satisfied: evidence map, reproduced/repaired implementation gaps plus linked normative question, existing lifecycle regression preservation, honest draft status, and required checks. Checked implementation items mean local completion with this PR pending merge; they do not mean the changes are already on main. #49's author-owned checklist is minimally updated with this PR and explicit local-complete/pending-merge status; #22/#17 parent checklists are unchanged.

After merge, #49 can be closed as an audit/targeted-repair task if maintainers accept the explicitly linked normative follow-up and documented limits. It must not be interpreted as completing #50, #22, #17 or all tool-stream/identity/resource guarantees. No issue is automatically closed by this PR.

Keep main's public call ID mapping in the tool.call.delta guard, adapt the
tombstone-eviction test to public call IDs, and update the contract audit's
note on cross-session identifiers now that global-tool-ids-v1 has landed.
@austinchennn
austinchennn merged commit 894d5f9 into EmergentExit:main Oct 19, 2026
7 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.

2 participants