-
Notifications
You must be signed in to change notification settings - Fork 0
Tool Registry
The in-process registry that holds every AI tool the model can call. Self-describing tools register once; AIManager.getToolDefinitions() lists them for the LLM; toolRegistry.dispatch() runs them.
Source: src/main/ai-tools/registry.ts.
export interface ToolRuntimeState {
currentStep: { number: number; title: string; action: string; successCriteria: string } | null
}
export interface VisionHelpers {
verify: (input: { imagePath: string; question: string }) => Promise<{
verdict: 'yes' | 'no' | 'unclear'
explanation: string
}>
describe: (input: { imagePath: string; prompt?: string }) => Promise<{
description: string
}>
}
export interface ToolContext {
window: BrowserWindow
ptyManager: PtyManager
workspaceStore: WorkspaceStore
agentStore: AgentStore
orchestrationStore: OrchestrationStore
configLoader: ConfigLoader
state: ToolRuntimeState
vision?: VisionHelpers // undefined when no provider is configured
}
export interface ToolDef<TArgs = Record<string, unknown>, TResult = unknown> {
name: string
description: string
parameters: AIToolDefinition['function']['parameters'] // OpenAI tool-schema
run: (args: TArgs, ctx: ToolContext) => TResult | Promise<TResult>
}class Registry {
register<TArgs, TResult>(def: ToolDef<TArgs, TResult>): void
unregister(name: string): boolean
has(name: string): boolean
listDefinitions(): AIToolDefinition[] // OpenAI-format
dispatch(name, args, ctx): Promise<
| { ok: true; result: unknown; durationMs: number }
| { ok: false; error: string; durationMs: number }
>
}
export const toolRegistry = new Registry()register warns (but allows) overwriting an existing tool — supports hot-reloading plugin tools without restart.
dispatch never throws — errors are wrapped and returned as { ok: false, error, durationMs }. The caller (AIManager.executeTool) renders these as tool results so the model sees the error and can adjust.
Example: a tool that returns the current time.
import { toolRegistry } from './registry'
toolRegistry.register<{ timezone?: string }, { now: string; timezone: string }>({
name: 'get_current_time',
description: 'Returns the current ISO timestamp in the specified timezone (default UTC).',
parameters: {
type: 'object',
properties: {
timezone: {
type: 'string',
description: 'IANA timezone name (e.g., "America/New_York"). Defaults to UTC.'
}
}
},
run: async ({ timezone }) => {
const tz = timezone ?? 'UTC'
return {
now: new Date().toLocaleString('en-US', { timeZone: tz, hour12: false }),
timezone: tz
}
}
})What this gives you:
- The model sees the tool in
getToolDefinitions()output - The model can call it with
{timezone: 'America/Los_Angeles'} - The result is returned to the model as a tool message
- Errors thrown inside
run()are caught and surfaced as an error tool result
-
<category>_<verb>_<object>— e.g.,browser_click,read_terminal_output,goal_assign_task - Lowercase, snake_case, no spaces
- Categories already in use:
browser_*,read_*,write_*,wait_*,poll_*,list_*,capture_*,focus_*,maximize_*,restart_*,convert_*, agent verbs (set_agent_role,assign_task, etc.),declare_step,verify_step,claim_complete,abort_with_report - Avoid conflicts with the built-in catalog (see AI-Tools-Reference)
If your tool collides with a built-in, the last registration wins — so user plugin tools can intentionally override built-ins. The registry logs a warning to console.
| Field | Use |
|---|---|
window |
The main BrowserWindow. Use for window.webContents.send(...) to push events to the renderer, or window.webContents.capturePage() for screenshots. |
ptyManager |
PTY pool. getPtyIdForPane(paneId), getScrollbackBuffer(ptyId), write(ptyId, data). |
workspaceStore |
Workspaces + settings. getSettings().activeWorkspaceId, get(workspaceId). |
agentStore |
Per-pane agent state. setRole, assignTask, completeTask, etc. |
orchestrationStore |
Multi-pane orchestration goals + events. |
configLoader |
Loaded personas, skills, task templates. |
state |
Per-AIManager ToolRuntimeState — currently just currentStep for the step protocol. Add fields here for tool-to-tool coordination. |
vision |
Optional vision helpers. undefined when no AI provider configured. Tools must guard before using. |
For tools returning large text payloads, use the standard envelope:
{
success: true,
content: string, // chunk for this page
hasMore: boolean,
nextCursor?: string, // pass back to get next chunk
totalBytes: number,
truncated?: boolean
}The model is taught about pagination in the default system prompt. Tools already using this envelope: read_terminal_output, browser_get_content, browser_get_axtree.
For your own tool, store the full content somewhere keyed by an opaque cursor, return chunks slice-by-slice.
src/main/ai-tools/
├── registry.ts — the Registry class
├── index.ts — registerAllTools() + plugin loader bootstrap
├── plugin-loader.ts — fs.watch + require-cache busting for hot reload
├── step-protocol.ts — declare_step, verify_step
├── pane.ts — list_panes, capture_screenshot, focus_pane, ...
├── terminal.ts — write_to_terminal, read_terminal_output, ...
├── orchestration.ts — get_fleet_status, assign_task, ...
└── browser/
├── _helpers.ts — saveScreenshotToDisk, cdpClickAt
├── navigation.ts — navigate, get_content, screenshot, execute_js, back/forward/reload
├── interaction-t1.ts — click, type, wait_for_*, keypress, scroll, select, check
├── interaction-t2.ts — query, get_axtree, set_files, click_at, hover, drag, full_page, annotated
├── advanced.ts — smart_click, run_recipe, cookies, save_pdf/html, convert_pane_*
└── vision.ts — verify_visual_state, describe_screen
The bootstrap at index.ts:registerAllTools() is called once from AIManager's constructor.
User-authored tools dropped into <userData>/clusterspace-data/config/tools/*.js are loaded automatically by plugin-loader.ts (CommonJS, hot-reloaded on file change). Full guide: Plugin-Authoring.
- AI-Tools-Reference — complete catalog of registered tools
- Plugin-Authoring — write your own tools
- Architecture-Overview — where the registry fits in the dispatch flow
- Goal-Policy-and-Risk-Levels — risk-level table that gates tool dispatch during goals
ClusterSpace · Issues · Releases · MIT License · Edit any page via the Edit button (top right of the wiki).
- Workspaces-and-Layout
- Terminal-Panes
- Per-Pane-Tabs
- SSH-and-tmux
- Browser-Panes
- Saved-Logins
- Command-Palette
- Broadcast-Mode
- Settings-and-Configuration
- AI-Overview
- AI-Providers
- AI-Chat-Panel
- AI-Tools-Reference
- Personas
- Skills
- Task-Templates
- Agent-Orchestration
- Fleet-Dashboard
- Goal-Runner-Overview
- Starting-a-Goal
- Success-Criteria
- Goal-Policy-and-Risk-Levels
- Critic-and-Replan
- Vision-Verification
- Goal-Dashboard