소스 검색

fix: resolve 400 error with native tools on OpenRouter (#9238)

Daniel 1 개월 전
부모
커밋
237c324fcd

+ 1 - 1
src/core/assistant-message/NativeToolCallParser.ts

@@ -81,7 +81,7 @@ export class NativeToolCallParser {
 			switch (toolCall.name) {
 				case "read_file":
 					if (args.files && Array.isArray(args.files)) {
-						nativeArgs = args.files as NativeArgsFor<TName>
+						nativeArgs = { files: args.files } as NativeArgsFor<TName>
 					}
 					break
 

+ 2 - 2
src/core/assistant-message/presentAssistantMessage.ts

@@ -179,8 +179,8 @@ export async function presentAssistantMessage(cline: Task) {
 							return getSimpleReadFileToolDescription(block.name, block.params)
 						} else {
 							// Prefer native typed args when available; fall back to legacy params
-							// Check if nativeArgs exists and is an array (native protocol)
-							if (Array.isArray(block.nativeArgs)) {
+							// Check if nativeArgs exists (native protocol)
+							if (block.nativeArgs) {
 								return readFileTool.getReadFileToolDescription(block.name, block.nativeArgs)
 							}
 							return readFileTool.getReadFileToolDescription(block.name, block.params)

+ 4 - 1
src/core/task/Task.ts

@@ -2451,11 +2451,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
 						// Get the tool call ID that was stored during parsing
 						const toolCallId = (toolUse as any).id
 						if (toolCallId) {
+							// nativeArgs is already in the correct API format for all tools
+							const input = toolUse.nativeArgs || toolUse.params
+
 							assistantContent.push({
 								type: "tool_use" as const,
 								id: toolCallId,
 								name: toolUse.name,
-								input: toolUse.nativeArgs || toolUse.params,
+								input,
 							})
 						}
 					}

+ 10 - 9
src/core/tools/ReadFileTool.ts

@@ -43,7 +43,7 @@ interface FileResult {
 export class ReadFileTool extends BaseTool<"read_file"> {
 	readonly name = "read_file" as const
 
-	parseLegacy(params: Partial<Record<string, string>>): FileEntry[] {
+	parseLegacy(params: Partial<Record<string, string>>): { files: FileEntry[] } {
 		const argsXmlTag = params.args
 		const legacyPath = params.path
 		const legacyStartLineStr = params.start_line
@@ -79,7 +79,7 @@ export class ReadFileTool extends BaseTool<"read_file"> {
 				fileEntries.push(fileEntry)
 			}
 
-			return fileEntries
+			return { files: fileEntries }
 		}
 
 		// Legacy single file path
@@ -99,13 +99,14 @@ export class ReadFileTool extends BaseTool<"read_file"> {
 			fileEntries.push(fileEntry)
 		}
 
-		return fileEntries
+		return { files: fileEntries }
 	}
 
-	async execute(fileEntries: FileEntry[], task: Task, callbacks: ToolCallbacks): Promise<void> {
+	async execute(params: { files: FileEntry[] }, task: Task, callbacks: ToolCallbacks): Promise<void> {
 		const { handleError, pushToolResult } = callbacks
+		const fileEntries = params.files
 
-		if (fileEntries.length === 0) {
+		if (!fileEntries || fileEntries.length === 0) {
 			task.consecutiveMistakeCount++
 			task.recordToolError("read_file")
 			const errorMsg = await task.sayAndCreateMissingParamError("read_file", "args (containing valid file paths)")
@@ -578,11 +579,11 @@ export class ReadFileTool extends BaseTool<"read_file"> {
 	}
 
 	getReadFileToolDescription(blockName: string, blockParams: any): string
-	getReadFileToolDescription(blockName: string, nativeArgs: FileEntry[]): string
+	getReadFileToolDescription(blockName: string, nativeArgs: { files: FileEntry[] }): string
 	getReadFileToolDescription(blockName: string, second: any): string {
-		// If native typed args (FileEntry[]) were provided
-		if (Array.isArray(second)) {
-			const paths = (second as FileEntry[]).map((f) => f?.path).filter(Boolean) as string[]
+		// If native typed args ({ files: FileEntry[] }) were provided
+		if (second && typeof second === "object" && "files" in second && Array.isArray(second.files)) {
+			const paths = (second.files as FileEntry[]).map((f) => f?.path).filter(Boolean) as string[]
 			if (paths.length === 0) {
 				return `[${blockName} with no valid paths]`
 			} else if (paths.length === 1) {

+ 1 - 1
src/shared/tools.ts

@@ -82,7 +82,7 @@ export type ToolProtocol = "xml" | "native"
  * Tools not listed here will fall back to `any` for backward compatibility.
  */
 export type NativeToolArgs = {
-	read_file: FileEntry[]
+	read_file: { files: FileEntry[] }
 	attempt_completion: { result: string }
 	execute_command: { command: string; cwd?: string }
 	insert_content: { path: string; line: number; content: string }