mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 12:03:49 +00:00
- Removed Attachment from agent package (now in web-ui/coding-agent) - Agent.prompt now takes (text, images?: ImageContent[]) - Removed transports from web-ui (duplicate of agent package) - Updated coding-agent to use local message types - Updated mom package for new agent API Remaining: Fix AgentInterface.ts to compose UserMessageWithAttachments |
||
|---|---|---|
| .. | ||
| hello | ||
| question | ||
| subagent | ||
| todo | ||
| README.md | ||
Custom Tools Examples
Example custom tools for pi-coding-agent.
Examples
Each example uses the subdirectory/index.ts structure required for tool discovery.
hello/
Minimal example showing the basic structure of a custom tool.
question/
Demonstrates pi.ui.select() for asking the user questions with options.
todo/
Full-featured example demonstrating:
onSessionfor state reconstruction from session history- Custom
renderCallandrenderResult - Proper branching support via details storage
- State management without external files
subagent/
Delegate tasks to specialized subagents with isolated context windows. Includes:
index.ts- The custom tool (single, parallel, and chain modes)agents.ts- Agent discovery helperagents/- Sample agent definitions (scout, planner, reviewer, worker)commands/- Workflow presets (/implement, /scout-and-plan, /implement-and-review)
See subagent/README.md for full documentation.
Usage
# Test directly (can point to any .ts file)
pi --tool examples/custom-tools/todo/index.ts
# Or copy entire folder to tools directory for persistent use
cp -r todo ~/.pi/agent/tools/
Then in pi:
> add a todo "test custom tools"
> list todos
> toggle todo #1
> clear todos
Writing Custom Tools
See docs/custom-tools.md for full documentation.
Key Points
Factory pattern:
import { Type } from "@sinclair/typebox";
import { StringEnum } from "@mariozechner/pi-ai";
import { Text } from "@mariozechner/pi-tui";
import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
const factory: CustomToolFactory = (pi) => ({
name: "my_tool",
label: "My Tool",
description: "Tool description for LLM",
parameters: Type.Object({
action: StringEnum(["list", "add"] as const),
}),
// Called on session start/switch/branch/clear
onSession(event) {
// Reconstruct state from event.entries
},
async execute(toolCallId, params) {
return {
content: [{ type: "text", text: "Result" }],
details: { /* for rendering and state reconstruction */ },
};
},
});
export default factory;
Custom rendering:
renderCall(args, theme) {
return new Text(
theme.fg("toolTitle", theme.bold("my_tool ")) + args.action,
0, 0 // No padding - Box handles it
);
},
renderResult(result, { expanded, isPartial }, theme) {
if (isPartial) {
return new Text(theme.fg("warning", "Working..."), 0, 0);
}
return new Text(theme.fg("success", "✓ Done"), 0, 0);
},
Use StringEnum for string parameters (required for Google API compatibility):
import { StringEnum } from "@mariozechner/pi-ai";
// Good
action: StringEnum(["list", "add"] as const)
// Bad - doesn't work with Google
action: Type.Union([Type.Literal("list"), Type.Literal("add")])