mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	Claude: Streamed tool calls parser
This commit is contained in:
		| @@ -136,6 +136,8 @@ export class ToolManager { | |||||||
|      */ |      */ | ||||||
|     static #tools = new Map(); |     static #tools = new Map(); | ||||||
|  |  | ||||||
|  |     static #INPUT_DELTA_KEY = '__input_json_delta'; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns an Array of all tools that have been registered. |      * Returns an Array of all tools that have been registered. | ||||||
|      * @type {ToolDefinition[]} |      * @type {ToolDefinition[]} | ||||||
| @@ -304,20 +306,48 @@ export class ToolManager { | |||||||
|         } |         } | ||||||
|         if (typeof parsed?.content_block === 'object') { |         if (typeof parsed?.content_block === 'object') { | ||||||
|             const choiceIndex = 0; |             const choiceIndex = 0; | ||||||
|  |             const toolCallIndex = parsed?.index ?? 0; | ||||||
|  |  | ||||||
|             if (parsed?.content_block?.type === 'tool_use') { |             if (parsed?.content_block?.type === 'tool_use') { | ||||||
|                 if (!Array.isArray(toolCalls[choiceIndex])) { |                 if (!Array.isArray(toolCalls[choiceIndex])) { | ||||||
|                     toolCalls[choiceIndex] = []; |                     toolCalls[choiceIndex] = []; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 const toolCallIndex = toolCalls[choiceIndex].length; |  | ||||||
|  |  | ||||||
|                 if (toolCalls[choiceIndex][toolCallIndex] === undefined) { |                 if (toolCalls[choiceIndex][toolCallIndex] === undefined) { | ||||||
|                     toolCalls[choiceIndex][toolCallIndex] = {}; |                     toolCalls[choiceIndex][toolCallIndex] = {}; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 const targetToolCall = toolCalls[choiceIndex][toolCallIndex]; |                 const targetToolCall = toolCalls[choiceIndex][toolCallIndex]; | ||||||
|                 Object.assign(targetToolCall, parsed.content_block); |                 ToolManager.#applyToolCallDelta(targetToolCall, parsed.content_block); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (typeof parsed?.delta === 'object') { | ||||||
|  |             const choiceIndex = 0; | ||||||
|  |             const toolCallIndex = parsed?.index ?? 0; | ||||||
|  |             const targetToolCall = toolCalls[choiceIndex]?.[toolCallIndex]; | ||||||
|  |             if (targetToolCall){ | ||||||
|  |                 if (parsed?.delta?.type === 'input_json_delta') { | ||||||
|  |                     const jsonDelta = parsed?.delta?.partial_json; | ||||||
|  |                     if (!targetToolCall[this.#INPUT_DELTA_KEY]) { | ||||||
|  |                         targetToolCall[this.#INPUT_DELTA_KEY] = ''; | ||||||
|  |                     } | ||||||
|  |                     targetToolCall[this.#INPUT_DELTA_KEY] += jsonDelta; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (parsed?.type === 'content_block_stop') { | ||||||
|  |             const choiceIndex = 0; | ||||||
|  |             const toolCallIndex = parsed?.index ?? 0; | ||||||
|  |             const targetToolCall = toolCalls[choiceIndex]?.[toolCallIndex]; | ||||||
|  |             if (targetToolCall) { | ||||||
|  |                 const jsonDeltaString = targetToolCall[this.#INPUT_DELTA_KEY]; | ||||||
|  |                 if (jsonDeltaString) { | ||||||
|  |                     try { | ||||||
|  |                         const jsonDelta = { input: JSON.parse(jsonDeltaString) }; | ||||||
|  |                         delete targetToolCall[this.#INPUT_DELTA_KEY]; | ||||||
|  |                         ToolManager.#applyToolCallDelta(targetToolCall, jsonDelta); | ||||||
|  |                     } catch (error) { | ||||||
|  |                         console.warn('Failed to apply input JSON delta:', error); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -397,9 +427,12 @@ export class ToolManager { | |||||||
|      * @returns {any[]} Tool calls from the response data |      * @returns {any[]} Tool calls from the response data | ||||||
|      */ |      */ | ||||||
|     static #getToolCallsFromData(data) { |     static #getToolCallsFromData(data) { | ||||||
|  |         const isClaudeToolCall = c => Array.isArray(c) ? c.filter(x => x).every(isClaudeToolCall) : c?.input && c?.name && c?.id; | ||||||
|  |         const convertClaudeToolCall = c => ({ id: c.id, function: { name: c.name, arguments: c.input } }); | ||||||
|  |  | ||||||
|         // Parsed tool calls from streaming data |         // Parsed tool calls from streaming data | ||||||
|         if (Array.isArray(data) && data.length > 0) { |         if (Array.isArray(data) && data.length > 0 && Array.isArray(data[0])) { | ||||||
|             return data[0]; |             return isClaudeToolCall(data[0]) ? data[0].filter(x => x).map(convertClaudeToolCall) : data[0]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Parsed tool calls from non-streaming data |         // Parsed tool calls from non-streaming data | ||||||
| @@ -412,19 +445,13 @@ export class ToolManager { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // Claude tool calls to OpenAI tool calls | ||||||
|         if (Array.isArray(data?.content)) { |         if (Array.isArray(data?.content)) { | ||||||
|             // Claude tool calls to OpenAI tool calls |             const content = data.content.filter(c => c.type === 'tool_use').map(convertClaudeToolCall); | ||||||
|             const content = data.content.filter(c => c.type === 'tool_use').map(c => { |  | ||||||
|                 return { |  | ||||||
|                     id: c.id, |  | ||||||
|                     function: { |  | ||||||
|                         name: c.name, |  | ||||||
|                         arguments: c.input, |  | ||||||
|                     }, |  | ||||||
|                 }; |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             return content; |             if (content) { | ||||||
|  |                 return content; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user