Skip to content
Closed
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
41 changes: 24 additions & 17 deletions docs/developers/daemon-client-adapters/channel-web.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Channel And Web Backend Daemon Adapter Draft
# Channel And Web Backend Daemon Adapter Spike

## Goal

Let channel adapters and web chat backends consume `qwen serve` through
`DaemonSessionClient` while keeping existing channel ACP subprocess behavior as
the default.
Document the default-off `DaemonChannelBridge` spike for server-side channel
and web backends.

As of the 2026-05-19 architecture decision, web chat / web terminal are the
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] All 3 files add "As of the 2026-05-19 architecture decision" but no ADR, design doc, or decision record exists in the repository for this date. Future readers have no way to verify what this decision entailed, who made it, or whether it has since been superseded.

Suggested fix: Add an ADR in .qwen/design/, link to the relevant GitHub discussion, or soften the reference (e.g., "As of a May 2026 architecture direction...").

— qwen-latest-series-invite-beta-v28 via Qwen Code /review

first daemon-native client targets. Channel adapters should continue to use the
existing ACP subprocess behavior by default; daemon channel integration remains
future / behind-flag evaluation.

This draft covers server-side clients only:
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.

[Critical] The title was changed from "Draft" to "Spike" but this line still reads "This draft covers server-side clients only". Internal inconsistency within the same file.

Suggested change
This draft covers server-side clients only:
This document covers server-side clients only:

— qwen-latest-series-invite-beta-v28 via Qwen Code /review


Expand All @@ -16,13 +20,13 @@ The daemon currently rejects browser `Origin` requests by design.

## Proposed Entry Points

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] "Proposed historical channel backend experiment" — "Proposed" (forward-looking) contradicts "historical" (past). Something cannot be simultaneously proposed for the future and consigned to history. The intent appears to be describing this as a historical reference, so the word "Proposed" should be removed.

Suggested change
Historical channel backend experiment, not a wired command today:

— DeepSeek/deepseek-v4-pro via Qwen Code /review

Channel backend:
Proposed historical channel backend experiment, not a wired command today:

```bash
QWEN_CHANNEL_DAEMON_URL=http://127.0.0.1:4170 qwen channel start telegram
```

Web backend:
Web backend / BFF target:

```bash
QWEN_WEB_DAEMON_URL=http://127.0.0.1:4170 qwen web-chat-backend
Expand All @@ -46,7 +50,9 @@ default and owns daemon session state inside the backend process.
3. Submit inbound user text with `session.prompt()`.
4. Subscribe to `session.events()` and collect assistant text chunks.
5. Send final text back through the platform adapter.
6. Cast permission votes through `session.respondToPermission()`.
6. Cast permission votes through `session.respondToSessionPermission()` when
`caps.features.session_permission_vote` is advertised; use the legacy
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] "use the legacy request-id route" — the legacy method (respondToPermission) is never explicitly named. A maintainer unfamiliar with the permission API evolution (respondToPermission → respondToSessionPermission) must grep the codebase to find the correct fallback. Consider naming it explicitly.

Suggested change
`caps.features.session_permission_vote` is advertised; use the legacy
use the legacy `respondToPermission` request-id route only for explicitly single-user or older-daemon fallback.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

request-id route only for explicitly single-user or older-daemon fallback.
7. Cancel active work through `session.cancel()`.

## Minimal Web Backend Flow
Expand All @@ -61,9 +67,9 @@ Browser clients must not receive daemon bearer tokens.

## Session Isolation Constraint

Current daemon Stage 1 behavior is effectively `sessionScope: single` at the
daemon setting level. Until per-request `sessionScope` lands, multi-user channel
or web deployments must choose one of these safe shapes:
Multi-user channel or web deployments must explicitly isolate sessions. Use
per-request `sessionScope: 'thread'` when supported; otherwise choose one of
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] The old text explicitly stated "Current daemon Stage 1 behavior is effectively sessionScope: single at the daemon setting level". This PR replaced it with "when supported" — a hedge that obscures whether sessionScope: 'thread' actually exists at the daemon server level (code search shows sessionScope type exists in channels but the daemon server core has zero references to it).

Suggested fix: Restore the diagnostic: "As of this spike, the daemon does not support per-request sessionScope. Until it does, multi-user deployments must choose one of these isolation shapes:"

— qwen-latest-series-invite-beta-v28 via Qwen Code /review

these safe shapes:

- one daemon per channel thread / web room
- one daemon per user workspace
Expand All @@ -85,7 +91,7 @@ Do not silently multiplex unrelated channel threads into one daemon session.

Unknown daemon events must be ignored or forwarded as debug metadata, not fatal.

The bridge is not wired into `qwen channel start` yet. Existing Telegram,
The bridge is not wired into `qwen channel start` by default. Existing Telegram,
Weixin, Dingtalk, plugin channel, and browser behavior remains unchanged.

## Explicit Non-Goals
Expand All @@ -111,10 +117,11 @@ Weixin, Dingtalk, plugin channel, and browser behavior remains unchanged.
- Smoke-test one single-user channel backend against local `qwen serve`.
- Smoke-test browser -> BFF -> daemon without exposing daemon token.

## Blockers Before Default Migration
## Current Follow-Up Direction
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] The old "Blockers Before Default Migration" sections across all 3 files were explicit checklists of hard prerequisites (session-scoped permission route, daemon-stamped client identity, FileSystemService boundary, session lifecycle close/delete). The new "Current Follow-Up Direction" prose mentions these concepts vaguely, losing the gating semantics. A future implementer scanning the doc will not see a clear stop-sign.

Suggested fix: Add a brief "Security Prerequisites" subsection within this section listing the unresolved security items (client identity, session-scoped permission, filesystem boundary).

— qwen-latest-series-invite-beta-v28 via Qwen Code /review


- Per-request `sessionScope`.
- Session metadata + close/delete lifecycle.
- Daemon-stamped client identity.
- Session-scoped permission route.
- Read-only diagnostics for MCP, skills, providers, and environment.
- Prioritize web chat / web terminal daemon integration first.
- Keep channel adapters on the existing ACP bridge by default.
- Revisit daemon channel integration only after web contract, runtime
diagnostics, identity, permission, and session lifecycle semantics are stable.
- Treat this spike as a server-side bridge reference, not a default migration
checklist.
35 changes: 21 additions & 14 deletions docs/developers/daemon-client-adapters/ide.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# IDE Daemon Adapter Draft
# IDE Daemon Adapter Spike

## Goal

Let the VS Code companion extension dogfood Mode B by connecting from the
extension host to `qwen serve` through `DaemonSessionClient`.
Document the default-off IDE daemon adapter spike.

As of the 2026-05-19 architecture decision, the VS Code companion should keep
the existing `--acp` child path as its default integration. A daemon-backed IDE
adapter remains future / behind-flag evaluation after the web chat / web
terminal contract and daemon control-plane parity are stable.

The webview must not call the daemon directly. The extension host owns daemon
URL, token, session id, and SSE replay state, then forwards sanitized app events
to the webview.

## Proposed Entry Point
## Historical Experimental Entry Point

VS Code settings:

Expand Down Expand Up @@ -37,7 +41,9 @@ QWEN_IDE_DAEMON_URL=http://127.0.0.1:4170 code .
6. Send user prompts through `session.prompt()`.
7. Route cancel/model switch through `session.cancel()` and
`session.setModel()`.
8. Route permission decisions through `session.respondToPermission()`.
8. Route permission decisions through `session.respondToSessionPermission()`
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] The permission-routing guidance says "when advertised; fall back to the legacy permission route" but does not name the capability key (caps.features.session_permission_vote) that channel-web.md explicitly documents. An IDE adapter implementer reading only this file would not know which capability flag to check. Add the exact key for consistency across the doc set.

Suggested change
8. Route permission decisions through `session.respondToSessionPermission()`
Route permission decisions through `session.respondToSessionPermission()`
when `caps.features.session_permission_vote` is advertised; fall back to the legacy `respondToPermission` route only for older daemons.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

when advertised; fall back to the legacy permission route only for older
daemons.

## Relationship To Existing ACP Connection

Expand All @@ -55,8 +61,8 @@ If an event cannot be faithfully mapped yet, the daemon path should surface a
clear unsupported-state warning rather than silently pretending parity.

This PR adds `DaemonIdeConnection` as the locally verifiable extension-host
adapter spike. It is not wired into the default `QwenAgentManager` path yet, so
existing VS Code behavior remains ACP subprocess based.
adapter spike. It is not wired into the default `QwenAgentManager` path.
Existing VS Code behavior remains ACP subprocess based.

## Event Mapping Contract

Expand Down Expand Up @@ -112,11 +118,12 @@ the daemon.
- permission UI can resolve a request
- SSE reconnect uses tracked `Last-Event-ID`

## Blockers Before Default Migration
## Current Follow-Up Direction

- Typed daemon event schema.
- Daemon-stamped client identity.
- Session-scoped permission route.
- Read-only runtime diagnostics.
- FileSystemService boundary and safe file read routes.
- Output sink refactor for CLI/TUI parity.
- Keep the existing ACP subprocess path as the default IDE path.
- Revisit daemon IDE integration later in phases:
1. web contract plus workspace/path identity checks
2. editor-context routing plus auth/status UI
3. control-plane parity
- Treat this spike as future-migration reference, not an active default
migration checklist.
46 changes: 27 additions & 19 deletions docs/developers/daemon-client-adapters/tui.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# TUI Daemon Adapter Draft
# TUI Daemon Adapter Spike

## Goal

Add a flag-gated TUI transport that talks to `qwen serve` through
`DaemonSessionClient` instead of creating an in-process `Config` + agent
runtime.
Document the default-off `DaemonTuiAdapter` spike that was added while
evaluating Mode B client integration.
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.

[Critical] "Mode B" is retained here but all other "Mode B" references were removed from ide.md and channel-web.md by this PR. It is now an orphaned term, undefined anywhere in the doc set. A reader encountering this file for the first time has no way to understand what "Mode B" refers to.

Suggested change
evaluating Mode B client integration.
evaluating daemon-backed client integration.

— qwen-latest-series-invite-beta-v28 via Qwen Code /review


This is a dogfood path for Mode B client migration. It must not replace the
default TUI path until output sinks, typed daemon events, session-scoped
permission, and lifecycle diagnostics are stable.
As of the 2026-05-19 architecture decision, native local TUI is not planned to
default-migrate to daemon HTTP/SSE. The normal `qwen` terminal path remains a
long-term direct runtime / streamJson / Ink path because it avoids an extra
localhost HTTP server hop and keeps the local UX simpler and more reliable.

## Proposed Entry Point
The useful follow-up from this spike is source-adapter / reducer / terminal
render-core extraction so native TUI and web terminal can share view-model and
rendering logic without forcing native TUI through daemon transport.

## Historical Experimental Entry Point

```bash
QWEN_DAEMON_URL=http://127.0.0.1:4170 qwen --experimental-daemon-tui
Expand All @@ -37,9 +41,10 @@ The CLI should refuse this mode unless both are true:
5. Submit user prompts through `session.prompt()`.
6. Route cancel through `session.cancel()`.
7. Route model switch through `session.setModel()`.
8. Route permission votes through `session.respondToPermission()`.
8. Route permission votes through `session.respondToSessionPermission()` when
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] The new permission-routing guidance says TUI should call session.respondToSessionPermission(), but the actual DaemonTuiAdapter implementation still calls session.respondToPermission() in both approve/reject paths. IDE and channel currently do the same in their adapter implementations, but those two docs hedge this as future/behind-flag evaluation; the TUI doc keeps describing a concrete experimental flow. That makes the spike doc look already aligned with the session-scoped permission route when the adapter code is not.

Suggested change
8. Route permission votes through `session.respondToSessionPermission()` when
8. Route permission votes through the legacy request-id permission route today;
migrate to `session.respondToSessionPermission()` once the adapter is updated
to gate on `caps.features.session_permission_vote`.

— gpt-5.5 via Qwen Code /review

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] Same capability-key gap as ide.md: the permission-routing guidance omits the exact capability flag caps.features.session_permission_vote that channel-web.md documents. Add it for cross-file consistency.

Suggested change
8. Route permission votes through `session.respondToSessionPermission()` when
Route permission votes through `session.respondToSessionPermission()` when
`caps.features.session_permission_vote` is advertised; fall back to the legacy `respondToPermission` route only for older daemons.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

advertised; fall back to the legacy permission route only for older daemons.

## Rendering Contract
## Rendering Contract Reference

The first implementation adds `DaemonTuiAdapter`, a locally verifiable reducer
and transport spike. It maps only these daemon events:
Expand All @@ -54,15 +59,17 @@ and transport spike. It maps only these daemon events:
| `model_switched` | Update footer/model display |
| `session_died` | Show disconnected state and stop streaming |

Unknown events must be ignored, not fatal. Typed event reducers will land in a
later protocol PR.
Unknown events must be ignored, not fatal. Typed event reducers should stay in
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] "Typed event reducers should stay in the daemon client/protocol layer, not in server internals" — this is a design constraint with no described enforcement mechanism. Since this doc is now framed as a Spike (historical reference), future implementers are unlikely to encounter or remember this rule. Consider either adding a note about how this constraint is enforced (lint rule, code review checklist, test), or softening the language if enforcement is aspirational.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

the daemon client/protocol layer, not in server internals, so server transport
code does not grow UI-specific state machines.

The adapter is not wired into the default Ink app yet. Existing interactive TUI,
The adapter is not wired into the default Ink app. Existing interactive TUI,
JSONL, stream-json, and dual-output behavior remains unchanged.

## Explicit Non-Goals

- Do not remove the current TUI in-process runtime.
- Do not make daemon transport the default native TUI path.
- Do not change JSONL, stream-json, or dual-output behavior in this PR.
- Do not expose file CRUD, MCP management, memory CRUD, or provider/auth
mutation through TUI yet.
Expand All @@ -87,10 +94,11 @@ JSONL, stream-json, and dual-output behavior remains unchanged.
- permission request can be accepted or rejected
- reconnect sends the tracked `Last-Event-ID`

## Blockers Before Default Migration
## Current Follow-Up Direction

- Typed daemon event schema.
- Session-scoped permission route.
- Output sink refactor for JSONL / stream-json / dual-output parity.
- Session lifecycle close/delete semantics.
- Runtime diagnostics for MCP, skills, providers, and workspace env.
- Keep native TUI direct by default.
- Extract source adapters and a shared terminal render core that can be reused
by native TUI and web terminal.
- Prioritize web terminal as the daemon-native terminal surface.
- Treat this spike as future-migration reference, not an active default
migration checklist.
Loading