Skip to content

Commit 5532d6c

Browse files
author
秦奇
committed
feat(daemon): add shared UI transcript layer
1 parent 066cab2 commit 5532d6c

32 files changed

Lines changed: 3139 additions & 1994 deletions

docs/developers/daemon-client-adapters/tui.md

Lines changed: 0 additions & 96 deletions
This file was deleted.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Daemon Web UI Adapter
2+
3+
## Goal
4+
5+
Web chat and web terminal clients should consume `qwen serve` through the
6+
daemon HTTP/SSE APIs and render a client-side transcript. Native local TUI,
7+
channel, and IDE integrations keep their existing default paths for now.
8+
9+
## Shared UI Contract
10+
11+
Use the TypeScript SDK daemon UI exports as the common boundary:
12+
13+
```ts
14+
import {
15+
DaemonClient,
16+
DaemonSessionClient,
17+
createDaemonTranscriptStore,
18+
normalizeDaemonEvent,
19+
} from '@qwen-code/sdk/daemon';
20+
```
21+
22+
The split is:
23+
24+
- `DaemonClient` handles daemon HTTP routes.
25+
- `DaemonSessionClient` owns session creation/attachment and SSE replay.
26+
- `normalizeDaemonEvent()` converts daemon wire events into UI events.
27+
- `createDaemonTranscriptStore()` reduces UI events into transcript blocks.
28+
29+
React clients can use the optional `@qwen-code/webui` binding:
30+
31+
```tsx
32+
import {
33+
DaemonSessionProvider,
34+
useDaemonActions,
35+
useDaemonConnection,
36+
useDaemonPendingPermissions,
37+
useDaemonTranscriptBlocks,
38+
} from '@qwen-code/webui';
39+
```
40+
41+
Minimal React shape:
42+
43+
```tsx
44+
function App() {
45+
return (
46+
<DaemonSessionProvider baseUrl="http://127.0.0.1:4170">
47+
<Transcript />
48+
<PromptBox />
49+
</DaemonSessionProvider>
50+
);
51+
}
52+
53+
function Transcript() {
54+
const blocks = useDaemonTranscriptBlocks();
55+
return blocks.map((block) => <RenderBlock key={block.id} block={block} />);
56+
}
57+
```
58+
59+
The provider creates or attaches a daemon session, subscribes to SSE, keeps the
60+
last event id on `DaemonSessionClient`, and reconnects the stream by default.
61+
Callers can disable that with `autoReconnect={false}` for tests or custom
62+
connection management.
63+
64+
## Browser Deployment Shapes
65+
66+
### Same-Origin Local POC
67+
68+
A daemon-served page can call the daemon directly because the page and API share
69+
one origin. This is the preferred early POC shape for local web chat and web
70+
terminal validation.
71+
72+
### Remote Web Chat / Web Terminal
73+
74+
A production remote web app should normally talk to a backend-for-frontend. The
75+
BFF owns daemon URL, token, workspace routing, and session metadata, then
76+
forwards browser-safe app events to the browser. This keeps bearer tokens out of
77+
browser storage and lets the deployment decide which daemon/workspace a user is
78+
allowed to reach.
79+
80+
### Local Browser Against Local Daemon
81+
82+
A separate local dev server is cross-origin from `qwen serve`; it must either
83+
proxy daemon routes through the same origin or be served by the daemon. The
84+
daemon intentionally rejects arbitrary browser `Origin` requests.
85+
86+
## Rendering Responsibilities
87+
88+
The shared transcript model is semantic, not visual. UI clients decide how to
89+
render:
90+
91+
- user and assistant message blocks
92+
- collapsed thought blocks
93+
- tool status cards
94+
- shell output blocks
95+
- permission request controls
96+
- status/error/debug blocks
97+
98+
The web terminal is a browser-native semantic renderer. It should look and feel
99+
terminal-like with monospace layout, scrollback, prompt input, shortcuts, and
100+
streaming blocks, but it is not a raw PTY proxy and does not require server-side
101+
Ink rendering.
102+
103+
## Merge Safety
104+
105+
- The native `qwen` TUI remains direct and unchanged.
106+
- `--acp`, channel, and IDE paths remain unchanged by default.
107+
- The SDK UI core is additive.
108+
- The WebUI React binding is optional and only runs in clients that import it.
109+
- Removed daemon TUI spike code should not be treated as a product migration.
110+
111+
## Follow-Ups
112+
113+
- Add a daemon-served local `/web` POC or equivalent same-origin web app.
114+
- Build first-class chat and terminal renderers on top of transcript blocks.
115+
- Add richer typed events only where existing daemon events are too low-level
116+
for stable browser UI behavior.
117+
- Consider a dedicated `@qwen-code/daemon-ui-core` package if non-SDK consumers
118+
need the UI core as an independent dependency.

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)