fix(coding-agent): chain tool_result extension patches

fixes #1280
This commit is contained in:
Mario Zechner 2026-02-06 11:48:51 +01:00
parent 961d3aacbc
commit 2668326e05
5 changed files with 162 additions and 13 deletions

View file

@ -41,6 +41,7 @@ import type {
SessionBeforeTreeResult,
ToolCallEvent,
ToolCallEventResult,
ToolResultEvent,
ToolResultEventResult,
UserBashEvent,
UserBashEventResult,
@ -98,7 +99,13 @@ interface BeforeAgentStartCombinedResult {
*/
type RunnerEmitEvent = Exclude<
ExtensionEvent,
ToolCallEvent | UserBashEvent | ContextEvent | BeforeAgentStartEvent | ResourcesDiscoverEvent | InputEvent
| ToolCallEvent
| ToolResultEvent
| UserBashEvent
| ContextEvent
| BeforeAgentStartEvent
| ResourcesDiscoverEvent
| InputEvent
>;
export type ExtensionErrorListener = (error: ExtensionError) => void;
@ -484,11 +491,9 @@ export class ExtensionRunner {
);
}
async emit(
event: RunnerEmitEvent,
): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {
async emit(event: RunnerEmitEvent): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | undefined> {
const ctx = this.createContext();
let result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;
let result: SessionBeforeCompactResult | SessionBeforeTreeResult | undefined;
for (const ext of this.extensions) {
const handlers = ext.handlers.get(event.type);
@ -504,10 +509,6 @@ export class ExtensionRunner {
return result;
}
}
if (event.type === "tool_result" && handlerResult) {
result = handlerResult as ToolResultEventResult;
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const stack = err instanceof Error ? err.stack : undefined;
@ -524,6 +525,56 @@ export class ExtensionRunner {
return result;
}
async emitToolResult(event: ToolResultEvent): Promise<ToolResultEventResult | undefined> {
const ctx = this.createContext();
const currentEvent: ToolResultEvent = { ...event };
let modified = false;
for (const ext of this.extensions) {
const handlers = ext.handlers.get("tool_result");
if (!handlers || handlers.length === 0) continue;
for (const handler of handlers) {
try {
const handlerResult = (await handler(currentEvent, ctx)) as ToolResultEventResult | undefined;
if (!handlerResult) continue;
if (handlerResult.content !== undefined) {
currentEvent.content = handlerResult.content;
modified = true;
}
if (handlerResult.details !== undefined) {
currentEvent.details = handlerResult.details;
modified = true;
}
if (handlerResult.isError !== undefined) {
currentEvent.isError = handlerResult.isError;
modified = true;
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const stack = err instanceof Error ? err.stack : undefined;
this.emitError({
extensionPath: ext.path,
event: "tool_result",
error: message,
stack,
});
}
}
}
if (!modified) {
return undefined;
}
return {
content: currentEvent.content,
details: currentEvent.details,
isError: currentEvent.isError,
};
}
async emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {
const ctx = this.createContext();
let result: ToolCallEventResult | undefined;

View file

@ -4,7 +4,7 @@
import type { AgentTool, AgentToolUpdateCallback } from "@mariozechner/pi-agent-core";
import type { ExtensionRunner } from "./runner.js";
import type { RegisteredTool, ToolCallEventResult, ToolResultEventResult } from "./types.js";
import type { RegisteredTool, ToolCallEventResult } from "./types.js";
/**
* Wrap a RegisteredTool into an AgentTool.
@ -72,7 +72,7 @@ export function wrapToolWithExtensions<T>(tool: AgentTool<any, T>, runner: Exten
// Emit tool_result event - extensions can modify the result
if (runner.hasHandlers("tool_result")) {
const resultResult = (await runner.emit({
const resultResult = await runner.emitToolResult({
type: "tool_result",
toolName: tool.name,
toolCallId,
@ -80,7 +80,7 @@ export function wrapToolWithExtensions<T>(tool: AgentTool<any, T>, runner: Exten
content: result.content,
details: result.details,
isError: false,
})) as ToolResultEventResult | undefined;
});
if (resultResult) {
return {
@ -94,7 +94,7 @@ export function wrapToolWithExtensions<T>(tool: AgentTool<any, T>, runner: Exten
} catch (err) {
// Emit tool_result event for errors
if (runner.hasHandlers("tool_result")) {
await runner.emit({
await runner.emitToolResult({
type: "tool_result",
toolName: tool.name,
toolCallId,