mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-19 16:28:28 +00:00
CRITICAL regression fix:
- Child env scrub flipped from allowlist back to denylist (just
QWEN_SERVER_TOKEN). The earlier allowlist was overzealous: it
dropped OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY /
QWEN_* / DASHSCOPE_API_KEY / custom modelProviders[].envKey, all of
which the agent legitimately needs to authenticate to the LLM.
Daemon-mode users with env-only auth would start the daemon, attach
a session, then watch every prompt fail with auth errors. Threat-
model rationale documented at the call site: prompt-injected shell
tools can already read ~/.bashrc, ~/.aws/credentials, etc., so env
passthrough isn't the security boundary; the user-as-trust-root is.
QWEN_SERVER_TOKEN stays scrubbed to prevent agent → its own daemon
escalation.
Other code fixes:
- doSpawn no longer tears down the session when create-time model
switch fails. The session is still operational on the agent's
default model; tearing it down left the caller with a 500 and no
sessionId to retry against. The model_switch_failed SSE event is
the visible signal; caller can retry via POST /session/:id/model
once they have the sessionId.
- doSpawn now uses applyModelServiceId for the create-time model
switch (was raw conn.unstable_setSessionModel + withTimeout). The
helper races against transportClosedReject too, so a child crash
during model switch fails fast instead of consuming the full init
timeout.
- sendPrompt's abort handler now calls cancelPendingForSession
before the ACP cancel notification (matching cancelSession). A
client disconnecting mid-permission was leaving the agent stuck
waiting on a vote that no SSE subscriber would ever cast.
- shutdown() and killSession() now publish a terminal `session_died`
SSE event before closing the bus. Previously the channel.exited
handler's "byId.get(...) !== entry" guard short-circuited (entry
already removed), so SSE subscribers couldn't tell daemon shutdown
from a transient network error.
- Express error middleware now special-cases `status: 413`
(EntityTooLargeError from body-parser when a request exceeds the
10 MB JSON limit) and returns a JSON 413 instead of a misleading
500.
- /health is now registered BEFORE bearerAuth middleware, so
liveness probes work without credentials when the daemon was
started with --token. CORS deny + Host allowlist still apply.
- SSE writes serialize through a per-connection chain so the
heartbeat interval can no longer interleave with the main event-
write loop. Two concurrent res.write calls would otherwise bypass
the backpressure guard and could interleave bytes between SSE
frames on the wire.
SDK:
- abortTimeout / composeAbortSignals exported for direct unit
testing. The existing test claimed to cover the polyfill paths via
subscribeEvents, but subscribeEvents calls _fetch directly (not
fetchWithTimeout), so composeAbortSignals never ran in the test.
New tests exercise the helpers directly across native + polyfill
runtimes.
Doc accuracy fixes:
- daemon-client-quickstart.md: createOrAttachSession({ cwd: ... })
→ ({ workspaceCwd: ... }) (SDK type), client.sendPrompt → prompt,
client.cancelSession → cancel. The example wouldn't typecheck.
- qwen-serve.md: "binds one workspace" claim removed — a single
daemon hosts sessions for any cwd the caller passes; the
per-instance constraint is per-user / scale, not per-workspace.
Auth verification example switched from /health to /capabilities
(since /health is now exempt from bearer auth).
- qwen-serve-protocol.md: env var was QWEN_E2E_LLM, real var is
SKIP_LLM_TESTS (inverted polarity). Streaming test count was 4,
actually 3. Added Stage 1 limitation notes for "no DELETE
/session" and "no permission timeout". Added client-side
ring-buffer gap detection guidance for Last-Event-ID reconnect.
Test updates:
- httpAcpBridge.test.ts: rewrote two tests for the new
doSpawn-on-model-switch-fail contract (publish event, keep
session). Updated shutdown-closes-subscriptions test to expect
the new terminal `session_died` frame.
- server.test.ts: switched bearer-auth rejection probes from
/health to /capabilities (since /health is now exempt). Added a
test that locks /health's exemption.
|
||
|---|---|---|
| .. | ||
| design | ||
| developers | ||
| plans | ||
| users | ||
| _meta.ts | ||
| index.md | ||