mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 04:34:32 +00:00
fix(hooks): propagate run/tool IDs for tool hook correlation (#32360)
* Plugin SDK: add run and tool call fields to tool hooks * Agents: propagate runId and toolCallId in before_tool_call * Agents: thread runId through tool wrapper context * Runner: pass runId into tool hook context * Compaction: pass runId into tool hook context * Agents: scope after_tool_call start data by run * Tests: cover run and tool IDs in before_tool_call hooks * Tests: add run-scoped after_tool_call collision coverage * Hooks: scope adjusted tool params by run * Tests: cover run-scoped adjusted param collisions * Hooks: preserve active tool start metadata until end * Changelog: add tool-hook correlation note
This commit is contained in:
@@ -22,8 +22,17 @@ import { consumeAdjustedParamsForToolCall } from "./pi-tools.before-tool-call.js
|
||||
import { buildToolMutationState, isSameToolMutationAction } from "./tool-mutation.js";
|
||||
import { normalizeToolName } from "./tool-policy.js";
|
||||
|
||||
/** Track tool execution start times and args for after_tool_call hook */
|
||||
const toolStartData = new Map<string, { startTime: number; args: unknown }>();
|
||||
type ToolStartRecord = {
|
||||
startTime: number;
|
||||
args: unknown;
|
||||
};
|
||||
|
||||
/** Track tool execution start data for after_tool_call hook. */
|
||||
const toolStartData = new Map<string, ToolStartRecord>();
|
||||
|
||||
function buildToolStartKey(runId: string, toolCallId: string): string {
|
||||
return `${runId}:${toolCallId}`;
|
||||
}
|
||||
|
||||
function isCronAddAction(args: unknown): boolean {
|
||||
if (!args || typeof args !== "object") {
|
||||
@@ -182,9 +191,10 @@ export async function handleToolExecutionStart(
|
||||
const toolName = normalizeToolName(rawToolName);
|
||||
const toolCallId = String(evt.toolCallId);
|
||||
const args = evt.args;
|
||||
const runId = ctx.params.runId;
|
||||
|
||||
// Track start time and args for after_tool_call hook
|
||||
toolStartData.set(toolCallId, { startTime: Date.now(), args });
|
||||
toolStartData.set(buildToolStartKey(runId, toolCallId), { startTime: Date.now(), args });
|
||||
|
||||
if (toolName === "read") {
|
||||
const record = args && typeof args === "object" ? (args as Record<string, unknown>) : {};
|
||||
@@ -302,12 +312,14 @@ export async function handleToolExecutionEnd(
|
||||
) {
|
||||
const toolName = normalizeToolName(String(evt.toolName));
|
||||
const toolCallId = String(evt.toolCallId);
|
||||
const runId = ctx.params.runId;
|
||||
const isError = Boolean(evt.isError);
|
||||
const result = evt.result;
|
||||
const isToolError = isError || isToolResultError(result);
|
||||
const sanitizedResult = sanitizeToolResult(result);
|
||||
const startData = toolStartData.get(toolCallId);
|
||||
toolStartData.delete(toolCallId);
|
||||
const toolStartKey = buildToolStartKey(runId, toolCallId);
|
||||
const startData = toolStartData.get(toolStartKey);
|
||||
toolStartData.delete(toolStartKey);
|
||||
const callSummary = ctx.state.toolMetaById.get(toolCallId);
|
||||
const meta = callSummary?.meta;
|
||||
ctx.state.toolMetas.push({ toolName, meta });
|
||||
@@ -364,7 +376,7 @@ export async function handleToolExecutionEnd(
|
||||
startData?.args && typeof startData.args === "object"
|
||||
? (startData.args as Record<string, unknown>)
|
||||
: {};
|
||||
const adjustedArgs = consumeAdjustedParamsForToolCall(toolCallId);
|
||||
const adjustedArgs = consumeAdjustedParamsForToolCall(toolCallId, runId);
|
||||
const afterToolCallArgs =
|
||||
adjustedArgs && typeof adjustedArgs === "object"
|
||||
? (adjustedArgs as Record<string, unknown>)
|
||||
@@ -424,6 +436,8 @@ export async function handleToolExecutionEnd(
|
||||
const hookEvent: PluginHookAfterToolCallEvent = {
|
||||
toolName,
|
||||
params: afterToolCallArgs,
|
||||
runId,
|
||||
toolCallId,
|
||||
result: sanitizedResult,
|
||||
error: isToolError ? extractToolErrorMessage(sanitizedResult) : undefined,
|
||||
durationMs,
|
||||
@@ -434,6 +448,8 @@ export async function handleToolExecutionEnd(
|
||||
agentId: ctx.params.agentId,
|
||||
sessionKey: ctx.params.sessionKey,
|
||||
sessionId: ctx.params.sessionId,
|
||||
runId,
|
||||
toolCallId,
|
||||
})
|
||||
.catch((err) => {
|
||||
ctx.log.warn(`after_tool_call hook failed: tool=${toolName} error=${String(err)}`);
|
||||
|
||||
Reference in New Issue
Block a user