Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
612 lines
30 KiB
Markdown
612 lines
30 KiB
Markdown
# @tutti-os/agent-gui
|
|
|
|
AgentGUI renders workspace agent sessions, timelines, approvals, and composer
|
|
UI. It is a UI package, not a host transport or business-core package.
|
|
|
|
## Product Error Presentation
|
|
|
|
AgentGUI does not own Account or Commerce UI. Product hosts render those
|
|
surfaces through `@tutti-os/commerce` and its `./react` entrypoint.
|
|
|
|
Hosts may pass `hostCapabilities.visibleErrorPresentationOverrides` to
|
|
customize structured product errors such as `insufficient_credits`. The
|
|
override contains only localized copy and an optional sanitized external
|
|
action; it does not expose membership state, credentials, or Commerce response
|
|
objects to AgentGUI. Raw provider error details remain available to diagnostics
|
|
and are rendered only behind an explicit disclosure, never in the product error
|
|
headline. Environment, authentication,
|
|
network, and runtime errors are not overridable and remain AgentGUI policy.
|
|
|
|
Hosts that render an Agent owned by somebody else must pass
|
|
`hostCapabilities.visibleErrorPresentationScope: "shared_caller"`. AgentGUI
|
|
then preserves structured failure reasons and diagnostic disclosure, replaces
|
|
Owner-remediable guidance with caller-safe contact guidance, and suppresses
|
|
current-device and current-account recovery actions. Omission defaults to
|
|
`"local_owner"` for backward compatibility. The scope is presentation-only;
|
|
it never changes a Turn, activity event, persistence, or provider error.
|
|
Hosts that inject an application i18n runtime must also provide
|
|
`agentHost.agentGui.visibleErrorSharedCallerHint` in every supported locale.
|
|
|
|
This is an intentional public API break. The former `accountMenuState`,
|
|
`commercePresentation`, `AgentGUIAccountMenu*`, and
|
|
`AgentGUIAccountRewardToast` surfaces were removed instead of being retained as
|
|
silent no-ops. Hosts must render account chrome through
|
|
`@tutti-os/commerce/react` and translate Commerce policy into
|
|
`visibleErrorPresentationOverrides`.
|
|
|
|
Before changing AgentGUI, AgentGuiNode, or the agent conversation module, read
|
|
[AgentGuiNode Architecture and Troubleshooting](../../../docs/architecture/agent-gui-node.md).
|
|
It defines daemon, workspace-engine, GUI-module, provider, and desktop-host
|
|
ownership.
|
|
|
|
## Data Source
|
|
|
|
The injected workspace `AgentSessionEngine`, reached through
|
|
`AgentGUIRuntime`, is AgentGUI's only source for canonical agent activity
|
|
data.
|
|
|
|
Runtime-owned data includes:
|
|
|
|
- canonical sessions, turns, interactions, and operation state
|
|
- prompt queue and correlated optimistic intents
|
|
- stable selector projections
|
|
- semantic session, turn, prompt, interaction, settings, and goal commands
|
|
|
|
Runtime-owned capability declarations are optional and default to enabled:
|
|
|
|
- `canCancel`: shows and enables Stop/cancel controls.
|
|
- `canSubmitInteractive`: shows approval, ask-user, and plan-decision
|
|
interaction entries.
|
|
- `canGoalControl`: shows goal banner controls, `/goal`, and the goal badge.
|
|
- `canUploadAttachment`: enables prompt attachment paths. Pasted large text
|
|
additionally requires the explicit `AgentGUIRuntime.stagePastedText`
|
|
host method; AgentGUI does not infer that capability from generic file
|
|
upload support. Ordinary `@` references and workspace-reference mentions
|
|
remain available.
|
|
|
|
## Pasted Text Staging
|
|
|
|
AgentGUI classifies plain-text clipboard content before delegating structured
|
|
mention HTML. A trimmed payload of at least 5,000 characters is never inserted
|
|
into the prompt automatically. It becomes a pasted-text draft attachment and
|
|
is passed as raw text to `AgentGUIRuntime.stagePastedText`; the host owns
|
|
persistence and returns either a local `{ path, name, sizeBytes }` locator or
|
|
a remote `{ url, name, sizeBytes, assetId?, uri?, uploadStatus? }` prepared
|
|
attachment. Local text is sent as a read-file instruction; a remote locator is
|
|
sent as an ordinary prepared file, so shared hosts reuse their attachment path.
|
|
Its conversation display mention contains only the pasted-text preview, never
|
|
the remote URL or storage locator.
|
|
|
|
If the method is absent or staging fails, the attachment remains in an explicit
|
|
failed state and retains its in-memory text. AgentGUI must not silently put the
|
|
payload back into the input. The user can explicitly choose “Show in text
|
|
field” to do that. Generic `uploadPromptContent` remains the image-upload
|
|
contract; it is not a pasted-text or external-file capability signal.
|
|
|
|
## External File Preparation
|
|
|
|
OS clipboard and drop entries first use the optional synchronous workspace
|
|
`resolveExternalPromptEntries` host port. The host classifies every input as a
|
|
live `WorkspaceFileReference` or a snapshot that needs preparation. AgentGUI
|
|
inserts references directly as ordinary file/folder mentions, preserves mixed
|
|
input order, and sends only `prepare` entries to `prepareExternalPromptFiles`.
|
|
Without the resolver, every input uses preparation.
|
|
|
|
Both ports return one result per input `sourceIndex`. The resolver is
|
|
synchronous so paste/drop insertion position remains stable. Prepared files
|
|
require a provider-readable `path` or `url`; failures require a typed
|
|
`errorCode`. Hosts must isolate per-file failures and reject oversized inputs
|
|
before reading or persisting their bytes. A host that resolves path-backed
|
|
entries as references must also reject any such entry that unexpectedly reaches
|
|
preparation, preventing a resolver failure from creating a duplicate snapshot.
|
|
|
|
Slash commands come from the runtime session command snapshot. AgentGUI keeps
|
|
legacy provider-default slash entries unless the host passes
|
|
`slashCommandFallbackMode="none"`, which makes the slash palette show only
|
|
runtime-advertised commands. The mode only controls whether AgentGUI synthesizes
|
|
provider fallback entries; owner-advertised built-in command names still keep
|
|
AgentGUI's local interaction semantics for a consistent composer experience.
|
|
|
|
If `reportDiagnostic` is omitted, non-production development builds emit AgentGUI
|
|
diagnostics to `console` by default for message page requests/resolutions,
|
|
render-state changes, and caught errors. Set
|
|
`devDiagnosticConsoleSink: false` on the runtime to disable that development
|
|
fallback. Production builds stay silent unless the host provides
|
|
`reportDiagnostic`.
|
|
|
|
Host capabilities remain separate from activity data. `AgentHostApi` is still
|
|
accepted for host capabilities that are not agent activity data:
|
|
|
|
- workspace files and file references
|
|
- clipboard
|
|
- account/user lookup
|
|
- user-project selection
|
|
- local file picking/reading and batch export helpers
|
|
|
|
## Worktree Session Launch
|
|
|
|
New-Session worktree launch is an opt-in host contract. A host enables it with
|
|
`hostCapabilities.sessionWorktreeEnabled`, supplies the current workspace's
|
|
durable `sessionLaunchModesByProjectSectionKey` projection, handles
|
|
`hostActions.onSessionLaunchModePreferenceChange`, and implements
|
|
`AgentHostApi.workspace.resolveSessionWorktreeSupport`. Omitting any part fails
|
|
closed and preserves the existing local-checkout launch behavior, so published
|
|
AgentGUI consumers do not acquire the feature until they opt in.
|
|
|
|
AgentGUI exposes the selector only for a new Session whose exact selected Agent
|
|
Target is self-owned and whose selected registered project passes the host
|
|
probe. Shared or remote targets, existing Sessions, missing projects, and
|
|
unsupported repositories show no selector. The stored preference is not
|
|
rewritten when current support disappears: the effective launch falls back to
|
|
`local`, and the saved `worktree` choice becomes effective again if the same
|
|
workspace and project section later regain support. Opening an existing
|
|
Session never changes the launch preference.
|
|
|
|
The preference is launch intent, keyed by workspace id and canonical project
|
|
`sectionKey`; it is separate from a Session's durable `isolation` fact. A
|
|
worktree launch sends `isolation: "worktree"` through the semantic activation
|
|
path. Rail summaries may render the package worktree glyph from the resulting
|
|
canonical Session isolation metadata, next to relative time in the unhovered
|
|
row; they must not infer isolation from `cwd`.
|
|
|
|
AgentGUI has no host-API activity fallback. A host must inject the runtime and
|
|
the grouped `AgentGUINodeProps` responsibility objects.
|
|
|
|
## Side Presentation
|
|
|
|
Side remains a surface-owned, transient conversation. By default AgentGUI
|
|
renders it through the inline `AgentGUISideConversationPane`. A host that owns
|
|
an external panel system may create an
|
|
`AgentGUISideConversationPresentation`, pass it through
|
|
`hostCapabilities.sideConversationPresentation`, and render the published
|
|
`AgentGUISideConversationSurface` itself.
|
|
|
|
The presentation store carries only the exact source/Side identities, surface
|
|
props, and close intent. It does not own provider commands, runtime state, or
|
|
persistence. External hosts must key tabs by the exact identities, propagate
|
|
panel visibility through `isVisible` so focus is released while hidden, and
|
|
invoke `close` only for the currently matching projection. Omitting the bridge
|
|
preserves the inline behavior for existing hosts.
|
|
|
|
## Headless Conversation Message Controller
|
|
|
|
`@tutti-os/agent-gui/conversation-message-controller` is the renderer-neutral
|
|
query controller for one focused conversation. Desktop AgentGUI and Native
|
|
Mobile both use it for initial detail hydration, latest-message reconciliation,
|
|
and explicit older-page loading.
|
|
|
|
Initial and latest reads enter the workspace Engine as semantic Session
|
|
reconcile commands. Older-page reads use only the Engine's authoritative
|
|
message-window cursor, share one in-flight/retry/stale-request state machine,
|
|
and apply the mapped durable page back to that same Engine. A high mutable
|
|
message version without an authoritative window is never treated as evidence
|
|
of older history.
|
|
|
|
Hosts supply the mapped message transport and retain lifecycle concerns such as
|
|
Mobile foreground/background behavior, disconnected polling, DOM or Native
|
|
scrolling, and diagnostics enrichment. The controller does not own navigation,
|
|
rendering, localization, or transport authorization. Desktop selection owns
|
|
activation guards and Rail projection coordination, then requests initial or
|
|
forced message hydration through this controller; it must not add a parallel
|
|
messages-only Engine reconcile path.
|
|
|
|
## Reference Picker Error Recovery
|
|
|
|
Hosts may provide `workspace.resolveReferenceContentErrorAction` to map a
|
|
reference-source content error to a labeled recovery action. AgentGUI passes
|
|
the resolver to the shared `ReferenceSourcePicker`; the picker renders the
|
|
action in its centered error state and retries the failed browse or search when
|
|
the user activates it. Hosts should return an action only for errors they can
|
|
recover interactively, such as requesting filesystem authorization again.
|
|
|
|
## DOM-Free Conversation Projection
|
|
|
|
`@tutti-os/agent-gui/conversation-projection` is the renderer-neutral entry
|
|
for hosts that need the same canonical transcript semantics without importing
|
|
the DOM conversation components. Its focused Session projection accepts the
|
|
canonical activity snapshot, the selected Session id, and known Turns. It
|
|
derives the exact Session and message snapshots from that one activity snapshot
|
|
and hides AgentGUI's intermediate activity-card and timeline-item construction.
|
|
The host owns rendering, local disclosure, scrolling, i18n, and semantic
|
|
commands for pending Interactions.
|
|
|
|
The entry also exports `resolveAgentConversationNavigationAction`, whose
|
|
portable action union contains only external URLs and Agent Session mentions.
|
|
Workspace files, local assets, apps, issues, and custom mentions stay in
|
|
host-specific capability adapters. The broad Workspace resolver and this
|
|
portable resolver share only the host-neutral URL and Agent Session parsing
|
|
primitives. Alternate renderers must not parse `mention://` values or invent
|
|
fallback file paths locally.
|
|
|
|
Pending Engine Interactions are projected through
|
|
`projectAgentConversationPromptFromInteraction`. The resulting canonical prompt
|
|
preserves runtime approval and plan option ids; hosts render it and submit those
|
|
exact ids rather than guessing generic allow/deny actions. Missing presentation
|
|
copy remains empty so each renderer can supply localized fallback text.
|
|
|
|
Do not recreate this transformation from raw message kinds in another host.
|
|
The public projection is where AgentGUI canonicalizes message snapshots and
|
|
groups assistant messages, thinking, tool activity, processing, notices, and
|
|
turn summaries.
|
|
|
|
## DOM-Free Composer Projection
|
|
|
|
`@tutti-os/agent-gui/composer-projection` exposes the shared pure Composer
|
|
support decision and presented-settings projection. The workspace engine
|
|
continues to own target-keyed Composer option loads and semantic settings
|
|
commands. Alternate renderers receive canonical activity-core options and
|
|
session settings, then retain only their menu, sheet, and disclosure UI.
|
|
|
|
The daemon DTO mapper belongs to
|
|
`@tutti-os/agent-activity-tuttid-adapter`, so Desktop and Mobile do not keep
|
|
separate parser implementations for Composer capabilities or option catalogs.
|
|
|
|
## Performance Failure Events
|
|
|
|
`AgentGUIPerformanceEvent` failure settlements carry a bounded `errorCode` and
|
|
`failureStage` when the operation fails. `errorCode` comes from a stable
|
|
machine-readable error field and falls back to `unknown`; raw error messages
|
|
are never included. Composer option failures use `options_load`, Session
|
|
activation uses `session_activation`, Prompt admission uses `prompt_admission`,
|
|
and Turn failures use `turn_settlement`. Each settlement keeps its existing
|
|
`operationId`, so hosts can deduplicate repeated observations without using
|
|
provider names, timestamps, or error text.
|
|
|
|
## Quick Composer
|
|
|
|
`@tutti-os/agent-gui/quick-composer` renders the canonical DOM Composer for a
|
|
launcher that needs text, image drafts, and exact Agent Target selection without
|
|
the Rail or timeline. It is controlled by typed prompt content and returns the
|
|
same prompt envelope on submit. It intentionally owns no Session lifecycle or
|
|
Composer-options loading; the host must route submit through its existing
|
|
workspace `AgentSessionEngine`. Its embedded layout keeps attachments and long
|
|
drafts in normal flow; hosts must not wrap the timeline-oriented dock layout in
|
|
fixed-height launch surfaces.
|
|
|
|
Agent selection is fail-closed. The host passes the canonical `agentTargetId`
|
|
and a capability snapshot for every selectable target. Quick Composer resolves
|
|
only that exact identifier: an unknown, disabled, or capability-less target
|
|
keeps submit unavailable instead of falling back to the first target or
|
|
guessing a provider. Image drafts are accepted only when the selected target's
|
|
declared content types include images. The submit envelope returns the resolved
|
|
`agentTargetId`, content, and display prompt so the host cannot activate a
|
|
different target from the one the user saw.
|
|
The public target contract does not accept AgentGUI's legacy `targetId` or
|
|
internal `ref`; Quick Composer derives both internal fields from the canonical
|
|
`agentTargetId` before rendering the shared selector.
|
|
|
|
Hosts that need canonical `@` results pass a `RichTextMentionService`; hosts
|
|
that enable the `+` control pass `onRequestWorkspaceReferences`. Quick Composer
|
|
installs both through the same AgentGUI Composer boundaries used by the full
|
|
surface and never owns a second reference source. Fixed or frameless launchers
|
|
should pass `menuViewportTopInset` for title-bar chrome that portaled provider
|
|
and mention menus must avoid. A host with a definite height may set
|
|
`fillAvailableHeight`; a host that needs every bottom control on one baseline
|
|
may set `composerActionPlacement="footer"`. Both are optional presentation
|
|
contracts and do not change prompt or Session ownership. A host whose own
|
|
window chrome already defines the visual perimeter may set
|
|
`inputSurfaceVariant="borderless"` to suppress the redundant inner outline
|
|
without overriding AgentGUI implementation selectors.
|
|
|
|
Standalone hosts may inject an AgentGUI i18n runtime. Otherwise Quick Composer
|
|
uses the package defaults; hosts must not render translation keys or hardcode a
|
|
second copy of Composer-visible text.
|
|
|
|
A launcher that owns project selection passes a real `WorkspaceUserProjectApi`
|
|
as `userProjectApi`, together with `selectedProjectPath` and
|
|
`onProjectPathChange`. Quick Composer then renders the canonical project
|
|
selector in its footer and delegates catalog reads, selection preparation, and
|
|
project registration to that API. A directory picker alone does not enable the
|
|
selector and never becomes a synthetic registered-project catalog. The host
|
|
remains responsible for carrying the selected path through its normal
|
|
new-Session activation input.
|
|
|
|
## Standalone Conversation Participant Presentation
|
|
|
|
The `@tutti-os/agent-gui/agent-conversation` entrypoint exposes one optional,
|
|
host-owned participant presentation contract on `WorkspaceAgentSessionDetail`,
|
|
`AgentConversationFlow`, and `AgentTranscriptView`:
|
|
|
|
```tsx
|
|
<WorkspaceAgentSessionDetail
|
|
participantPresentation={{
|
|
enabled: true,
|
|
status: "ready",
|
|
user: { name: "Alice", avatarUrl: userAvatarUrl },
|
|
agent: { name: "Codex", avatarUrl: agentAvatarUrl }
|
|
}}
|
|
{...props}
|
|
/>
|
|
```
|
|
|
|
Omitting the property or passing `{ enabled: false }` preserves the existing
|
|
transcript DOM and spacing. Pass `{ enabled: true, status: "loading" }` while
|
|
the host is resolving identities; existing messages stay visible and the
|
|
package renders fixed-size circular loading slots. In the `ready` state, each
|
|
participant requires a non-empty `name`; `avatarUrl` is optional and the shared
|
|
UI System `Avatar` falls back to the name's initial.
|
|
|
|
Participant headers are turn-scoped. Agent GUI renders at most one header for
|
|
each speaker in a presentation turn, even when thinking, tool progress, or
|
|
turn-work disclosure splits that turn into multiple message rows. A completed
|
|
collapsed turn anchors the Agent header to visible reply content instead of the
|
|
hidden work section.
|
|
|
|
The host owns identity lookup and lifecycle. Agent GUI owns placement, sizing,
|
|
loading treatment, image fallback, and left/right message alignment. The
|
|
contract is presentation-only and must not be copied into canonical Session,
|
|
Turn, Message, or workspace-engine state.
|
|
|
|
## Session Handoff Drafts
|
|
|
|
External AgentGUI hosts can use `createAgentSessionHandoffPrompt` to prefill a
|
|
destination Agent composer with the same canonical complete-session mention as
|
|
AgentGUI's built-in Handoff menu. The helper owns mention serialization and the
|
|
trailing rich-text caret space; hosts continue to own destination selection and
|
|
window launch behavior.
|
|
|
|
Hosts that copy a session reference without launching a handoff must use
|
|
`createAgentSessionMarkdownLink`. This is the same canonical serializer used by
|
|
AgentGUI's Copy as reference action. Pass `withAtPrefix: true` when the copied
|
|
value should paste back into Agent and room-chat composers as an `@` session
|
|
mention; unlike the handoff helper, it does not append a trailing caret space.
|
|
|
|
## Boundary Rule
|
|
|
|
`AgentActivity*` types from `@tutti-os/agent-activity-core` are the canonical
|
|
frontend agent activity model. Production reads use exported engine selectors;
|
|
production writes use engine commands. GUI modules must not read entity maps,
|
|
subscribe to daemon streams, or reconstruct session/turn lifecycle from
|
|
messages.
|
|
|
|
Runtime identity is explicit: each consumer resolves the injected engine and
|
|
verifies its `(workspaceId, origin)` identity. Module-global runtime slots and
|
|
hidden origin registries are forbidden.
|
|
|
|
The `@tutti-os/agent-gui/conversation-rail-runtime` subpath exposes the
|
|
host-neutral Rail query/mutation cohort through
|
|
`createAgentConversationRailRuntime` and its runtime/source types. Method-name
|
|
manifests and UI capability inspection remain package-internal; hosts use the
|
|
typed factory instead of importing test helpers. The sibling
|
|
`@tutti-os/agent-gui/conversation-rail-controller` subpath exposes the canonical
|
|
`createAgentGUIConversationRailQueryController` factory and controller
|
|
interface used by Desktop and Native Mobile. The headless implementation owns
|
|
Rail query scope, first-page and cursor pagination, cache and stale-request
|
|
handling, membership refresh, and canonical Engine ingestion. Hosts supply
|
|
transport and Session mapping, then retain only host lifecycle, availability,
|
|
polling, diagnostic context, and presentation policy. Do not instantiate the
|
|
internal controller, create a host-local second Rail state machine, or export
|
|
its internal query helpers as public API.
|
|
Its public snapshot is presentation-free; Desktop derives localized
|
|
conversation summaries from that snapshot plus Engine state in its adapter.
|
|
The factory owns resolved-query cache reuse per workspace Engine; cache access
|
|
is not a runtime or host capability and has no published package entrypoint.
|
|
In-flight first-page results are fenced to the attached controller generation
|
|
so stale mounts cannot mutate the Engine or cache.
|
|
|
|
The `@tutti-os/agent-gui/abortable-single-flight` subpath exposes the generic
|
|
`AbortableSingleFlight` lifecycle primitive for host adapters that need to
|
|
coalesce keyed abortable reads while keeping caller cancellation independent.
|
|
The primitive owns only request sharing and cancellation; cache, snapshot, and
|
|
event ownership remain with the host adapter.
|
|
|
|
Run this boundary check after changing AgentGUI data flow:
|
|
|
|
```sh
|
|
pnpm check:agent-activity-runtime-boundaries
|
|
```
|
|
|
|
## Node Contract
|
|
|
|
`AgentGUINodeProps` has eight required top-level responsibilities:
|
|
`identity`, `workspace`, `frame`, `state`, `runtimeRequests`,
|
|
`hostCapabilities`, `hostActions`, and `renderSlots`. Extend the owning object;
|
|
do not restore flat compatibility props.
|
|
|
|
Hosts may provide `renderSlots.agentTargetInfo` to enrich the exact Agent icon
|
|
in the provider Rail and Conversation Rail. The renderer receives
|
|
`{ target, surface }` and returns one React element, or `null` to retain the
|
|
built-in target-label fallback. AgentGUI owns Tooltip mechanics and calls the
|
|
renderer only while the content is mounted. Pass the same renderer plus an exact
|
|
`conversationAgentTarget` to `AgentGuiWorkbenchHeader` for the Header icon.
|
|
Conversation history resolves the current Host directory by canonical
|
|
`agentTargetId`; missing targets show no enriched Tooltip and target metadata
|
|
is never copied into Session state.
|
|
|
|
Workbench hosts capture Dock and minimize previews from the mounted AgentGUI
|
|
node. AgentGUI does not expose a second-tree preview renderer or preview-mode
|
|
contract.
|
|
|
|
## Reference Provenance Filtering
|
|
|
|
Reference provenance filtering is disabled by default. Collaboration hosts can
|
|
opt in by injecting the complete catalog through
|
|
`hostCapabilities.referenceProvenanceFilterCatalog`:
|
|
|
|
```tsx
|
|
<AgentGUI
|
|
{...props}
|
|
hostCapabilities={{
|
|
referenceProvenanceFilterCatalog: {
|
|
enabledDimensions: ["agent", "member"],
|
|
agentOptions: [{ id: "agent-1", label: "Agent 1" }],
|
|
memberOptions: [{ id: "member-1", label: "Member 1" }]
|
|
}
|
|
}}
|
|
/>
|
|
```
|
|
|
|
The catalog is host-owned: option IDs must be durable identities understood by
|
|
the host's injected reference/search providers. Active dimensions are passed
|
|
to those providers as query metadata and must be enforced before pagination.
|
|
Sources that cannot enforce an active dimension must fail closed instead of
|
|
returning unfiltered results.
|
|
|
|
`referenceProvenanceFilterEnabled` remains as the legacy Tutti personal-edition
|
|
switch. When enabled without an explicit catalog, AgentGUI derives only the
|
|
Agent options from the Agent directory and keeps `memberOptions` empty. Omitting
|
|
both properties keeps the filter off. An explicitly supplied catalog (including
|
|
`null`) takes precedence over the legacy switch.
|
|
|
|
## Home Suggestions
|
|
|
|
The six starter entries below the empty new-session composer are enabled by
|
|
default. External hosts can hide individual entries with the public
|
|
`AgentGUI.disabled` array:
|
|
|
|
```tsx
|
|
<AgentGUI disabled={["meet-tutti", "import-session"]} {...props} />
|
|
```
|
|
|
|
The supported stable IDs are `meet-tutti`, `clone-github-repository`,
|
|
`task-breakdown`, `quality-review`, `agent-interaction`, and `import-session`.
|
|
Omitting `disabled` (or passing an empty array) renders all six entries.
|
|
|
|
## Tutti Mode capability
|
|
|
|
Tutti Mode UI (composer footer chip, composer badge activation, `/tutti`) is a
|
|
host-gated product capability under
|
|
`hostCapabilities.capabilityMenuState.tuttiMode.enabled`.
|
|
|
|
Hosts must set `enabled: true` to show those controls. Omitting `tuttiMode` or
|
|
setting `enabled: false` fails closed — the same rule as other unsupported host
|
|
capabilities. External hosts that share AgentGUI for Codex/Claude/VM sessions
|
|
should keep Tutti Mode disabled unless they intentionally productize it, and
|
|
should also hide Tutti branding home chips via `disabled` (for example
|
|
`meet-tutti`).
|
|
|
|
```tsx
|
|
<AgentGUI
|
|
disabled={["meet-tutti", "import-session"]}
|
|
hostCapabilities={{
|
|
capabilityMenuState: { tuttiMode: { enabled: false } }
|
|
}}
|
|
{...props}
|
|
/>
|
|
```
|
|
|
|
## Agent Directory
|
|
|
|
`AgentGUI` requires the host's `/agents` projection through its `agents` prop.
|
|
The array is the complete UI directory and its order is authoritative. AgentGUI
|
|
does not add provider catalog entries when the array is empty.
|
|
|
|
```ts
|
|
export interface AgentGUIAgent {
|
|
agentTargetId: string;
|
|
name: string;
|
|
iconUrl: string;
|
|
maskIconUrl?: string | null;
|
|
heroImageUrl?: string | null;
|
|
description?: string | null;
|
|
ownerDeviceLabel?: string | null;
|
|
owner?: {
|
|
name?: string | null;
|
|
avatarUrl?: string | null;
|
|
} | null;
|
|
ownership?: "self" | "shared" | null;
|
|
availability: {
|
|
status:
|
|
| "ready"
|
|
| "checking"
|
|
| "coming_soon"
|
|
| "not_installed"
|
|
| "auth_required"
|
|
| "unavailable";
|
|
reason?: string | null;
|
|
pendingAction?: "install" | "login" | "refresh" | null;
|
|
};
|
|
provider: AgentGUIProvider;
|
|
}
|
|
```
|
|
|
|
`agentTargetId` is the sole entry identity used for selection, filtering,
|
|
composer option lookup, persisted node state, and new-session launch. Two agents
|
|
may share the same `provider` and remain distinct. `provider` is runtime metadata
|
|
for provider-native execution, composer policy, probes, and capabilities; it
|
|
must not be used to group, deduplicate, name, icon, or select agents.
|
|
|
|
Runnable provider targets are host-supplied. If the target catalog is absent,
|
|
AgentGUI presents an explicit unavailable state; it does not synthesize local
|
|
targets from presentation metadata.
|
|
|
|
Agent names, primary icons, optional conversation-mask icons, and optional
|
|
home-carousel artwork come from `agents[].name`, `agents[].iconUrl`,
|
|
`agents[].maskIconUrl`, and `agents[].heroImageUrl`. Hosts must pass fully
|
|
resolved presentation URLs from their authoritative directory. All identity
|
|
surfaces use `iconUrl`; conversation rows use `maskIconUrl` where present.
|
|
`owner.avatarUrl` is rendered separately as an ownership badge.
|
|
`ownerDeviceLabel` is optional host-resolved presentation metadata rendered on
|
|
the exact Handoff target row. Invalid entries and duplicate `agentTargetId`
|
|
values are discarded by
|
|
`normalizeAgentGUIAgents`, with the first occurrence preserving host order.
|
|
Hosts set `agents[].ownership` to `"self"` or `"shared"` from their authoritative
|
|
directory or launch reference. Owner name and avatar are presentation metadata
|
|
and do not determine ownership.
|
|
|
|
With one agent, AgentGUI hides the aggregate `All` entry and renders that agent
|
|
directly. With multiple agents, it shows `All` plus the host-ordered agent rail
|
|
and empty-home carousel. Hosts may customize the aggregate icon with
|
|
`allAgentsPresentation.iconUrl`.
|
|
|
|
Daemon-owned system targets seed and refresh their `iconUrl` and `maskIconUrl`
|
|
from the target descriptor `iconKey`. AgentGUI consumers must not synthesize
|
|
built-in target icons from provider IDs or `iconKey`; stale or missing directory
|
|
presentation should be fixed in the source directory.
|
|
|
|
Hosts that need provider identity presentation may call
|
|
`resolveAgentGUIProviderIdentity(value)` from the narrow
|
|
`@tutti-os/agent-gui/provider-identity` subpath. Migrated providers resolve from
|
|
the generated descriptor catalog, which is checked against the daemon provider
|
|
registry and OpenAPI provider enums.
|
|
|
|
Inside AgentGUI, normalized directory entries use the canonical
|
|
`AgentGUIAgentTarget` / `agentTargets` vocabulary. `provider` is execution
|
|
metadata, not target identity. Rail tiles, the single-agent empty state, and
|
|
the WebGL empty-home carousel all project the same agent-target avatar
|
|
presentation, including the owner badge; renderer-specific DOM and WebGL code
|
|
must not rebuild partial icon-only models.
|
|
|
|
Hosts serving `owner.avatarUrl` from another origin must enable anonymous CORS
|
|
for that asset. The WebGL carousel keeps a local programmatic owner marker when
|
|
the remote image cannot be decoded or uploaded safely, while DOM avatar
|
|
surfaces continue using the same shared presentation.
|
|
|
|
Pass the full `agentDirectory` lifecycle snapshot for directory hydration and
|
|
use `renderAgentsEmpty` for a host-specific loaded-empty state. Use
|
|
`renderAgentUnavailableState` or
|
|
`renderAgentReadinessState` for host-specific availability presentation, and
|
|
handle install/login/refresh requests through `onAgentAvailabilityAction`.
|
|
|
|
Hosts that launch handoffs across session-runtime boundaries may also pass
|
|
`handoffAgentDirectory`. Its ready entries populate only the active-conversation
|
|
Handoff menu; the conversation rail, session queries, and empty composer remain
|
|
owned by `agentDirectory`. When omitted, Handoff uses `agentDirectory`. Handoff
|
|
rows keep the Agent name as the primary identity and render ownership separately:
|
|
entries with `ownership: "self"` are labeled as the current user's Agent, while
|
|
entries with `ownership: "shared"` are labeled as shared and show the available
|
|
owner identity. Entries without explicit ownership remain unclassified; AgentGUI
|
|
does not infer ownership from `owner.name`, `owner.avatarUrl`, or other
|
|
presentation metadata.
|
|
|
|
Host-owned task or activity surfaces can render the same target picker with
|
|
`AgentHandoffMenu`. Pass the authoritative ready `AgentGUIAgentTarget` entries
|
|
and keep launch orchestration in the host's `onSelect` callback; the shared
|
|
component owns only menu disclosure, ownership presentation, and handoff-icon
|
|
motion.
|
|
|
|
The old public `providerTargets`, `providerRailMode`, provider-target renderers,
|
|
and `defaultProviderTargetId` contract is intentionally unsupported. Workbench
|
|
state hydration performs a one-time read of legacy `providerTargetId` into
|
|
`agentTargetId`; new state writes contain only `agentTargetId`.
|
|
|
|
Account and Commerce remain Host chrome. A Host may use
|
|
`renderSlots.agentConfigAccount` to replace the selected target's default
|
|
account/quota block and `hostActions.onAgentConfigMenuOpen` to refresh its
|
|
Host-owned account state. Both receive the same exact target context. Returning
|
|
`null` preserves the default provider account and quota presentation; the slot
|
|
must not start requests or own menu lifecycle. The context declares
|
|
`presentation: "menu"`; interactive slot content must therefore use ui-system
|
|
`DropdownMenuItem` / `DropdownMenuSub` primitives instead of plain buttons or
|
|
links. The same rule applies to `renderSlots.agentConfigSystemActions`.
|