docs(serve): v0.16-alpha known limits + SDK QWEN_SERVER_TOKEN env fallback (PR 27)#4473
Conversation
…lback (PR 27) First PR in the F5 release chain (PR 27 → 28 → 30a → 31) per the 2026-05-24 v0.16-alpha scope freeze in #4175 (text-only chat / coding + local-only deployment). ## SDK ergonomic micro-change (~50 LOC + 4 tests) `DaemonClient` constructor falls back to `QWEN_SERVER_TOKEN` env var when `opts.token` is absent — closes the asymmetry where the daemon side already honors this var (--token CLI flag fallback, already in main since PR 15) but the SDK forced clients to thread it through every construction. Properties: - Browser-safe via `globalThis.process` indirection (the SDK is imported by @qwen-code/webui; literal process.env access would explode at module load on browser bundles) - Whitespace stripped (matches daemon-side trim — handy for `export QWEN_SERVER_TOKEN=\"\$(cat token.txt)\"` where cat adds a trailing newline) - Empty / whitespace-only treated as unset (a stale `export QWEN_SERVER_TOKEN=\"\"` won't accidentally send Authorization: Bearer with no token) - Resolved at construction, not lazily per-request (later process.env mutations don't affect already-built clients) - Explicit opts.token wins over env Tests: 4 new in DaemonClient.test.ts `bearer auth` describe covering env fallback / explicit-wins / empty-treated-unset / whitespace-stripped. Plus a defensive snapshot/restore on the existing 'omits Authorization when no token' test so an inherited test-runner export of QWEN_SERVER_TOKEN doesn't turn that assertion into a false positive. This SDK fallback is the entire ergonomic replacement for PR 29's SDK env/file fallback. PR 29's other features (auto-gen daemon token, instance-path keying, stale cleanup) remain deferred to v0.16.x — all are DX improvements over the boot-time security gate already shipped in PR 15. ## v0.16-alpha docs (~120 LOC markdown) - docs/users/qwen-serve.md: new "v0.16-alpha known limits" section enumerating product surface (text-only ✅, multimodal ❌), deployment surface (local launchers ✅, containerized ❌, multi- daemon ❌, BYO-token ✅), and hardening posture (boot security gate ✅, mutation gate ✅, MCP guardrails ✅, prompt absolute deadline ⏸️, rate limiting ⏸️, --max-body-size ⏸️). Adds an alpha banner at the top of the file. - docs/developers/examples/daemon-client-quickstart.md: documents the SDK env fallback in both the Hello-daemon intro and the Authentication section, with the "export + no-token-arg" recommended path called out for local dev. Verification: 125/125 DaemonClient.test.ts pass (121 existing + 4 new); 4/4 daemon-public-surface.test.ts pass (constructor signature unchanged); tsc clean on packages/sdk-typescript; eslint --max-warnings 0 clean on touched .ts files. Part of #4175.
📋 Review SummaryThis PR implements two key changes for the v0.16-alpha release: (1) SDK 🔍 General Feedback
🎯 Specific Feedback🟢 Medium
🔵 Low
✅ Highlights
|
There was a problem hiding this comment.
Pull request overview
Adds v0.16-alpha “known limits” documentation for qwen serve and introduces an SDK ergonomics change where DaemonClient can automatically pick up QWEN_SERVER_TOKEN from the environment when opts.token is not provided.
Changes:
- SDK:
DaemonClientconstructor falls back toQWEN_SERVER_TOKEN(browser-safe viaglobalThis.process, trims whitespace, treats empty as unset). - Tests: expands
DaemonClientbearer-auth coverage with env-fallback cases and hardens the “no token” test against inherited environment state. - Docs: adds a v0.16-alpha banner + “known limits” section to
qwen servedocs and documents the SDK env fallback in the daemon client quickstart.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/sdk-typescript/src/daemon/DaemonClient.ts | Adds readTokenFromEnv() and constructor fallback to QWEN_SERVER_TOKEN. |
| packages/sdk-typescript/test/unit/DaemonClient.test.ts | Adds env-fallback tests and isolates env state for the “no token” assertion. |
| docs/users/qwen-serve.md | Adds v0.16-alpha banner and a “known limits” section for deferred scope. |
| docs/developers/examples/daemon-client-quickstart.md | Documents env fallback usage patterns in the SDK quickstart and auth section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
T1 [copilot DaemonClient.ts:144 — stale line refs in readTokenFromEnv
JSDoc]: removed `runQwenServe.ts:175` (token resolution actually
lives at line 302-318 today, would drift again on next refactor)
and `docs/users/qwen-serve.md:173`. Replaced with stable
symbol/section references ("runQwenServe token-resolution path";
"qwen-serve user guide CLI flags section").
T2 [copilot daemon-client-quickstart.md:33 — `~/.qwen/server-token`
implies built-in path that doesn't exist]: PR 27 explicitly defers
token auto-generation + file-store fallback (PR 29 deferred features).
The example incorrectly suggested a standard file location.
Replaced with two explicit user-managed alternatives:
- `openssl rand -hex 32` one-shot
- `cat ./my-token-file` user-managed file
Both threads were accurate suggestions caught at the right time
(zero behavior change; pure docstring/example accuracy).
Verification: 125/125 DaemonClient tests pass; tsc + eslint clean
on touched files.
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
Squashed feature work from daemon_mode_b_main branch, rebased onto latest main to establish proper merge-base and clean PR diff. Original commits: - perf(core): F2 cleanup PR A — R9/W11/W12/R10 (post-merge follow-ups) (#4411) - refactor(acp-bridge): F1 test split — lift bridge.test.ts (6861 LOC) to acp-bridge (#4445) - fix(core): F2 cleanup PR B — self-heal observability (W133-a + W134) (#4460) - feat(sdk/daemon-ui): unified completeness follow-up to #4328 (#4353) - docs(serve): v0.16-alpha known limits + SDK QWEN_SERVER_TOKEN env fallback (PR 27) (#4473) - docs(deploy): local launch templates for v0.16-alpha (PR 30a) (#4483) - feat(daemon+sdk): cross-client real-time sync completeness (#4484) - feat(serve): add POST /session/:id/recap (#4504) - feat(daemon): add voterClientId to permission_resolved (A4) (#4539) - feat(serve): --allow-origin <pattern> CORS allowlist (T2.4 #4514) (#4527) - feat(daemon): in-session model switch reaches the bus (A1) (#4546) - feat(serve): prompt absolute deadline + SSE writer idle timeout (#4514 T2.9) (#4530) - Feat/daemon react cli (#4380)
…lback (PR 27) (#4473) * docs(serve): v0.16-alpha known limits + SDK QWEN_SERVER_TOKEN env fallback (PR 27) First PR in the F5 release chain (PR 27 → 28 → 30a → 31) per the 2026-05-24 v0.16-alpha scope freeze in #4175 (text-only chat / coding + local-only deployment). ## SDK ergonomic micro-change (~50 LOC + 4 tests) `DaemonClient` constructor falls back to `QWEN_SERVER_TOKEN` env var when `opts.token` is absent — closes the asymmetry where the daemon side already honors this var (--token CLI flag fallback, already in main since PR 15) but the SDK forced clients to thread it through every construction. Properties: - Browser-safe via `globalThis.process` indirection (the SDK is imported by @qwen-code/webui; literal process.env access would explode at module load on browser bundles) - Whitespace stripped (matches daemon-side trim — handy for `export QWEN_SERVER_TOKEN=\"\$(cat token.txt)\"` where cat adds a trailing newline) - Empty / whitespace-only treated as unset (a stale `export QWEN_SERVER_TOKEN=\"\"` won't accidentally send Authorization: Bearer with no token) - Resolved at construction, not lazily per-request (later process.env mutations don't affect already-built clients) - Explicit opts.token wins over env Tests: 4 new in DaemonClient.test.ts `bearer auth` describe covering env fallback / explicit-wins / empty-treated-unset / whitespace-stripped. Plus a defensive snapshot/restore on the existing 'omits Authorization when no token' test so an inherited test-runner export of QWEN_SERVER_TOKEN doesn't turn that assertion into a false positive. This SDK fallback is the entire ergonomic replacement for PR 29's SDK env/file fallback. PR 29's other features (auto-gen daemon token, instance-path keying, stale cleanup) remain deferred to v0.16.x — all are DX improvements over the boot-time security gate already shipped in PR 15. ## v0.16-alpha docs (~120 LOC markdown) - docs/users/qwen-serve.md: new "v0.16-alpha known limits" section enumerating product surface (text-only ✅, multimodal ❌), deployment surface (local launchers ✅, containerized ❌, multi- daemon ❌, BYO-token ✅), and hardening posture (boot security gate ✅, mutation gate ✅, MCP guardrails ✅, prompt absolute deadline ⏸️, rate limiting ⏸️, --max-body-size ⏸️). Adds an alpha banner at the top of the file. - docs/developers/examples/daemon-client-quickstart.md: documents the SDK env fallback in both the Hello-daemon intro and the Authentication section, with the "export + no-token-arg" recommended path called out for local dev. Verification: 125/125 DaemonClient.test.ts pass (121 existing + 4 new); 4/4 daemon-public-surface.test.ts pass (constructor signature unchanged); tsc clean on packages/sdk-typescript; eslint --max-warnings 0 clean on touched .ts files. Part of #4175. * fix(sdk): #4473 round 1 fold-in — 2 copilot doc threads adopted T1 [copilot DaemonClient.ts:144 — stale line refs in readTokenFromEnv JSDoc]: removed `runQwenServe.ts:175` (token resolution actually lives at line 302-318 today, would drift again on next refactor) and `docs/users/qwen-serve.md:173`. Replaced with stable symbol/section references ("runQwenServe token-resolution path"; "qwen-serve user guide CLI flags section"). T2 [copilot daemon-client-quickstart.md:33 — `~/.qwen/server-token` implies built-in path that doesn't exist]: PR 27 explicitly defers token auto-generation + file-store fallback (PR 29 deferred features). The example incorrectly suggested a standard file location. Replaced with two explicit user-managed alternatives: - `openssl rand -hex 32` one-shot - `cat ./my-token-file` user-managed file Both threads were accurate suggestions caught at the right time (zero behavior change; pure docstring/example accuracy). Verification: 125/125 DaemonClient tests pass; tsc + eslint clean on touched files.
Summary
First PR in the F5 release chain (PR 27 → PR 28 → PR 30a → PR 31) per the 2026-05-24 v0.16-alpha scope freeze in #4175. v0.16-alpha targets text-only chat / coding with local-only deployment.
Two changes bundled:
1. SDK
DaemonClientenv fallback (~50 LOC + 4 tests)DaemonClientconstructor now falls back toQWEN_SERVER_TOKENwhenopts.tokenis absent — closes the asymmetry where the daemon side already honors this env var (--tokenCLI flag fallback, in main since PR 15) but the SDK forced clients to thread the value through every construction.This is the entire ergonomic replacement for PR 29's SDK env/file fallback. PR 29's other features (auto-gen daemon token, instance-path keying, stale cleanup) remain deferred to v0.16.x per the scope freeze — all are DX improvements over the boot-time security gate already shipped in PR 15.
Properties:
globalThis.processindirection (the SDK is imported by@qwen-code/webui; literalprocess.envaccess would explode at module load on browser bundles)export QWEN_SERVER_TOKEN="$(cat token.txt)"wherecatadds a trailing newline)export QWEN_SERVER_TOKEN=""won't accidentally sendAuthorization: Bearerwith no token)process.envmutations don't affect already-built clients)opts.tokenwins over env (existing API behavior preserved)2. v0.16-alpha known limits + scope docs (~120 LOC markdown)
docs/users/qwen-serve.md: new top-of-file alpha banner + a comprehensive## v0.16-alpha known limitssection enumerating the deferred surface (text-only ✅ vs multimodal ❌, local launchers ✅ vs containerized ❌, BYO-token ✅ vs auto-gen ❌, etc.). Each entry links to the v0.16.x or v0.17 destination per the scope freeze.docs/developers/examples/daemon-client-quickstart.md: documents the SDK env fallback in both the Hello-daemon intro snippet and the Authentication section. Shows the recommended "export + no-token-arg" pattern for local dev.Files changed
packages/sdk-typescript/src/daemon/DaemonClient.tsreadTokenFromEnv()helper + constructor fallback (~50 LOC)packages/sdk-typescript/test/unit/DaemonClient.test.tsbearer authdescribe + defensive snapshot on the existing "omits Authorization" testdocs/users/qwen-serve.mdv0.16-alpha known limitssectiondocs/developers/examples/daemon-client-quickstart.mdTest plan
npx tsc --noEmit -p packages/sdk-typescript/tsconfig.json— cleannpm test --workspace=@qwen-code/sdk -- DaemonClient— 125/125 pass (121 existing + 4 new)npm test --workspace=@qwen-code/sdk -- daemon-public-surface— 4/4 pass; constructor signature + exported types unchanged (no breaking change)eslint --max-warnings 0clean on the 2 touched.tsfilesBackward compatibility
DaemonClientconstructor signature unchanged.opts.tokenstill wins when explicitly passed.attaches Authorization: Bearer when token is set+omits Authorization when no token) keep passing. The latter got a defensive snapshot/restore around it so an inherited test-runner export ofQWEN_SERVER_TOKENcan't turn it into a false positive.globalThis.processaccess pattern matches existing browser-safe code in the SDK.@qwen-code/sdkstill ships at 0.1.7 in this PR; the minor bump to 0.2.0 (with this fallback as one of the motivating additions) lands in PR 28's npm publish scaffolding.Follow-ups (out of scope)
@qwen-code/sdkto 0.2.0 + ships the npm publish scaffolding for the v0.16-alpha cut🤖 Generated with Qwen Code