Implement support for tool input modification (#15492)

This commit is contained in:
Christian Gunderman
2025-12-30 11:37:43 -08:00
committed by GitHub
parent 15c9f88da6
commit 90eb1e0281
12 changed files with 413 additions and 2 deletions
@@ -158,6 +158,14 @@ export class HookAggregator {
merged.suppressOutput = true;
}
// Merge hookSpecificOutput
if (output.hookSpecificOutput) {
merged.hookSpecificOutput = {
...(merged.hookSpecificOutput || {}),
...output.hookSpecificOutput,
};
}
// Collect additional context from hook-specific outputs
this.extractAdditionalContext(output, additionalContexts);
}
+15
View File
@@ -15,6 +15,7 @@ import type {
BeforeAgentInput,
BeforeModelInput,
BeforeModelOutput,
BeforeToolInput,
} from './types.js';
import type { LLMRequest } from './hookTranslator.js';
import { debugLogger } from '../utils/debugLogger.js';
@@ -190,6 +191,20 @@ export class HookRunner {
}
break;
case HookEventName.BeforeTool:
if ('tool_input' in hookOutput.hookSpecificOutput) {
const newToolInput = hookOutput.hookSpecificOutput[
'tool_input'
] as Record<string, unknown>;
if (newToolInput && 'tool_input' in modifiedInput) {
(modifiedInput as BeforeToolInput).tool_input = {
...(modifiedInput as BeforeToolInput).tool_input,
...newToolInput,
};
}
}
break;
default:
// For other events, no special input modification is needed
break;
+6
View File
@@ -13,6 +13,7 @@ import {
AfterModelHookOutput,
HookEventName,
HookType,
BeforeToolHookOutput,
} from './types.js';
import { defaultHookTranslator } from './hookTranslator.js';
import type {
@@ -92,6 +93,11 @@ describe('Hook Output Classes', () => {
const output = createHookOutput(HookEventName.BeforeToolSelection, {});
expect(output).toBeInstanceOf(BeforeToolSelectionHookOutput);
});
it('should return BeforeToolHookOutput for BeforeTool event', () => {
const output = createHookOutput(HookEventName.BeforeTool, {});
expect(output).toBeInstanceOf(BeforeToolHookOutput);
});
});
describe('DefaultHookOutput', () => {
+21 -1
View File
@@ -133,6 +133,8 @@ export function createHookOutput(
return new AfterModelHookOutput(data);
case 'BeforeToolSelection':
return new BeforeToolSelectionHookOutput(data);
case 'BeforeTool':
return new BeforeToolHookOutput(data);
default:
return new DefaultHookOutput(data);
}
@@ -236,7 +238,24 @@ export class DefaultHookOutput implements HookOutput {
/**
* Specific hook output class for BeforeTool events.
*/
export class BeforeToolHookOutput extends DefaultHookOutput {}
export class BeforeToolHookOutput extends DefaultHookOutput {
/**
* Get modified tool input if provided by hook
*/
getModifiedToolInput(): Record<string, unknown> | undefined {
if (this.hookSpecificOutput && 'tool_input' in this.hookSpecificOutput) {
const input = this.hookSpecificOutput['tool_input'];
if (
typeof input === 'object' &&
input !== null &&
!Array.isArray(input)
) {
return input as Record<string, unknown>;
}
}
return undefined;
}
}
/**
* Specific hook output class for BeforeModel events
@@ -368,6 +387,7 @@ export interface BeforeToolInput extends HookInput {
export interface BeforeToolOutput extends HookOutput {
hookSpecificOutput?: {
hookEventName: 'BeforeTool';
tool_input?: Record<string, unknown>;
};
}