( sendEvent: (event: ChatStreamEvent) => void, resolvers: Map<string, (answer: string) => void> )
| 30 | const ASK_USER_TIMEOUT_MS = 5 * 60 * 1000; |
| 31 | |
| 32 | export function createAskUserTool( |
| 33 | sendEvent: (event: ChatStreamEvent) => void, |
| 34 | resolvers: Map<string, (answer: string) => void> |
| 35 | ): { definition: ToolDefinition; executor: ToolExecutor } { |
| 36 | let askCounter = 0; |
| 37 | |
| 38 | const executor: ToolExecutor = { |
| 39 | execute: async (args: Record<string, unknown>) => { |
| 40 | const question = requireString(args, "question"); |
| 41 | |
| 42 | const options = args.options as string[] | undefined; |
| 43 | const multiple = args.multiple as boolean | undefined; |
| 44 | |
| 45 | const askId = `ask_${Date.now()}_${++askCounter}`; |
| 46 | |
| 47 | // 通知 UI 显示提问 |
| 48 | sendEvent({ type: "ask_user", id: askId, question, options, multiple }); |
| 49 | |
| 50 | // 等待用户回复 |
| 51 | return new Promise<string>((resolve) => { |
| 52 | const timer = setTimeout(() => { |
| 53 | resolvers.delete(askId); |
| 54 | resolve(JSON.stringify({ answer: null, reason: "timeout" })); |
| 55 | }, ASK_USER_TIMEOUT_MS); |
| 56 | |
| 57 | resolvers.set(askId, (answer: string) => { |
| 58 | clearTimeout(timer); |
| 59 | resolvers.delete(askId); |
| 60 | resolve(JSON.stringify({ answer })); |
| 61 | }); |
| 62 | }); |
| 63 | }, |
| 64 | }; |
| 65 | |
| 66 | return { definition: ASK_USER_DEFINITION, executor }; |
| 67 | } |
no test coverage detected