Repository navigation
feat(channels): add a Pi TUI client for the Web Channel - #2437
Conversation
🦋 Changeset detectedLatest commit: 1da3166 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
✅ agents import sizes: no significant changes ( |
5fa7763 to
a668a3c
Compare
a668a3c to
37df5b1
Compare
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
37df5b1 to
7b5674b
Compare
7b5674b to
719e05c
Compare
719e05c to
d95fb21
Compare
d95fb21 to
55fd5bd
Compare
| refresh(); | ||
| return; | ||
| } | ||
| client.follow(matches[0]); |
There was a problem hiding this comment.
🔴 Conversation switches lose the agent route
With /channels/ai-sdk/lobby, /switch reconnects WebChannelClient to /channels/ai-sdk/<id>, making the conversation ID the room. The gateway connects to a different agent; /new and /fork also lose their conversation on reconnect.
Learn more
The TUI uses a Web Channel client whose default follow URL rewrites /channels/<route>/<conversation> with only one route segment. The example gateway instead uses /channels/<harness>/<room>/<conversation>, so a room URL is misread as a conversation URL. Following new-id from /channels/ai-sdk/lobby connects to the room new-id instead of the room lobby; from an explicit conversation URL, the follow URL does not change at all. The same URL rewriting applies when the server moves the connection after a create or fork, so later reconnects go to the wrong conversation. See defaultFollowUrl and the gateway resolver.
Example: Start at /channels/ai-sdk/lobby, create conversation c2, then lose the WebSocket. Reconnection uses /channels/ai-sdk/c2, which reaches the c2 room's default session instead of the lobby room's c2 conversation.
Recommended fix: Supply a followUrl function to WebChannelClient that preserves the entire agent route and replaces or appends only the conversation segment. Ensure the initial URL with or without a conversation ID and URLs with multiple route segments both reconnect to the intended agent and conversation.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (!protocol) throw new UsageError(`Unsupported protocol ${url.protocol}`); | ||
| url.protocol = protocol; | ||
| return url; |
There was a problem hiding this comment.
🟡 Fragment URLs crash the terminal client
When the input URL contains #fragment, toSocketUrl passes it to WebChannelClient unchanged. WebSocket rejects fragment URLs, so the terminal client exits before connecting.
Learn more
parseArgs accepts both HTTP and WebSocket URLs and converts the HTTP schemes to WebSocket schemes. A URL fragment is legal in an HTTP URL but not in a WebSocket constructor URL. WebChannelClient passes the parsed URL straight to new WebSocket, which throws for fragments.
Example: agents tui 'https://example.com/channels/ai-sdk/lobby#chat' produces a wss: URL with #chat and fails before connecting instead of using the channel path.
Recommended fix: Reject nonempty url.hash with a UsageError, or remove the hash when converting HTTP URLs if fragments have no useful Web Channel meaning.
Was this helpful? React with 👍 or 👎 to provide feedback.
| `pnpm tui2 [harness] [room]` runs the Agents SDK terminal client built on Pi | ||
| TUI (`npx agents tui <url>`) against either agent, for example | ||
| `pnpm tui2 ai-sdk lobby`. It shows turns started from other surfaces, lets you | ||
| provide client-tool results, and can start, fork, list and switch |
There was a problem hiding this comment.
🔍 Example advertises an unregistered harness
The terminal instructions claim tui2 works with either harness, but the gateway resolver registers only ai-sdk. The example needs either the second harness or narrower instructions.
Was this helpful? React with 👍 or 👎 to provide feedback.
| local.runningSince.clear(); | ||
| local.notices = []; | ||
| prompted.clear(); | ||
| context.ui = { ...context.ui, selected: undefined }; |
There was a problem hiding this comment.
🔍 Block expansion state crosses conversations
Switching conversations clears selection but retains context.ui.toggled. Reused tool-call or message IDs inherit expansion choices from the previous conversation; consider clearing per-block toggles on follow.
Was this helpful? React with 👍 or 👎 to provide feedback.
55fd5bd to
e463b13
Compare
This PR adds `npx agents tui <url>`, a terminal client for any conversation's Web Channel, built on `@earendil-works/pi-tui`. ## Why - Developers need to talk to a Channels agent from a terminal without writing a client. The `@ai-sdk/tui` client in the example is tied to that example. - The client covers what the Web Channel offers: live transcript and turns from every surface, approvals, client tool results, cancellation, and moving between conversations. - Its dependencies are bundled into `dist/cli.js`, so installing `agents` adds none. ## Public API Surface Additive CLI: | Command or flag | Notes | | --- | --- | | `agents tui <url>` | Connects to a Web Channel URL | | `--header`, `-H` | Extra headers on the WebSocket upgrade | | `--as` | Sets the `as` query parameter, which demo agents read as the participant | | `CF_ACCESS_CLIENT_ID`, `CF_ACCESS_CLIENT_SECRET` | Sent as an Access service token | | `/new`, `/fork`, `/reset [note]` | Create, fork or reset a conversation, when the agent offers it | | `/conversations`, `/switch <id>` | List the agent's conversations and follow one; a unique id prefix is enough | ## Code Changes - `channels/web/tui/` holds argument parsing, the socket, the view model, and rendering components with Markdown highlighting and collapsible reasoning and tool blocks. - The header and footer show the route and the current conversation id. - `cli/index.ts` dispatches `tui`. `scripts/build.ts` bundles the CLI. - The Channels example gains a `tui2 [harness] [room]` script and a README entry. Patch changeset for `agents`. # Conflicts: # packages/agents/package.json # pnpm-lock.yaml # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # interactive rebase in progress; onto 74570a1 # Last commands done (19 commands done): # update-ref 62d6f8f # pick 55fd5bd # feat(channels): add a Pi TUI client for the Web Channel # Next commands to do (8 remaining commands): # update-ref 55fd5bd # pick 3d73aec # feat(examples): add the pi agent to the Channels example # You are currently rebasing branch 'channels/13-harness-bridge' on '74570a19a'. # # Changes to be committed: # new file: .changeset/channels-tui.md # modified: examples/next/channels/README.md # modified: examples/next/channels/package.json # modified: packages/agents/package.json # modified: packages/agents/scripts/build.ts # new file: packages/agents/src/cli/index.ts # new file: packages/agents/src/experimental/channels/__tests__/tui-args.test.ts # new file: packages/agents/src/experimental/channels/__tests__/tui-render.test.ts # new file: packages/agents/src/experimental/channels/__tests__/tui-view.test.ts # new file: packages/agents/src/experimental/channels/web/tui/app.ts # new file: packages/agents/src/experimental/channels/web/tui/args.ts # new file: packages/agents/src/experimental/channels/web/tui/components/blocks.ts # new file: packages/agents/src/experimental/channels/web/tui/components/footer.ts # new file: packages/agents/src/experimental/channels/web/tui/components/modal.ts # new file: packages/agents/src/experimental/channels/web/tui/highlight.ts # new file: packages/agents/src/experimental/channels/web/tui/main.ts # new file: packages/agents/src/experimental/channels/web/tui/socket.ts # new file: packages/agents/src/experimental/channels/web/tui/theme.ts # new file: packages/agents/src/experimental/channels/web/tui/view.ts # modified: pnpm-lock.yaml #
e463b13 to
1da3166
Compare
This PR adds
npx agents tui <url>, a terminal client for any conversation's Web Channel, built on@earendil-works/pi-tui.Why
@ai-sdk/tuiclient in the example is tied to that example.dist/cli.js, so installingagentsadds none.Public API Surface
Additive CLI:
agents tui <url>--header,-H--asasquery parameter, which demo agents read as the participantCF_ACCESS_CLIENT_ID,CF_ACCESS_CLIENT_SECRET/new,/fork,/reset [note]/conversations,/switch <id>Code Changes
channels/web/tui/holds argument parsing, the socket, the view model, and rendering components with Markdown highlighting and collapsible reasoning and tool blocks.cli/index.tsdispatchestui.scripts/build.tsbundles the CLI.tui2 [harness] [room]script and a README entry. Patch changeset foragents.