mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 07:24: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:
@@ -11,6 +11,7 @@ export type HookContext = {
|
||||
sessionKey?: string;
|
||||
/** Ephemeral session UUID — regenerated on /new and /reset. */
|
||||
sessionId?: string;
|
||||
runId?: string;
|
||||
loopDetection?: ToolLoopDetectionConfig;
|
||||
};
|
||||
|
||||
@@ -23,6 +24,13 @@ const MAX_TRACKED_ADJUSTED_PARAMS = 1024;
|
||||
const LOOP_WARNING_BUCKET_SIZE = 10;
|
||||
const MAX_LOOP_WARNING_KEYS = 256;
|
||||
|
||||
function buildAdjustedParamsKey(params: { runId?: string; toolCallId: string }): string {
|
||||
if (params.runId && params.runId.trim()) {
|
||||
return `${params.runId}:${params.toolCallId}`;
|
||||
}
|
||||
return params.toolCallId;
|
||||
}
|
||||
|
||||
function shouldEmitLoopWarning(state: SessionState, warningKey: string, count: number): boolean {
|
||||
if (!state.toolLoopWarningBuckets) {
|
||||
state.toolLoopWarningBuckets = new Map();
|
||||
@@ -141,17 +149,22 @@ export async function runBeforeToolCallHook(args: {
|
||||
|
||||
try {
|
||||
const normalizedParams = isPlainObject(params) ? params : {};
|
||||
const toolContext = {
|
||||
toolName,
|
||||
...(args.ctx?.agentId ? { agentId: args.ctx.agentId } : {}),
|
||||
...(args.ctx?.sessionKey ? { sessionKey: args.ctx.sessionKey } : {}),
|
||||
...(args.ctx?.sessionId ? { sessionId: args.ctx.sessionId } : {}),
|
||||
...(args.ctx?.runId ? { runId: args.ctx.runId } : {}),
|
||||
...(args.toolCallId ? { toolCallId: args.toolCallId } : {}),
|
||||
};
|
||||
const hookResult = await hookRunner.runBeforeToolCall(
|
||||
{
|
||||
toolName,
|
||||
params: normalizedParams,
|
||||
...(args.ctx?.runId ? { runId: args.ctx.runId } : {}),
|
||||
...(args.toolCallId ? { toolCallId: args.toolCallId } : {}),
|
||||
},
|
||||
{
|
||||
toolName,
|
||||
agentId: args.ctx?.agentId,
|
||||
sessionKey: args.ctx?.sessionKey,
|
||||
sessionId: args.ctx?.sessionId,
|
||||
},
|
||||
toolContext,
|
||||
);
|
||||
|
||||
if (hookResult?.block) {
|
||||
@@ -197,7 +210,8 @@ export function wrapToolWithBeforeToolCallHook(
|
||||
throw new Error(outcome.reason);
|
||||
}
|
||||
if (toolCallId) {
|
||||
adjustedParamsByToolCallId.set(toolCallId, outcome.params);
|
||||
const adjustedParamsKey = buildAdjustedParamsKey({ runId: ctx?.runId, toolCallId });
|
||||
adjustedParamsByToolCallId.set(adjustedParamsKey, outcome.params);
|
||||
if (adjustedParamsByToolCallId.size > MAX_TRACKED_ADJUSTED_PARAMS) {
|
||||
const oldest = adjustedParamsByToolCallId.keys().next().value;
|
||||
if (oldest) {
|
||||
@@ -240,14 +254,16 @@ export function isToolWrappedWithBeforeToolCallHook(tool: AnyAgentTool): boolean
|
||||
return taggedTool[BEFORE_TOOL_CALL_WRAPPED] === true;
|
||||
}
|
||||
|
||||
export function consumeAdjustedParamsForToolCall(toolCallId: string): unknown {
|
||||
const params = adjustedParamsByToolCallId.get(toolCallId);
|
||||
adjustedParamsByToolCallId.delete(toolCallId);
|
||||
export function consumeAdjustedParamsForToolCall(toolCallId: string, runId?: string): unknown {
|
||||
const adjustedParamsKey = buildAdjustedParamsKey({ runId, toolCallId });
|
||||
const params = adjustedParamsByToolCallId.get(adjustedParamsKey);
|
||||
adjustedParamsByToolCallId.delete(adjustedParamsKey);
|
||||
return params;
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
BEFORE_TOOL_CALL_WRAPPED,
|
||||
buildAdjustedParamsKey,
|
||||
adjustedParamsByToolCallId,
|
||||
runBeforeToolCallHook,
|
||||
isPlainObject,
|
||||
|
||||
Reference in New Issue
Block a user