File size: 2,521 Bytes
064bfd6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { z } from 'zod/v4'
import type { Tool } from '../../Tool.js'
import {
SYNTHETIC_OUTPUT_TOOL_NAME,
SyntheticOutputTool,
} from '../../tools/SyntheticOutputTool/SyntheticOutputTool.js'
import { substituteArguments } from '../argumentSubstitution.js'
import { lazySchema } from '../lazySchema.js'
import type { SetAppState } from '../messageQueueManager.js'
import { hasSuccessfulToolCall } from '../messages.js'
import { addFunctionHook } from './sessionHooks.js'
/**
* Schema for hook responses (shared by prompt and agent hooks)
*/
export const hookResponseSchema = lazySchema(() =>
z.object({
ok: z.boolean().describe('Whether the condition was met'),
reason: z
.string()
.describe('Reason, if the condition was not met')
.optional(),
}),
)
/**
* Add hook input JSON to prompt, either replacing $ARGUMENTS placeholder or appending.
* Also supports indexed arguments like $ARGUMENTS[0], $ARGUMENTS[1], or shorthand $0, $1, etc.
*/
export function addArgumentsToPrompt(
prompt: string,
jsonInput: string,
): string {
return substituteArguments(prompt, jsonInput)
}
/**
* Create a StructuredOutput tool configured for hook responses.
* Reusable by agent hooks and background verification.
*/
export function createStructuredOutputTool(): Tool {
return {
...SyntheticOutputTool,
inputSchema: hookResponseSchema(),
inputJSONSchema: {
type: 'object',
properties: {
ok: {
type: 'boolean',
description: 'Whether the condition was met',
},
reason: {
type: 'string',
description: 'Reason, if the condition was not met',
},
},
required: ['ok'],
additionalProperties: false,
},
async prompt(): Promise<string> {
return `Use this tool to return your verification result. You MUST call this tool exactly once at the end of your response.`
},
}
}
/**
* Register a function hook that enforces structured output via SyntheticOutputTool.
* Used by ask.tsx, execAgentHook.ts, and background verification.
*/
export function registerStructuredOutputEnforcement(
setAppState: SetAppState,
sessionId: string,
): void {
addFunctionHook(
setAppState,
sessionId,
'Stop',
'', // No matcher - applies to all stops
messages => hasSuccessfulToolCall(messages, SYNTHETIC_OUTPUT_TOOL_NAME),
`You MUST call the ${SYNTHETIC_OUTPUT_TOOL_NAME} tool to complete this request. Call this tool now.`,
{ timeout: 5000 },
)
}
|