Summary
The shared sandbox-terminal transport is already in place. agent-app owns the same-origin connection, runtime-proxy, WebSocket-upgrade, terminal-token, connection-hook, per-tab connection-id, and terminal-panel mechanisms. Creative Agent and GTM Agent both use the shared transport.
The remaining work is narrower:
- retire the duplicated per-tab connection-id helpers in both apps; and
- settle whether the full terminal panel is shared shell UI or product-owned chrome.
This is a standalone sandbox-terminal cleanup. It is not part of the chat/vault vertical.
Current state
Complete
Still duplicated
Creative Agent and GTM Agent each still define their own:
tabTerminalConnectionId
- lazy
TerminalView wiring
WorkspaceTerminalPanel UI
The local connection-id helpers also have a weaker fallback: if sessionStorage is unavailable, they derive a deterministic ID from the sandbox ID. Separate clients can therefore still collide in that edge case. The shared helper returns a unique ephemeral ID instead.
Remaining work
1. Adopt the shared connection-id helper
2. Decide and implement the terminal-panel ownership boundary
The current shared WorkspaceTerminalPanel is not a behavior-preserving drop-in for either app:
- Creative Agent has product-specific icon, badge, button, connected-state actions, empty-state copy, and full-bleed container treatment.
- GTM Agent additionally uses its product-owned
WorkspacePageHeader.
- The shared panel has a fixed internal header and empty state.
headerExtra can append content, but cannot replace those regions.
Choose one direction:
A. Shared shell panel
Make the shared terminal surface adoptable without forcing product UI changes. Prefer a narrow mechanism boundary or additive render/slot seams for product-owned header, empty state, actions, and container chrome. Then migrate both apps and delete their duplicated terminal mechanics.
B. Product-owned panel chrome
Keep each app's header, empty state, and surrounding layout local. Document the boundary explicitly: agent-app owns terminal connection/session mechanism, while products own panel presentation. In this direction, do not require consumers to adopt the full shared panel merely for deduplication.
Whichever direction is chosen:
Non-goals
- A combined
createWorkspaceSandboxTerminal(deps) factory. The three existing handlers already share the important mechanism, while the apps have different provisioning/credential seams and GTM has additional WebSocket-subprotocol response handling.
- Changes to sandbox provisioning,
SandboxRuntimeConfig, auth trusted origins, tool installation, or product-specific layout mounting.
- Changes to terminal transport or token architecture; those migrations are complete.
References
Summary
The shared sandbox-terminal transport is already in place.
agent-appowns the same-origin connection, runtime-proxy, WebSocket-upgrade, terminal-token, connection-hook, per-tab connection-id, and terminal-panel mechanisms. Creative Agent and GTM Agent both use the shared transport.The remaining work is narrower:
This is a standalone sandbox-terminal cleanup. It is not part of the chat/vault vertical.
Current state
Complete
tabTerminalConnectionIdis exported from@tangle-network/agent-app/web-react.WorkspaceTerminalPanelis exported from the sandbox-specific@tangle-network/agent-app/web-react/terminalentrypoint.useSandboxTerminalConnection.connectionId, so the original normal-browser multi-tab eviction bug is fixed.Still duplicated
Creative Agent and GTM Agent each still define their own:
tabTerminalConnectionIdTerminalViewwiringWorkspaceTerminalPanelUIThe local connection-id helpers also have a weaker fallback: if
sessionStorageis unavailable, they derive a deterministic ID from the sandbox ID. Separate clients can therefore still collide in that edge case. The shared helper returns a unique ephemeral ID instead.Remaining work
1. Adopt the shared connection-id helper
Creative Agent imports
tabTerminalConnectionIdinstead of defining it locally.GTM Agent imports
tabTerminalConnectionIdinstead of defining it locally.Both apps preserve per-sandbox reload behavior by supplying a sandbox-specific storage key, for example:
Existing same-tab reload persistence and cross-tab/client isolation remain covered.
2. Decide and implement the terminal-panel ownership boundary
The current shared
WorkspaceTerminalPanelis not a behavior-preserving drop-in for either app:WorkspacePageHeader.headerExtracan append content, but cannot replace those regions.Choose one direction:
A. Shared shell panel
Make the shared terminal surface adoptable without forcing product UI changes. Prefer a narrow mechanism boundary or additive render/slot seams for product-owned header, empty state, actions, and container chrome. Then migrate both apps and delete their duplicated terminal mechanics.
B. Product-owned panel chrome
Keep each app's header, empty state, and surrounding layout local. Document the boundary explicitly: agent-app owns terminal connection/session mechanism, while products own panel presentation. In this direction, do not require consumers to adopt the full shared panel merely for deduplication.
Whichever direction is chosen:
WorkspacePageHeaderand its current terminal behavior.Non-goals
createWorkspaceSandboxTerminal(deps)factory. The three existing handlers already share the important mechanism, while the apps have different provisioning/credential seams and GTM has additional WebSocket-subprotocol response handling.SandboxRuntimeConfig, auth trusted origins, tool installation, or product-specific layout mounting.References