Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions docs/users/qwen-serve.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,22 +190,21 @@ Stage 1's contract is sized for prototyping. Per [#3889 chiga0 downstream-consum

**Blockers for serious downstream use:**

1. **Per-request `sessionScope` override** on `POST /session` — today the daemon-wide default is the only setting; a VSCode extension can't say "I want a private session for this window" against a daemon configured for shared sessions.
2. **`loadSession` / `unstable_resumeSession` over HTTP** — without this, no integration can survive a child crash or daemon restart, and any orchestrator coordinating the daemon can't recover state either.
3. **Persistent client identity (pair tokens + per-client revocation)** — Stage 1 uses one shared bearer; a leaked token revokes everyone, and `originatorClientId` is client-self-declared rather than daemon-stamped from authenticated identity.
1. **`loadSession` / `unstable_resumeSession` over HTTP** — without this, no integration can survive a child crash or daemon restart, and any orchestrator coordinating the daemon can't recover state either.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Now that per-request sessionScope is no longer a blocker, the user guide should also tell client authors how to use the shipped override. This page currently has no mention of sessionScope or the session_scope_override capability, while the developer protocol docs describe POST /session accepting sessionScope: "thread" and recommend gating it on /capabilities. Readers of the user guide can still come away thinking same-workspace clients must share the daemon-wide default session, which is especially risky for IDE/window-style integrations that need isolation.

Consider adding a short POST /session note or example here that mirrors the developer docs: sessionScope: "thread" forces a fresh session, the default single may attach to an existing one, and clients should check /capabilities.features for session_scope_override before sending the field.

— gpt-5.5 via Qwen Code /review

2. **Persistent client identity (pair tokens + per-client revocation)** — Stage 1 uses one shared bearer; a leaked token revokes everyone, and `originatorClientId` is client-self-declared rather than daemon-stamped from authenticated identity.

**Reliability baseline:**

4. **Client-initiated heartbeat path** — distinguish "agent thinking" from "daemon dead" without waiting for the 15s server heartbeat.
5. **`permission_already_resolved` event** when a vote loses the first-responder race — currently UIs have to infer state from a `404`.
6. **Larger / per-session-configurable replay ring** — default 4000 covers short drops; mobile / chatty-turn workloads need 8000+ or per-session config.
7. **`slow_client_warning` event before `client_evicted`** — soft backpressure so well-behaved slow clients can self-throttle (trim render depth, drop chunks) before being terminated.
3. **Client-initiated heartbeat path** — distinguish "agent thinking" from "daemon dead" without waiting for the 15s server heartbeat.
4. **`permission_already_resolved` event** when a vote loses the first-responder race — currently UIs have to infer state from a `404`.
5. **Larger / per-session-configurable replay ring** — default 4000 covers short drops; mobile / chatty-turn workloads need 8000+ or per-session config.
6. **`slow_client_warning` event before `client_evicted`** — soft backpressure so well-behaved slow clients can self-throttle (trim render depth, drop chunks) before being terminated.

**Integration ergonomics:**

8. **`POST /session/:id/_meta` for IM-style context** — per-session key-value attached to subsequent prompts (chat id, sender, thread id) replaces the per-channel improvisation.
9. **`/capabilities` actual feature negotiation** — `protocol_versions: { acp: '0.14.x', daemon_envelope: 1 }` so clients can detect drift instead of falling through to "unknown frame, ignore".
10. **First-class durability documentation** (this section) — already shipped above.
7. **`POST /session/:id/_meta` for IM-style context** — per-session key-value attached to subsequent prompts (chat id, sender, thread id) replaces the per-channel improvisation.
8. **`/capabilities` actual feature negotiation** — `protocol_versions: { acp: '0.14.x', daemon_envelope: 1 }` so clients can detect drift instead of falling through to "unknown frame, ignore".
9. **First-class durability documentation** (this section) — already shipped above.

The full convergence roadmap is tracked on [#3803](https://github.com/QwenLM/qwen-code/issues/3803).

Expand Down
6 changes: 5 additions & 1 deletion integration-tests/cli/qwen-serve-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,18 @@ describe('qwen serve — CORS browser-origin denial', () => {
});

describe('qwen serve — capabilities envelope', () => {
it('advertises all 9 Stage 1 features', async () => {
it('advertises all 10 Stage 1 features', async () => {
const caps = await client.capabilities();
expect(caps.v).toBe(1);
expect(caps.mode).toBe('http-bridge');
// Order must match `SERVE_CAPABILITY_REGISTRY` in
// `packages/cli/src/serve/capabilities.ts` and the unit-level
// `EXPECTED_STAGE1_FEATURES` in `packages/cli/src/serve/server.test.ts`.
expect(caps.features).toEqual([
'health',
'capabilities',
'session_create',
'session_scope_override',
'session_list',
'session_prompt',
'session_cancel',
Expand Down
Loading