84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
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 },
|
|
)
|
|
}
|