v2-refactor-temp/docs/ai/composer-tool-surface-design.md
This note covers the chat composer tool surface shared by assistant chat and agent sessions:
+ menu in the message composer./ root suggestion panel.It does not cover the main-process LLM tool registry, tool execution, approval persistence, or model-side defer exposition except where those concepts affect renderer discoverability.
Assistant chat and agent sessions share the same renderer tool runtime:
ComposerToolRuntimeHost resolves tools by scope.ComposerToolMenu renders the + menu.ComposerSurface renders the / root suggestion panel from
root-panel launchers.The current launcher model has two sources:
popover — intended for the + menu.root-panel — intended for the / suggestion panel.The awkward part is that ComposerToolMenu currently merges popover
launchers with root-only launchers. This makes keyboard/search-oriented items
appear in the + menu, and it is most visible in agent sessions where slash
commands can expand into several shallow items.
+ menu a long flat catalog.+ menu into a complete searchable command palette.+ menu: capability discovery and lightweight togglesThe + menu should contain stable, user-recognizable capabilities:
The first level should prefer one row per capability. It should not directly list dynamic children such as each slash command, each MCP prompt, each MCP resource, every quick phrase, or every knowledge file.
/ panel: keyboard-first commands and searchThe / root suggestion panel should own high-frequency and searchable actions:
These entries benefit from filtering, keyboard navigation, and insertion into
the editor. They should stay out of the first-level + menu unless they are
represented by a single parent entry.
Active state should be visible without reopening the + menu:
These chips are status feedback and quick toggles. They should not replace the
discoverability role of the + menu.
Use three categories instead of one blanket filter.
Show normally when the tool belongs to the current scope and all requirements are satisfied.
Examples:
Show disabled when the user reasonably expects the capability to exist, but a model, assistant setting, provider setting, or configuration makes it unavailable.
This should be the default for core capabilities:
Disabled rows should include a short tooltip or secondary text. The reason should be actionable when possible, for example "Select a function-calling model" or "Configure a web search provider".
Hide only when the concept does not belong to the current scope.
Examples:
This keeps the two sides honest without making users wonder why a known feature disappeared because of model capability.
Assistant chat owns assistant-configured context and model-selection workflows.
First-level + entries:
| Capability | Default treatment | Notes |
|---|---|---|
| Attachment | Show; disabled if no supported file type | File type support follows selected model set |
| Knowledge base | Show; disabled with reason if unavailable | Belongs to assistant chat only |
| Web search | Show; disabled or guarded with reason | Built-in model search and external provider paths differ |
| MCP | Show; disabled with reason if unavailable | First level is only the mode / parent entry |
| Thinking | Show; disabled if model cannot configure reasoning | Active chip shows selected effort |
| Generate image | Show; disabled if unsupported | Only meaningful for image-capable generation models |
| Quick phrases | Prefer / panel, not first-level + | If kept in +, use a parent entry only |
Model effects:
Agent sessions own runtime/session concepts rather than assistant chat configuration.
First-level + entries:
| Capability | Default treatment | Notes |
|---|---|---|
| Attachment | Show; disabled if no supported file type | Agent session file tokens only |
| Permission mode | Show | Agent-only; opens a small picker |
| Thinking | Show; disabled if model cannot configure reasoning | Controlled by session-local state before send |
| Slash commands | Show parent entry only when commands exist | Do not flatten each command into + |
| Quick phrases | Prefer / panel, not first-level + | Same search-oriented behavior as assistant chat |
Agent-only affordances:
+ because it is a shallow, low-cardinality mode
picker.+, with the concrete command list
handled by QuickPanel or the / trigger.+ menu, because it depends on search over accessible paths.Model effects:
claude-code provides /clear,
/compact, /context, /cost, and /todos; other agent types provide no
built-in slash commands.Use a nested popover only for shallow, bounded, non-search actions:
Use QuickPanel instead of nested popovers for list/search actions:
Reason: these lists benefit from filtering, keyboard navigation, and stable height. Nested popovers are harder to scan, easier to overflow, and worse for command insertion workflows.
Recommended source semantics:
popover: first-level + menu entry.root-panel: / suggestion entry.ComposerToolMenu should not automatically backfill root-only launchers into
the + menu. A tool that wants a parent entry in + and child entries in /
should register them separately:
sources: ['popover'].sources: ['root-panel'].Disabled entries should include:
Suggested reason examples:
| Capability | Reason |
|---|---|
| Thinking | Current model does not support adjustable reasoning |
| Generate image | Current model does not support image generation |
| Knowledge base | Select a tool-capable model |
| Knowledge base | No knowledge base is configured for this assistant |
| MCP | No MCP tools are enabled for this assistant |
| Web search | Configure a web search provider |
| Attachment | Current model does not accept supported file types |
Keep the text short. Detailed setup flows should open settings rather than expanding explanatory copy inside the menu.
Likely renderer changes:
disabledReason?: ReactNode | string.ComposerToolMenu.popover parent launcher and keep command children
as root-panel only.root-panel only; use a parent MCP
row in +.Targeted test areas:
ComposerToolRuntime.test.tsx for launcher source behavior.ChatComposer.test.tsx for assistant-side visible/disabled states.AgentComposer.test.tsx for agent-side slash-command and permission-mode
behavior.+ menu never appears empty; if no entries are available, the trigger is
hidden or disabled with a clear reason./ remains the primary path for searchable command insertion.+ no longer flattens every slash command into first-level rows.