qwen-code/docs
ChiGao ce4b0cf629
feat(sdk,serve): DaemonTransport abstraction + ACP standard compliance (#5040)
* feat(sdk): DaemonTransport abstraction — pluggable transport for REST/ACP-HTTP/ACP-WS

- DaemonTransport interface with fetch + subscribeEvents
- RestSseTransport: extract current SSE logic from DaemonClient
- AcpWsTransport: WebSocket multiplexer + URL-to-JSON-RPC mapping
- AcpHttpTransport: POST /acp + session-scoped SSE
- AcpEventDenormalizer: JSON-RPC notification -> DaemonEvent
- AutoReconnectTransport: opt-in reconnect + fallback wrapper
- negotiateTransport(): auto-detect best transport via GET /capabilities
- Provider: DaemonWorkspaceProvider gains transport prop
- Server: GET /capabilities advertises supported transports
- Zero breaking changes: no transport = current REST behavior

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(design): include DaemonTransport design doc in implementation PR

* fix(sdk): address 6 verification findings — bundle size, WS hang, error types, ACP compat

- Remove ACP transport class re-exports from barrel (index.ts) to avoid
  ~19.7KB browser bundle bloat; keep type-only exports
- Fix WS dial hang: reject connect promise in onerror when not yet
  connected (Node WebSocket may only fire error, not close)
- Fix parked generators: maintain _activeGenerators set, abort all on
  WS close so generators throw DaemonTransportClosedError
- Forward abort signal through AcpHttpTransport.sendRequest to fetch
- Restore DaemonHttpError in RestSseTransport (was plain Error)
- ACP endpoint compat: extract connectionId from initialize, send
  Acp-Connection-Id header, add _qwen/ prefix for vendor methods,
  preserve real HTTP status in error mapping, fetch /capabilities
  from REST endpoint for correct shape

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): address 16 review findings + CI bundle size

- CI: move negotiateTransport to separate file, extract DaemonHttpError
  to break static import chain from barrel -> DaemonClient. Browser
  bundle drops from 136KB to 115KB, under the 116KB budget.
- Route table: extract shared acpRouteTable.ts, used by both transports.
  Unify method naming (remove _qwen/ prefix inconsistency).
- Token: move from URL query to Authorization header on WS upgrade
- Error type: DaemonHttpError extracted to DaemonHttpError.ts; import
  in RestSseTransport no longer pulls in DaemonClient.
- Init retry: reset failed initPromise so next call retries
- Reconnect mutex: prevent concurrent reconnect storms
- Generator queue: cap at 256, drop-oldest
- WS init timeout: 30s default
- negotiate: clear timer on all paths, catch dispose rejection
- Headers: forward init.headers in ACP transports via mergeHeaders()
- Dead code: remove unused pendingRequests/sseAbort fields
- Provider: dispose client on unmount
- Helpers: extract matchRoute/synthesizeResponse/jsonRpcErrorToHttpStatus/
  isRecord/composeAbortSignals to shared acpTransportUtils.ts
- Package exports: add deep import paths for ACP transports
- Tests: add AcpEventDenormalizer unit tests (17 cases)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): ESLint array-type rule — ReadonlyArray<T> → readonly T[]

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): fix 3 ACP wire bugs + bundle size + npm exports

Wire bugs (verified broken against real daemon):
1. AcpHttpTransport: read connectionId from response header + correct JSON path
2. AcpWsTransport: send token via Authorization header, not URL query
3. AcpEventDenormalizer: read params.update.sessionUpdate, not params.type

Bundle: remove negotiateTransport from barrel-reachable imports
Exports: add package.json deep import paths for ACP transports

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(sdk): comprehensive ACP transport test suite (~175 tests)

- RestSseTransport: fetch delegation, SSE subscribe, auth, timeout, signal
- AcpWsTransport: route mapping, token auth, event filtering, queue cap
- AcpHttpTransport: connectionId extraction, header injection, init retry
- AutoReconnectTransport: reconnect mutex, fallback, delegation
- negotiateTransport: capability probing, timeout, fallback
- acpRouteTable: URL→method mapping, param extraction

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): route table coverage, browser WS auth, header forwarding, capabilities type

- Route table: add file/stat/list/glob/write/edit paths (all DaemonClient URLs)
- Route table: add session diagnostic routes (context, tasks, stats, rewind, language)
- Route table: add bulk sessions/delete
- WS auth: document browser limitation, Node uses headers, browser needs proxy
- Headers: forward X-Qwen-Client-Id via JSON-RPC _meta in WS transport
- DaemonCapabilities: add transports field to SDK type
- Package exports: remove unreachable deep exports, document monorepo usage
- Provider bypass: document limitation for glob/stat/list in workspace actions

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): add missing detach + hooks routes per QA doc

Cross-referenced with daemon-acp-integration-qa.md route table.
Added POST /session/:id/detach and GET /session/:id/hooks.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(serve,sdk): enforce ACP standard session/new — always isolated session

ACP standard mandates session/new MUST create a new isolated session.

Server-side (dispatch.ts):
- Force sessionScope='thread' on /acp session/new, ignoring client params
- REST POST /session retains 'single' default for backward compat

SDK-side (acpRouteTable.ts):
- Strip sessionScope from session/new params in ACP transports
- Document that ACP follows the standard (no extensions)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(serve): ACP session/new returns standard models/modes fields

ACP standard NewSessionResponse includes optional `models` and `modes`
top-level fields alongside `configOptions`. Extract model/mode state
from configOptions and surface them as standard-shaped objects:
- models: { currentModelId, availableModels: [{id}] }
- modes:  { currentModeId, availableModes: [{id}] }

Also update test to verify sessionScope is always forced to 'thread'
(ACP standard compliance — session/new always creates isolated session).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* feat(serve): add standard ACP methods session/set_mode, session/set_model, session/fork

Align /acp endpoint with ACP standard protocol:

- session/set_mode: dedicated method for mode changes (standard)
  Maps to bridge.setSessionApprovalMode(). Params: {modeId, sessionId}
- session/set_model: dedicated method for model changes (unstable)
  Maps to bridge.setSessionModel(). Params: {modelId, sessionId}
- session/fork: create a branched copy of an existing session
  Maps to bridge.branchSession(). Response includes configOptions,
  models, modes per ACP standard.
- session/load, session/resume: responses now include configOptions,
  models, modes (per ACP LoadSessionResponse/ResumeSessionResponse)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(serve): TS2345 — pass persist: false to setSessionApprovalMode

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(webui): add dispose() to MockDaemonClient in provider tests

DaemonClient now has dispose() (called in provider cleanup effect).
Mock clients in test files need to implement it.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(serve): add sessionId pre-validation + remove type assertion

- session/set_mode, session/set_model: add explicit sessionId empty
  check before requireOwned (consistent with session/fork)
- session/set_model: remove `as unknown as` type assertion, pass
  proper {modelId, sessionId} matching SetSessionModelRequest

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk,serve): align route table with dispatcher + AcpHttp SSE response correlation

Route table:
- Add _qwen/ prefix to all vendor session/workspace methods
- Split workspace catch-all into granular dispatcher methods
- Fix session/branch → session/fork, model → session/set_model
- Remove routes with no dispatcher handler

AcpHttpTransport:
- Implement conn-scoped SSE stream for response correlation
- POST returns 202 (ack), real response rides SSE stream
- Map<id, {resolve, reject}> for pending request correlation

dispatch.ts:
- Remove session/set_mode, session/set_model from CONN_ROUTED_METHODS

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): bump browser bundle budget 116KB→118KB for transport abstraction

Main uses 117,753 bytes (99.1% of 116KB budget). The transport
abstraction adds ~1.5KB (DaemonTransport interface + RestSseTransport
default constructor in DaemonClient). Bump to 118KB (120,832 bytes).

Also change RestSseTransport to type-only export from barrel (class
is constructed internally by DaemonClient, not needed as a value
export for consumers).

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): fix 2 test failures — SSE error message + workspace catch-all route

- RestSseTransport: error message 'SSE response has no body' → 'No SSE body'
  (matches existing DaemonClient.test.ts assertion)
- acpRouteTable: re-add GET/POST /workspace/* catch-all after granular routes
  (AcpWsTransport.test.ts expects generic workspace path to resolve)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): align RestSseTransport test with updated error message

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-06-14 02:37:06 +08:00
..
design feat(sdk,serve): DaemonTransport abstraction + ACP standard compliance (#5040) 2026-06-14 02:37:06 +08:00
developers fix(docs): update Coding Plan model list and fix stale references in developer docs (#5054) 2026-06-13 01:34:14 +08:00
e2e-tests feat(worktree): Phase D — startup --worktree flag + symlinkDirectories + PR refs (#4381) 2026-05-27 17:04:51 +08:00
plans feat(core)!: redesign auto-compaction thresholds with three-tier ladder (#4345) 2026-05-25 21:11:08 +08:00
superpowers feat(core): durable cron jobs — /loop tasks that survive restarts (#5004) 2026-06-13 19:30:40 +08:00
users fix(serve): Add prompt queue backpressure (#5033) 2026-06-13 18:46:01 +08:00
verification/abort-controller-refactor fix(core): stop AbortSignal listener leak in long sessions (MaxListenersExceededWarning) (#4366) 2026-05-26 14:21:49 +08:00
_meta.ts feat: refactor docs 2025-12-05 10:51:57 +08:00
declarative-agents-port.md feat(core): port declarative-agent mcpServers + hooks (CC 2.1.168 parity follow-up) (#4996) 2026-06-12 14:15:51 +08:00
index.md fix: lint issues 2025-12-19 15:52:11 +08:00
yaml-parser-replacement.md feat(core): port declarative-agent mcpServers + hooks (CC 2.1.168 parity follow-up) (#4996) 2026-06-12 14:15:51 +08:00