返回 oh-my-ppt
tool-error-recovery.ts
根目录 / src / main / thinking / tool-error-recovery.ts
1 import { ToolMessage } from '@langchain/core/messages'
2 import { createMiddleware } from 'langchain'
3
4 const THINKING_WORKFLOW_TOOL_NAMES = new Set([
5 'update_context_document',
6 'update_thinking_document'
7 ])
8
9 function readErrorChain(error: unknown): string {
10 const messages: string[] = []
11 const seen = new Set<object>()
12 let current: unknown = error
13
14 while (current && typeof current === 'object' && !seen.has(current as object)) {
15 seen.add(current as object)
16 const record = current as Record<string, unknown>
17 const name = typeof record.name === 'string' ? record.name : ''
18 const message = typeof record.message === 'string' ? record.message : ''
19 if (name || message) messages.push(`${name}: ${message}`)
20 current = record.cause
21 }
22
23 return messages.join('\n')
24 }
25
26 export function isThinkingToolInputError(error: unknown): boolean {
27 return /ToolInvocationError|ToolInputParsingException|Received tool input did not match expected schema/i.test(
28 readErrorChain(error)
29 )
30 }
31
32 export function createThinkingToolInputRecoveryMiddleware() {
33 const recoveredToolNames = new Set<string>()
34
35 return createMiddleware({
36 name: 'thinkingToolInputRecovery',
37 wrapToolCall: async (request, handler) => {
38 try {
39 return await handler(request)
40 } catch (error) {
41 const toolName = String(request.toolCall?.name || '')
42 if (
43 !THINKING_WORKFLOW_TOOL_NAMES.has(toolName) ||
44 recoveredToolNames.has(toolName) ||
45 !isThinkingToolInputError(error)
46 ) {
47 throw error
48 }
49
50 recoveredToolNames.add(toolName)
51 return new ToolMessage({
52 name: toolName,
53 tool_call_id: String(request.toolCall?.id || ''),
54 status: 'error',
55 content: [
56 error instanceof Error ? error.message : String(error),
57 'Fix the tool arguments so they match the declared schema, then call the same tool again.'
58 ].join('\n\n')
59 })
60 }
61 }
62 })
63 }
64
64 lines TYPESCRIPT