feat(agent,coding-agent): per-tool executionMode override for sequential tool execution (#3345)
* feat(agent,coding-agent): add per-tool executionMode field to AgentTool and ToolDefinition Add optional executionMode?: ToolExecutionMode to AgentTool and ToolDefinition interfaces. Propagate through wrapToolDefinition and createToolDefinitionFromAgentTool. No behavioral change yet — agent loop will read this field in a follow-up. * feat(agent): support per-tool executionMode override for sequential execution When a tool defines executionMode='sequential', the agent loop forces sequential execution of all tool calls in that batch, even if the global config is parallel. * feat(coding-agent): re-export ToolExecutionMode from @mariozechner/pi-agent-core Makes the type available to extensions that want to set executionMode on tool definitions. * feat(coding-agent): add tic-tac-toe extension example with executionMode: sequential Demonstrates per-tool executionMode: the agent plays via move/play tool calls that share a cursor. Without sequential execution, play can resolve before earlier moves finish, landing on the wrong cell.
This commit is contained in:
@@ -104,6 +104,8 @@ Tool execution mode is configurable:
|
|||||||
- `parallel` (default): preflight tool calls sequentially, execute allowed tools concurrently, emit final `tool_execution_end` and `toolResult` messages in assistant source order
|
- `parallel` (default): preflight tool calls sequentially, execute allowed tools concurrently, emit final `tool_execution_end` and `toolResult` messages in assistant source order
|
||||||
- `sequential`: execute tool calls one by one, matching the historical behavior
|
- `sequential`: execute tool calls one by one, matching the historical behavior
|
||||||
|
|
||||||
|
The mode can be set globally via `toolExecution` in the agent config, or per-tool via `executionMode` on `AgentTool`. If any tool call in a batch targets a tool with `executionMode: "sequential"`, the entire batch executes sequentially regardless of the global setting.
|
||||||
|
|
||||||
The `beforeToolCall` hook runs after `tool_execution_start` and validated argument parsing. It can block execution. The `afterToolCall` hook runs after tool execution finishes and before `tool_execution_end` and final tool result message events are emitted.
|
The `beforeToolCall` hook runs after `tool_execution_start` and validated argument parsing. It can block execution. The `afterToolCall` hook runs after tool execution finishes and before `tool_execution_end` and final tool result message events are emitted.
|
||||||
|
|
||||||
When you use the `Agent` class, assistant `message_end` processing is treated as a barrier before tool preflight begins. That means `beforeToolCall` sees agent state that already includes the assistant message that requested the tool call.
|
When you use the `Agent` class, assistant `message_end` processing is treated as a barrier before tool preflight begins. That means `beforeToolCall` sees agent state that already includes the assistant message that requested the tool call.
|
||||||
@@ -367,6 +369,11 @@ const readFileTool: AgentTool = {
|
|||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
path: Type.String({ description: "File path" }),
|
path: Type.String({ description: "File path" }),
|
||||||
}),
|
}),
|
||||||
|
// Override execution mode for this tool (optional).
|
||||||
|
// "sequential" forces the entire batch to run one at a time.
|
||||||
|
// "parallel" allows concurrent execution with other tool calls.
|
||||||
|
// If omitted, the global toolExecution config applies.
|
||||||
|
executionMode: "sequential",
|
||||||
execute: async (toolCallId, params, signal, onUpdate) => {
|
execute: async (toolCallId, params, signal, onUpdate) => {
|
||||||
const content = await fs.readFile(params.path, "utf-8");
|
const content = await fs.readFile(params.path, "utf-8");
|
||||||
|
|
||||||
@@ -432,7 +439,7 @@ const context: AgentContext = {
|
|||||||
const config: AgentLoopConfig = {
|
const config: AgentLoopConfig = {
|
||||||
model: getModel("openai", "gpt-4o"),
|
model: getModel("openai", "gpt-4o"),
|
||||||
convertToLlm: (msgs) => msgs.filter(m => ["user", "assistant", "toolResult"].includes(m.role)),
|
convertToLlm: (msgs) => msgs.filter(m => ["user", "assistant", "toolResult"].includes(m.role)),
|
||||||
toolExecution: "parallel",
|
toolExecution: "parallel", // overridden by per-tool executionMode if set
|
||||||
beforeToolCall: async ({ toolCall, args, context }) => undefined,
|
beforeToolCall: async ({ toolCall, args, context }) => undefined,
|
||||||
afterToolCall: async ({ toolCall, result, isError, context }) => undefined,
|
afterToolCall: async ({ toolCall, result, isError, context }) => undefined,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -341,7 +341,10 @@ async function executeToolCalls(
|
|||||||
emit: AgentEventSink,
|
emit: AgentEventSink,
|
||||||
): Promise<ToolResultMessage[]> {
|
): Promise<ToolResultMessage[]> {
|
||||||
const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
|
const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
|
||||||
if (config.toolExecution === "sequential") {
|
const hasSequentialToolCall = toolCalls.some(
|
||||||
|
(tc) => currentContext.tools?.find((t) => t.name === tc.name)?.executionMode === "sequential",
|
||||||
|
);
|
||||||
|
if (config.toolExecution === "sequential" || hasSequentialToolCall) {
|
||||||
return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);
|
return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);
|
||||||
}
|
}
|
||||||
return executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit);
|
return executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit);
|
||||||
|
|||||||
@@ -304,6 +304,14 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any
|
|||||||
signal?: AbortSignal,
|
signal?: AbortSignal,
|
||||||
onUpdate?: AgentToolUpdateCallback<TDetails>,
|
onUpdate?: AgentToolUpdateCallback<TDetails>,
|
||||||
) => Promise<AgentToolResult<TDetails>>;
|
) => Promise<AgentToolResult<TDetails>>;
|
||||||
|
/**
|
||||||
|
* Per-tool execution mode override.
|
||||||
|
* - "sequential": this tool must execute one at a time with other tool calls.
|
||||||
|
* - "parallel": this tool can execute concurrently with other tool calls.
|
||||||
|
*
|
||||||
|
* If omitted, the default execution mode applies.
|
||||||
|
*/
|
||||||
|
executionMode?: ToolExecutionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Context snapshot passed into the low-level agent loop. */
|
/** Context snapshot passed into the low-level agent loop. */
|
||||||
|
|||||||
@@ -635,6 +635,250 @@ describe("agentLoop with AgentMessage", () => {
|
|||||||
// Interrupt message should be in context when second LLM call is made
|
// Interrupt message should be in context when second LLM call is made
|
||||||
expect(sawInterruptInContext).toBe(true);
|
expect(sawInterruptInContext).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should force sequential execution when a tool has executionMode=sequential even with default parallel config", async () => {
|
||||||
|
const toolSchema = Type.Object({ value: Type.String() });
|
||||||
|
let firstResolved = false;
|
||||||
|
let parallelObserved = false;
|
||||||
|
let releaseFirst: (() => void) | undefined;
|
||||||
|
const firstDone = new Promise<void>((resolve) => {
|
||||||
|
releaseFirst = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
const slowTool: AgentTool<typeof toolSchema, { value: string }> = {
|
||||||
|
name: "slow",
|
||||||
|
label: "Slow",
|
||||||
|
description: "Slow tool",
|
||||||
|
parameters: toolSchema,
|
||||||
|
executionMode: "sequential",
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
if (params.value === "first") {
|
||||||
|
await firstDone;
|
||||||
|
firstResolved = true;
|
||||||
|
}
|
||||||
|
if (params.value === "second" && !firstResolved) {
|
||||||
|
parallelObserved = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `slow: ${params.value}` }],
|
||||||
|
details: { value: params.value },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const context: AgentContext = {
|
||||||
|
systemPrompt: "",
|
||||||
|
messages: [],
|
||||||
|
tools: [slowTool],
|
||||||
|
};
|
||||||
|
|
||||||
|
const userPrompt: AgentMessage = createUserMessage("run both");
|
||||||
|
// config is parallel (default), but tool forces sequential
|
||||||
|
const config: AgentLoopConfig = {
|
||||||
|
model: createModel(),
|
||||||
|
convertToLlm: identityConverter,
|
||||||
|
};
|
||||||
|
|
||||||
|
let callIndex = 0;
|
||||||
|
const stream = agentLoop([userPrompt], context, config, undefined, () => {
|
||||||
|
const mockStream = new MockAssistantStream();
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (callIndex === 0) {
|
||||||
|
const message = createAssistantMessage(
|
||||||
|
[
|
||||||
|
{ type: "toolCall", id: "tool-1", name: "slow", arguments: { value: "first" } },
|
||||||
|
{ type: "toolCall", id: "tool-2", name: "slow", arguments: { value: "second" } },
|
||||||
|
],
|
||||||
|
"toolUse",
|
||||||
|
);
|
||||||
|
mockStream.push({ type: "done", reason: "toolUse", message });
|
||||||
|
setTimeout(() => releaseFirst?.(), 20);
|
||||||
|
} else {
|
||||||
|
const message = createAssistantMessage([{ type: "text", text: "done" }]);
|
||||||
|
mockStream.push({ type: "done", reason: "stop", message });
|
||||||
|
}
|
||||||
|
callIndex++;
|
||||||
|
});
|
||||||
|
return mockStream;
|
||||||
|
});
|
||||||
|
|
||||||
|
const events: AgentEvent[] = [];
|
||||||
|
for await (const event of stream) {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// With sequential execution, second tool should NOT start before first finishes
|
||||||
|
expect(parallelObserved).toBe(false);
|
||||||
|
|
||||||
|
const toolResultIds = events.flatMap((event) => {
|
||||||
|
if (event.type !== "message_end" || event.message.role !== "toolResult") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [event.message.toolCallId];
|
||||||
|
});
|
||||||
|
expect(toolResultIds).toEqual(["tool-1", "tool-2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should force sequential execution when one of multiple tools has executionMode=sequential", async () => {
|
||||||
|
const toolSchema = Type.Object({ value: Type.String() });
|
||||||
|
const executionOrder: string[] = [];
|
||||||
|
let releaseSlow: (() => void) | undefined;
|
||||||
|
const slowDone = new Promise<void>((resolve) => {
|
||||||
|
releaseSlow = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
const slowTool: AgentTool<typeof toolSchema, { value: string }> = {
|
||||||
|
name: "slow",
|
||||||
|
label: "Slow",
|
||||||
|
description: "Slow tool",
|
||||||
|
parameters: toolSchema,
|
||||||
|
executionMode: "sequential",
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
executionOrder.push(`slow:${params.value}`);
|
||||||
|
if (params.value === "a") {
|
||||||
|
await slowDone;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `slow: ${params.value}` }],
|
||||||
|
details: { value: params.value },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fastTool: AgentTool<typeof toolSchema, { value: string }> = {
|
||||||
|
name: "fast",
|
||||||
|
label: "Fast",
|
||||||
|
description: "Fast tool",
|
||||||
|
parameters: toolSchema,
|
||||||
|
// no executionMode = defaults to parallel
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
executionOrder.push(`fast:${params.value}`);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `fast: ${params.value}` }],
|
||||||
|
details: { value: params.value },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const context: AgentContext = {
|
||||||
|
systemPrompt: "",
|
||||||
|
messages: [],
|
||||||
|
tools: [slowTool, fastTool],
|
||||||
|
};
|
||||||
|
|
||||||
|
const userPrompt: AgentMessage = createUserMessage("run both");
|
||||||
|
const config: AgentLoopConfig = {
|
||||||
|
model: createModel(),
|
||||||
|
convertToLlm: identityConverter,
|
||||||
|
// parallel by default, but slowTool forces sequential
|
||||||
|
};
|
||||||
|
|
||||||
|
let callIndex = 0;
|
||||||
|
const stream = agentLoop([userPrompt], context, config, undefined, () => {
|
||||||
|
const mockStream = new MockAssistantStream();
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (callIndex === 0) {
|
||||||
|
const message = createAssistantMessage(
|
||||||
|
[
|
||||||
|
{ type: "toolCall", id: "tool-1", name: "slow", arguments: { value: "a" } },
|
||||||
|
{ type: "toolCall", id: "tool-2", name: "fast", arguments: { value: "b" } },
|
||||||
|
],
|
||||||
|
"toolUse",
|
||||||
|
);
|
||||||
|
mockStream.push({ type: "done", reason: "toolUse", message });
|
||||||
|
setTimeout(() => releaseSlow?.(), 20);
|
||||||
|
} else {
|
||||||
|
const message = createAssistantMessage([{ type: "text", text: "done" }]);
|
||||||
|
mockStream.push({ type: "done", reason: "stop", message });
|
||||||
|
}
|
||||||
|
callIndex++;
|
||||||
|
});
|
||||||
|
return mockStream;
|
||||||
|
});
|
||||||
|
|
||||||
|
const events: AgentEvent[] = [];
|
||||||
|
for await (const event of stream) {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast tool should NOT run before slow tool finishes
|
||||||
|
expect(executionOrder[0]).toBe("slow:a");
|
||||||
|
expect(executionOrder).toContain("fast:b");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow parallel execution when all tools have executionMode=parallel", async () => {
|
||||||
|
const toolSchema = Type.Object({ value: Type.String() });
|
||||||
|
let firstResolved = false;
|
||||||
|
let parallelObserved = false;
|
||||||
|
let releaseFirst: (() => void) | undefined;
|
||||||
|
const firstDone = new Promise<void>((resolve) => {
|
||||||
|
releaseFirst = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
const tool: AgentTool<typeof toolSchema, { value: string }> = {
|
||||||
|
name: "echo",
|
||||||
|
label: "Echo",
|
||||||
|
description: "Echo tool",
|
||||||
|
parameters: toolSchema,
|
||||||
|
executionMode: "parallel",
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
if (params.value === "first") {
|
||||||
|
await firstDone;
|
||||||
|
firstResolved = true;
|
||||||
|
}
|
||||||
|
if (params.value === "second" && !firstResolved) {
|
||||||
|
parallelObserved = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `echoed: ${params.value}` }],
|
||||||
|
details: { value: params.value },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const context: AgentContext = {
|
||||||
|
systemPrompt: "",
|
||||||
|
messages: [],
|
||||||
|
tools: [tool],
|
||||||
|
};
|
||||||
|
|
||||||
|
const userPrompt: AgentMessage = createUserMessage("echo both");
|
||||||
|
const config: AgentLoopConfig = {
|
||||||
|
model: createModel(),
|
||||||
|
convertToLlm: identityConverter,
|
||||||
|
};
|
||||||
|
|
||||||
|
let callIndex = 0;
|
||||||
|
const stream = agentLoop([userPrompt], context, config, undefined, () => {
|
||||||
|
const mockStream = new MockAssistantStream();
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (callIndex === 0) {
|
||||||
|
const message = createAssistantMessage(
|
||||||
|
[
|
||||||
|
{ type: "toolCall", id: "tool-1", name: "echo", arguments: { value: "first" } },
|
||||||
|
{ type: "toolCall", id: "tool-2", name: "echo", arguments: { value: "second" } },
|
||||||
|
],
|
||||||
|
"toolUse",
|
||||||
|
);
|
||||||
|
mockStream.push({ type: "done", reason: "toolUse", message });
|
||||||
|
setTimeout(() => releaseFirst?.(), 20);
|
||||||
|
} else {
|
||||||
|
const message = createAssistantMessage([{ type: "text", text: "done" }]);
|
||||||
|
mockStream.push({ type: "done", reason: "stop", message });
|
||||||
|
}
|
||||||
|
callIndex++;
|
||||||
|
});
|
||||||
|
return mockStream;
|
||||||
|
});
|
||||||
|
|
||||||
|
const events: AgentEvent[] = [];
|
||||||
|
for await (const event of stream) {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// With executionMode=parallel, second tool should start before first finishes
|
||||||
|
expect(parallelObserved).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("agentLoopContinue with AgentMessage", () => {
|
describe("agentLoopContinue with AgentMessage", () => {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|||||||
| `hidden-thinking-label.ts` | Customizes the collapsed thinking label via `ctx.ui.setHiddenThinkingLabel()` |
|
| `hidden-thinking-label.ts` | Customizes the collapsed thinking label via `ctx.ui.setHiddenThinkingLabel()` |
|
||||||
| `model-status.ts` | Shows model changes in status bar via `model_select` hook |
|
| `model-status.ts` | Shows model changes in status bar via `model_select` hook |
|
||||||
| `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
|
| `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
|
||||||
|
| `tic-tac-toe.ts` | Tic-tac-toe vs the agent with `executionMode: "sequential"` tools to prevent race conditions on shared cursor state |
|
||||||
| `send-user-message.ts` | Demonstrates `pi.sendUserMessage()` for sending user messages from extensions |
|
| `send-user-message.ts` | Demonstrates `pi.sendUserMessage()` for sending user messages from extensions |
|
||||||
| `timed-confirm.ts` | Demonstrates AbortSignal for auto-dismissing `ctx.ui.confirm()` and `ctx.ui.select()` dialogs |
|
| `timed-confirm.ts` | Demonstrates AbortSignal for auto-dismissing `ctx.ui.confirm()` and `ctx.ui.select()` dialogs |
|
||||||
| `rpc-demo.ts` | Exercises all RPC-supported extension UI methods; pair with [`examples/rpc-extension-ui.ts`](../rpc-extension-ui.ts) |
|
| `rpc-demo.ts` | Exercises all RPC-supported extension UI methods; pair with [`examples/rpc-extension-ui.ts`](../rpc-extension-ui.ts) |
|
||||||
|
|||||||
1008
packages/coding-agent/examples/extensions/tic-tac-toe.ts
Normal file
1008
packages/coding-agent/examples/extensions/tic-tac-toe.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -134,6 +134,8 @@ export type {
|
|||||||
ToolDefinition,
|
ToolDefinition,
|
||||||
// Events - Tool Execution
|
// Events - Tool Execution
|
||||||
ToolExecutionEndEvent,
|
ToolExecutionEndEvent,
|
||||||
|
// Tool execution mode
|
||||||
|
ToolExecutionMode,
|
||||||
ToolExecutionStartEvent,
|
ToolExecutionStartEvent,
|
||||||
ToolExecutionUpdateEvent,
|
ToolExecutionUpdateEvent,
|
||||||
ToolInfo,
|
ToolInfo,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import type {
|
|||||||
AgentToolResult,
|
AgentToolResult,
|
||||||
AgentToolUpdateCallback,
|
AgentToolUpdateCallback,
|
||||||
ThinkingLevel,
|
ThinkingLevel,
|
||||||
|
ToolExecutionMode,
|
||||||
} from "@mariozechner/pi-agent-core";
|
} from "@mariozechner/pi-agent-core";
|
||||||
import type {
|
import type {
|
||||||
Api,
|
Api,
|
||||||
@@ -74,7 +75,7 @@ import type {
|
|||||||
} from "../tools/index.js";
|
} from "../tools/index.js";
|
||||||
|
|
||||||
export type { ExecOptions, ExecResult } from "../exec.js";
|
export type { ExecOptions, ExecResult } from "../exec.js";
|
||||||
export type { AgentToolResult, AgentToolUpdateCallback };
|
export type { AgentToolResult, AgentToolUpdateCallback, ToolExecutionMode };
|
||||||
export type { AppKeybinding, KeybindingsManager } from "../keybindings.js";
|
export type { AppKeybinding, KeybindingsManager } from "../keybindings.js";
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -385,6 +386,15 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
|||||||
/** Optional compatibility shim to prepare raw tool call arguments before schema validation. Must return an object conforming to TParams. */
|
/** Optional compatibility shim to prepare raw tool call arguments before schema validation. Must return an object conforming to TParams. */
|
||||||
prepareArguments?: (args: unknown) => Static<TParams>;
|
prepareArguments?: (args: unknown) => Static<TParams>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-tool execution mode override.
|
||||||
|
* - "sequential": this tool must execute one at a time with other tool calls.
|
||||||
|
* - "parallel": this tool can execute concurrently with other tool calls.
|
||||||
|
*
|
||||||
|
* If omitted, the default execution mode applies.
|
||||||
|
*/
|
||||||
|
executionMode?: ToolExecutionMode;
|
||||||
|
|
||||||
/** Execute the tool. */
|
/** Execute the tool. */
|
||||||
execute(
|
execute(
|
||||||
toolCallId: string,
|
toolCallId: string,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export function wrapToolDefinition<TDetails = unknown>(
|
|||||||
description: definition.description,
|
description: definition.description,
|
||||||
parameters: definition.parameters,
|
parameters: definition.parameters,
|
||||||
prepareArguments: definition.prepareArguments,
|
prepareArguments: definition.prepareArguments,
|
||||||
|
executionMode: definition.executionMode,
|
||||||
execute: (toolCallId, params, signal, onUpdate) =>
|
execute: (toolCallId, params, signal, onUpdate) =>
|
||||||
definition.execute(toolCallId, params, signal, onUpdate, ctxFactory?.() as ExtensionContext),
|
definition.execute(toolCallId, params, signal, onUpdate, ctxFactory?.() as ExtensionContext),
|
||||||
};
|
};
|
||||||
@@ -38,6 +39,7 @@ export function createToolDefinitionFromAgentTool(tool: AgentTool<any>): ToolDef
|
|||||||
description: tool.description,
|
description: tool.description,
|
||||||
parameters: tool.parameters as any,
|
parameters: tool.parameters as any,
|
||||||
prepareArguments: tool.prepareArguments,
|
prepareArguments: tool.prepareArguments,
|
||||||
|
executionMode: tool.executionMode,
|
||||||
execute: async (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate),
|
execute: async (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ export type {
|
|||||||
ToolCallEvent,
|
ToolCallEvent,
|
||||||
ToolCallEventResult,
|
ToolCallEventResult,
|
||||||
ToolDefinition,
|
ToolDefinition,
|
||||||
|
ToolExecutionMode,
|
||||||
ToolInfo,
|
ToolInfo,
|
||||||
ToolRenderResultOptions,
|
ToolRenderResultOptions,
|
||||||
ToolResultEvent,
|
ToolResultEvent,
|
||||||
|
|||||||
Reference in New Issue
Block a user