support custom tools (#2668)

This commit is contained in:
Dax
2025-09-18 03:58:21 -04:00
committed by GitHub
parent e9d902d844
commit 3b6c0ec0b3
12 changed files with 140 additions and 488 deletions

View File

@@ -1,14 +1,20 @@
import { Plugin } from "./index"
import { tool } from "./tool"
export const ExamplePlugin: Plugin = async ({
client: _client,
$: _shell,
project: _project,
directory: _directory,
worktree: _worktree,
}) => {
export const ExamplePlugin: Plugin = async (ctx) => {
return {
permission: {},
tool: {
mytool: tool((zod) => ({
description: "This is a custom tool tool",
args: {
foo: zod.string(),
},
async execute(args, ctx) {
return `Hello ${args.foo}!`
},
})),
},
async "chat.params"(_input, output) {
output.topP = 1
},

View File

@@ -10,7 +10,11 @@ import type {
Auth,
Config,
} from "@opencode-ai/sdk"
import type { BunShell } from "./shell"
import { type ToolDefinition } from "./tool"
export * from "./tool"
export type PluginInput = {
client: ReturnType<typeof createOpencodeClient>
@@ -18,34 +22,16 @@ export type PluginInput = {
directory: string
worktree: string
$: BunShell
Tool: {
define(id: string, init: any | (() => Promise<any>)): any
}
z: any // Zod instance for creating schemas
}
export type Plugin = (input: PluginInput) => Promise<Hooks>
// Lightweight schema spec for HTTP-registered tools
export type HttpParamSpec = {
type: "string" | "number" | "boolean" | "array"
description?: string
optional?: boolean
items?: "string" | "number" | "boolean"
}
export type HttpToolRegistration = {
id: string
description: string
parameters: {
type: "object"
properties: Record<string, HttpParamSpec>
}
callbackUrl: string
headers?: Record<string, string>
}
export type Plugin = (input: PluginInput) => Promise<Hooks>
export interface Hooks {
event?: (input: { event: Event }) => Promise<void>
config?: (input: Config) => Promise<void>
tool?: {
[key: string]: ToolDefinition
}
auth?: {
provider: string
loader?: (auth: () => Promise<Auth>, provider: Provider) => Promise<Record<string, any>>
@@ -121,16 +107,4 @@ export interface Hooks {
metadata: any
},
) => Promise<void>
/**
* Allow plugins to register additional tools with the server.
* Use registerHTTP to add a tool that calls back to your plugin/service.
* Use register to add a native/local tool with direct function execution.
*/
"tool.register"?: (
input: {},
output: {
registerHTTP: (tool: HttpToolRegistration) => void | Promise<void>
register: (tool: any) => void | Promise<void> // Tool.Info type from opencode
},
) => Promise<void>
}

View File

@@ -0,0 +1,20 @@
import { z } from "zod/v4"
export type ToolContext = {
sessionID: string
messageID: string
agent: string
abort: AbortSignal
}
export function tool<Args extends z.ZodRawShape>(
input: (zod: typeof z) => {
description: string
args: Args
execute: (args: z.infer<z.ZodObject<Args>>, ctx: ToolContext) => Promise<string>
},
) {
return input(z)
}
export type ToolDefinition = ReturnType<typeof tool>