Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/editor/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export { TerrainSculptPanel } from './components/ui/controls/terrain-sculpt-pane
export { ToggleControl } from './components/ui/controls/toggle-control'
export { ToolOptionsPanel } from './components/ui/controls/tool-options-panel'
export { FloatingLevelSelector } from './components/ui/floating-level-selector'
export { IconRefGlyph, IconRefImage } from './components/ui/icon-ref'
export { CATALOG_ITEMS } from './components/ui/item-catalog/catalog-items'
// A base plate's panel (one connected footprint's floor and foundation); the
// slab kind's panel hands base plates to it.
Expand Down Expand Up @@ -725,6 +726,7 @@ export {
resolvePlanarCursorPosition,
} from './lib/planar-cursor-placement'
export type {
ChatStartProps,
ChatToolCardProps,
ChatToolOutput,
PluginChatExtension,
Expand Down
15 changes: 15 additions & 0 deletions packages/editor/src/lib/plugin-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ export type ChatToolCardProps = {
}
}

/**
* What a plugin's start screen does through the host's chat, before anything is said. `send` sends
* a message now, its pictures by reference (a host-stored image), and `attach` puts files on the
* next message, in the composer: both at the level that runs the plugin's tools. `requirePro` only
* asks whether the person's plan includes that level ("Pro" is the hosted product's name for it):
* it answers false after offering the upgrade, and changes nothing in the chat.
*/
export type ChatStartProps = {
send(text: string, images?: readonly { url: string; name: string }[]): void
attach(files: readonly File[]): void
requirePro(): boolean
}

/**
* A plugin's contribution to a host's chat, exported from its browser entry beside its panels and
* views; its tool contracts are its `./agent-tools` export. Which tools a turn offers, and to whom,
Expand All @@ -47,4 +60,6 @@ export type PluginChatExtension = {
actions?: readonly { id: string; label: string; hint: string; prompt: string }[]
/** File extensions or MIME types the plugin's tools read, which the composer then accepts. */
accepts?: readonly string[]
/** What the chat shows while its thread is empty, loaded lazily. */
start?: () => Promise<{ default: ComponentType<ChatStartProps> }>
}
2 changes: 2 additions & 0 deletions wiki/architecture/plugin-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ export const signageChat: PluginChatExtension = {
cards: { signage_schedule: () => import('./schedule-card') },
actions: [{ id: 'exit-signs', label: 'Exit signs', hint: 'Sign every exit', prompt: 'Place exit signs on every level.' }],
accepts: ['.csv'],
start: () => import('./chat-start'),
}
```

Expand All @@ -368,6 +369,7 @@ export const signageChat: PluginChatExtension = {
- **The host decides.** Which tools a turn offers, to whom and at what cost, whether a `chatOnly` request is honoured, and how far `timeoutMs` may go are host policy, like a panel's `access`. Being in `installedPlugins` is necessary, not sufficient. These packages define the shapes; a host keeps its own catalog of the plugins it serves.
- **Trusted code.** These exports run with the application's privileges: a zod schema is code, and an executor or a card runs in the page. Hosts load reviewed, pinned plugins. The purity rule keeps contracts loadable in a sandboxed workflow; it does not isolate them.
- **Cards and outputs.** A card renders from the persisted call alone (`toolName`, `input`, `output`, `state`), so a reloaded chat shows the same card; its `actions` open a view, select nodes or send a prompt. A `ChatToolOutput` carries images by reference (`ref`), never bytes. `actions` add entries to the composer's `/` menu; `accepts` lists the file types the plugin's tools read.
- **A start screen.** `start` is what the host's chat shows while its thread is empty. It acts only through its `ChatStartProps`: `send` a message (pictures by reference) or `attach` files to the composer, both at the level the plugin's tools run at, and `requirePro()` before a step that needs that level: it answers false after the host offered the upgrade, and changes nothing in the chat. Render registry icons with `IconRefGlyph`, as the editor does.

The rules both surfaces follow for these tools are in [agent surfaces](agent-surfaces.md#plugin-tools).

Expand Down
Loading