chore: promote expbkmain to bkmain (agent views in chat) - #143
Merged
Conversation
Agents could describe a chart, a diagram or a table, but never show one. Everything they produced arrived as text or as a collapsed tool row, so anything visual had to be rebuilt in the user's head — or opened somewhere outside the conversation. This adds the piece MCP Apps hosts like Claude Desktop have: a sandboxed box rendered inline in the transcript, where the tool call happened. An agent calls the new `t3_show_ui` MCP tool with a self-contained HTML document (or an https URL) and the chat mounts it in an iframe with an opaque origin — its scripts run, so charts and interactions work, but it cannot reach T3 Code, its cookies, or the network as the signed-in user. The document never travels on an activity payload. The tool stores it and returns a short render handle; the projection layer carves that handle out before it summarizes the result away, and the chat fetches the body on demand through a new thread-scoped fork RPC. That keeps oversized documents off the websocket and clear of the 32 KiB activity string cap, and it works on every provider — including Claude Code, whose CLI flattens MCP results to text. Renders are immutable: calling the tool again shows a new box rather than mutating an old one, so a row keeps showing what the agent actually produced at that point in the thread. Fork surface is deliberately small: the feature lives in new fork-owned modules (`apps/server/src/agentui/`, `apps/web/src/fork/agentUiSurface.tsx`), and the timeline seam is one import plus an early return that wraps the unchanged upstream row. Gated by an Experiments setting, on by default. Written by Claude Opus 5 in T3 Code.
…vider sends Providers disagree about where an MCP tool result lands: the text content array, `structuredContent`, or the bare result object. Claude Code has shipped the second in place of the first, and a miss here fails silently — the view just turns back into an ordinary tool row — so read all three. Written by Claude Opus 5 in T3 Code.
Adds the user-facing page for the feature and registers it in the docs index and the expbkt3 customization boundary registry. Written by Claude Opus 5 in T3 Code.
Written by Claude Opus 5 in T3 Code.
feat(chat): agents can render interactive views inline in the chat
…ixture `ClientSettings` is exhaustive, so adding `agentUiSurfacesEnabled` broke the desktop persistence test that builds a whole settings object by hand. Written by Claude Opus 5 in T3 Code.
The repo's Effect lint rules reject `crypto.randomUUID()` inside Effect code — it bypasses Effect-injected randomness. Use the same `Crypto.randomUUIDv4` pattern PlanReviewService uses, where a failing CSPRNG is a defect rather than a recoverable error. Written by Claude Opus 5 in T3 Code.
Written by Claude Opus 5 in T3 Code.
The catalog derives one virtual MCP tool per websocket RPC, and two tests pin the total. Adding `agentUi.getRender` moves it from 137 to 138; `matchedCount` moves with it, so the new RPC generates a complete schema like the rest. Written by Claude Opus 5 in T3 Code.
Embedding a URL without `allow-same-origin` gives the document an opaque origin, so localStorage, IndexedDB and cookies all throw. Every real app fails to boot that way — a self-hosted Excalidraw canvas among them — which made the `url` half of agent views useless in practice. Grant it, except when the framed URL is same-origin with the page itself. `allow-scripts` plus `allow-same-origin` is a sandbox escape only in that case, where the frame could reach our DOM and the signed-in session directly; a self-referential embed stays opaque and harmless instead. Written by Claude Opus 5 in T3 Code.
fix(desktop): add the new client setting to the settings round-trip fixture
A chart or table worth showing is usually worth showing bigger, and the inline box is capped at 900px by design. Clicking a view's title now expands it to fill the message area, leaving the composer where it is so the conversation can continue without collapsing the view first. The overlay mounts beside the message list rather than inside the row that opened it: timeline rows are virtualized, so they clip and get recycled out from under anything absolutely positioned. The messages wrapper is already `relative` and already excludes the input bar, so `absolute inset-0` there covers exactly the transcript. Escape closes it, on the capture phase — the composer and timeline both handle Escape, and the frontmost surface should answer first. Written by Claude Opus 5 in T3 Code.
feat(web): expand an agent view over the transcript
An agent view arrived as an ordinary tool row, so the work log treated it like one: once the turn settled it folded away with the rest of the tool calls, and in a long run it collapsed behind a "+N tool calls" toggle. The box the agent drew for the user was there, but nobody saw it without hunting for it. Agent-spawn rows already had this exemption, for the same reason — a running fleet must not hide behind a toggle. Generalise that one predicate to cover agent views too. A view is the answer the agent produced, not a record that work happened; folded away it may as well not have been drawn. Written by Claude Opus 5 in T3 Code.
fix(web): keep an agent view visible instead of folding it away
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Promotes the current
expbkmainline tobkmain. 15 commits, all already verified running at expbkt3.dev.beknown.live on3f8aeeab5.Highlights:
Cryptoservice, desktop settings round-trip fixture, and the web UI parity catalog covering the new fork RPC.Verification
expbkmainis a clean fast-forward ofbkmain(0 commits behind). Every commit shipped through expbkt3 first;Validate and deploy experimental T3is green on the tip and/home/ubuntu/.t3/expbkt3-dev/deployed-shamatches3f8aeeab5.Merging this restarts
t3-bkmain.serviceand interrupts in-flight turns on bkt3.Model: Claude Opus 5, harness: Claude Code in T3 Code.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.