add(coding-agent): add defineTool helper closes #2746
This commit is contained in:
@@ -73,6 +73,8 @@ After runtime replacement, use `runtimeHost.session` as the new live session and
|
|||||||
|
|
||||||
- Added public SDK runtime-host exports `createAgentSessionRuntime()` and `AgentSessionRuntimeHost` for apps that need runtime-backed session replacement and mode-style session switching
|
- Added public SDK runtime-host exports `createAgentSessionRuntime()` and `AgentSessionRuntimeHost` for apps that need runtime-backed session replacement and mode-style session switching
|
||||||
|
|
||||||
|
- Added `defineTool()` so standalone and array-based custom tool definitions keep inferred parameter types without manual casts ([#2746](https://github.com/badlogic/pi-mono/issues/2746))
|
||||||
|
|
||||||
- Added label timestamps to the session tree with a `Shift+T` toggle in `/tree`, smart date formatting, and timestamp preservation through branching ([#2691](https://github.com/badlogic/pi-mono/pull/2691) by [@w-winter](https://github.com/w-winter))
|
- Added label timestamps to the session tree with a `Shift+T` toggle in `/tree`, smart date formatting, and timestamp preservation through branching ([#2691](https://github.com/badlogic/pi-mono/pull/2691) by [@w-winter](https://github.com/w-winter))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -493,21 +493,21 @@ const { session } = await createAgentSession({
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import { createAgentSession, type ToolDefinition } from "@mariozechner/pi-coding-agent";
|
import { createAgentSession, defineTool } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
// Inline custom tool
|
// Inline custom tool
|
||||||
const myTool: ToolDefinition = {
|
const myTool = defineTool({
|
||||||
name: "my_tool",
|
name: "my_tool",
|
||||||
label: "My Tool",
|
label: "My Tool",
|
||||||
description: "Does something useful",
|
description: "Does something useful",
|
||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
input: Type.String({ description: "Input value" }),
|
input: Type.String({ description: "Input value" }),
|
||||||
}),
|
}),
|
||||||
execute: async (toolCallId, params, onUpdate, ctx, signal) => ({
|
execute: async (_toolCallId, params) => ({
|
||||||
content: [{ type: "text", text: `Result: ${params.input}` }],
|
content: [{ type: "text", text: `Result: ${params.input}` }],
|
||||||
details: {},
|
details: {},
|
||||||
}),
|
}),
|
||||||
};
|
});
|
||||||
|
|
||||||
// Pass custom tools directly
|
// Pass custom tools directly
|
||||||
const { session } = await createAgentSession({
|
const { session } = await createAgentSession({
|
||||||
@@ -515,6 +515,8 @@ const { session } = await createAgentSession({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Use `defineTool()` for standalone definitions and arrays like `customTools: [myTool]`. Inline `pi.registerTool({ ... })` already infers parameter types correctly.
|
||||||
|
|
||||||
Custom tools passed via `customTools` are combined with extension-registered tools. Extensions loaded by the ResourceLoader can also register tools via `pi.registerTool()`.
|
Custom tools passed via `customTools` are combined with extension-registered tools. Extensions loaded by the ResourceLoader can also register tools via `pi.registerTool()`.
|
||||||
|
|
||||||
> See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
|
> See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
|
||||||
@@ -828,14 +830,14 @@ import { getModel } from "@mariozechner/pi-ai";
|
|||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import {
|
import {
|
||||||
AuthStorage,
|
AuthStorage,
|
||||||
|
bashTool,
|
||||||
createAgentSession,
|
createAgentSession,
|
||||||
DefaultResourceLoader,
|
DefaultResourceLoader,
|
||||||
|
defineTool,
|
||||||
ModelRegistry,
|
ModelRegistry,
|
||||||
|
readTool,
|
||||||
SessionManager,
|
SessionManager,
|
||||||
SettingsManager,
|
SettingsManager,
|
||||||
readTool,
|
|
||||||
bashTool,
|
|
||||||
type ToolDefinition,
|
|
||||||
} from "@mariozechner/pi-coding-agent";
|
} from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
// Set up auth storage (custom location)
|
// Set up auth storage (custom location)
|
||||||
@@ -850,7 +852,7 @@ if (process.env.MY_KEY) {
|
|||||||
const modelRegistry = ModelRegistry.create(authStorage);
|
const modelRegistry = ModelRegistry.create(authStorage);
|
||||||
|
|
||||||
// Inline tool
|
// Inline tool
|
||||||
const statusTool: ToolDefinition = {
|
const statusTool = defineTool({
|
||||||
name: "status",
|
name: "status",
|
||||||
label: "Status",
|
label: "Status",
|
||||||
description: "Get system status",
|
description: "Get system status",
|
||||||
@@ -859,7 +861,7 @@ const statusTool: ToolDefinition = {
|
|||||||
content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }],
|
content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }],
|
||||||
details: {},
|
details: {},
|
||||||
}),
|
}),
|
||||||
};
|
});
|
||||||
|
|
||||||
const model = getModel("anthropic", "claude-opus-4-5");
|
const model = getModel("anthropic", "claude-opus-4-5");
|
||||||
if (!model) throw new Error("Model not found");
|
if (!model) throw new Error("Model not found");
|
||||||
@@ -1030,6 +1032,7 @@ type ResourceLoader
|
|||||||
createEventBus
|
createEventBus
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
defineTool
|
||||||
|
|
||||||
// Session management
|
// Session management
|
||||||
SessionManager
|
SessionManager
|
||||||
|
|||||||
@@ -3,23 +3,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Type } from "@mariozechner/pi-ai";
|
import { Type } from "@mariozechner/pi-ai";
|
||||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
import { defineTool, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
const helloTool = defineTool({
|
||||||
|
name: "hello",
|
||||||
|
label: "Hello",
|
||||||
|
description: "A simple greeting tool",
|
||||||
|
parameters: Type.Object({
|
||||||
|
name: Type.String({ description: "Name to greet" }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `Hello, ${params.name}!` }],
|
||||||
|
details: { greeted: params.name },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default function (pi: ExtensionAPI) {
|
export default function (pi: ExtensionAPI) {
|
||||||
pi.registerTool({
|
pi.registerTool(helloTool);
|
||||||
name: "hello",
|
|
||||||
label: "Hello",
|
|
||||||
description: "A simple greeting tool",
|
|
||||||
parameters: Type.Object({
|
|
||||||
name: Type.String({ description: "Name to greet" }),
|
|
||||||
}),
|
|
||||||
|
|
||||||
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
||||||
const { name } = params as { name: string };
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Hello, ${name}!` }],
|
|
||||||
details: { greeted: name },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ export type {
|
|||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
// Type guards
|
// Type guards
|
||||||
export {
|
export {
|
||||||
|
defineTool,
|
||||||
isBashToolResult,
|
isBashToolResult,
|
||||||
isEditToolResult,
|
isEditToolResult,
|
||||||
isFindToolResult,
|
isFindToolResult,
|
||||||
|
|||||||
@@ -404,6 +404,21 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
|||||||
) => Component;
|
) => Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AnyToolDefinition = ToolDefinition<any, any, any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preserve parameter inference for standalone tool definitions.
|
||||||
|
*
|
||||||
|
* Use this when assigning a tool to a variable or passing it through arrays such
|
||||||
|
* as `customTools`, where contextual typing would otherwise widen params to
|
||||||
|
* `unknown`.
|
||||||
|
*/
|
||||||
|
export function defineTool<TParams extends TSchema, TDetails = unknown, TState = any>(
|
||||||
|
tool: ToolDefinition<TParams, TDetails, TState>,
|
||||||
|
): ToolDefinition<TParams, TDetails, TState> & AnyToolDefinition {
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Resource Events
|
// Resource Events
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export {
|
|||||||
type AgentToolUpdateCallback,
|
type AgentToolUpdateCallback,
|
||||||
type BeforeAgentStartEvent,
|
type BeforeAgentStartEvent,
|
||||||
type ContextEvent,
|
type ContextEvent,
|
||||||
|
defineTool,
|
||||||
discoverAndLoadExtensions,
|
discoverAndLoadExtensions,
|
||||||
type ExecOptions,
|
type ExecOptions,
|
||||||
type ExecResult,
|
type ExecResult,
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export type {
|
|||||||
} from "./core/extensions/index.js";
|
} from "./core/extensions/index.js";
|
||||||
export {
|
export {
|
||||||
createExtensionRuntime,
|
createExtensionRuntime,
|
||||||
|
defineTool,
|
||||||
discoverAndLoadExtensions,
|
discoverAndLoadExtensions,
|
||||||
ExtensionRunner,
|
ExtensionRunner,
|
||||||
isBashToolResult,
|
isBashToolResult,
|
||||||
|
|||||||
Reference in New Issue
Block a user