You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend the existing `/embed/thread/:environmentId/:threadId` route to broadcast agent status events to its iframe parent via `window.parent.postMessage`. Enables the host (t3-canvas) to render per-tile status chips so users can triage agents at a glance.
Context
t3-canvas embeds T3 Code threads as canvas tiles. Phase 4.5 over there needs each tile to show a live status indicator (running / awaiting input / error / etc). The cleanest source of truth is T3 Code itself — we know turn state, approvals, errors. The cheapest channel is `window.parent.postMessage` since the iframe and host are same-origin localhost.
Acceptance criteria
EmbedThreadView (or wherever the route component lives) subscribes to the existing thread state in the store via the same hooks used by `_chat.$environmentId.$threadId.tsx`
On every relevant state transition, post a message to `window.parent` with shape:
```ts
window.parent.postMessage({
source: "t3-code-embed",
type: "agent-status",
threadId: string,
environmentId: string,
status: "idle" | "streaming" | "awaiting-input" | "error" | "completed" | "disconnected",
timestamp: number,
// optional payload — leave room for future fields without breaking consumers
payload?: { errorMessage?: string; turnId?: string }
}, "*");
```
Status mapping (start with these, refine if T3 Code's internal taxonomy differs):
turn started / first delta arrives → `streaming`
turn finished cleanly → `completed` (host will auto-fade to idle)
approval/user-input request received → `awaiting-input`
turn errored → `error` (include errorMessage in payload)
no active turn AND last turn was not just completed → `idle`
no thread or thread fetch failed → `disconnected`
Initial post on mount with current state
Cleanup on unmount: post a final `disconnected` so the parent knows the iframe went away
Wrap the postMessage in a `source: "t3-code-embed"` discriminator so the host can ignore unrelated postMessage chatter
Existing route behavior (rendering the conversation, no sidebar chrome) is unchanged
No new dependencies — read state from existing stores/hooks only
Files (verify against current repo state)
`apps/web/src/routes/embed.thread.$environmentId.$threadId.tsx` — add a useEffect that subscribes to thread state and emits postMessage on changes
`apps/web/src/components/EmbedThreadView.tsx` (or wherever the conversation component is) — possibly the better location depending on how state is wired
Read `apps/web/src/routes/_chat.$environmentId.$threadId.tsx` to see how the main route subscribes to thread state. Reuse the same hooks (`useStore`, `createThreadSelectorByRef`, `selectEnvironmentState`).
Branch
`feat/embed-status-postmessage` (separate from any other in-flight work).
Non-goals
Two-way postMessage (host → embed) — read only for now
Authenticated postMessage origin checks — same-origin localhost only
Wire status events for tools-use, model thinking deltas, etc. — keep the taxonomy minimal for v1
How to test
`bun run dev` in t3code
Build & run t3-canvas with the matching Phase 4.5 PR
Create a thread in T3 Code, copy env+thread IDs, open via t3-canvas's New Agent dialog
Send a turn → t3-canvas tile border should pulse blue (streaming) → settle green (completed) → fade gray (idle)
Trigger an approval-required tool → border turns amber
Goal
Extend the existing `/embed/thread/:environmentId/:threadId` route to broadcast agent status events to its iframe parent via `window.parent.postMessage`. Enables the host (t3-canvas) to render per-tile status chips so users can triage agents at a glance.
Context
t3-canvas embeds T3 Code threads as canvas tiles. Phase 4.5 over there needs each tile to show a live status indicator (running / awaiting input / error / etc). The cleanest source of truth is T3 Code itself — we know turn state, approvals, errors. The cheapest channel is `window.parent.postMessage` since the iframe and host are same-origin localhost.
Acceptance criteria
```ts
window.parent.postMessage({
source: "t3-code-embed",
type: "agent-status",
threadId: string,
environmentId: string,
status: "idle" | "streaming" | "awaiting-input" | "error" | "completed" | "disconnected",
timestamp: number,
// optional payload — leave room for future fields without breaking consumers
payload?: { errorMessage?: string; turnId?: string }
}, "*");
```
Files (verify against current repo state)
Read `apps/web/src/routes/_chat.$environmentId.$threadId.tsx` to see how the main route subscribes to thread state. Reuse the same hooks (`useStore`, `createThreadSelectorByRef`, `selectEnvironmentState`).
Branch
`feat/embed-status-postmessage` (separate from any other in-flight work).
Non-goals
How to test