mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
fix: update Kimi tool call marker detection to handle both delimiter formats
This commit is contained in:
parent
464a7b5600
commit
582c639640
2 changed files with 56 additions and 9 deletions
|
|
@ -7,11 +7,16 @@ import {
|
|||
|
||||
describe("kimi-tool-call-extractor", () => {
|
||||
describe("hasKimiEmbeddedToolCalls", () => {
|
||||
it("should return true when content contains tool call markers", () => {
|
||||
it("should return true when content contains tool call markers with delimiters", () => {
|
||||
const content = "Some reasoning <|tool_calls_section_begin|> stuff <|tool_calls_section_end|>"
|
||||
expect(hasKimiEmbeddedToolCalls(content)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when content contains tool call markers without delimiters", () => {
|
||||
const content = "Some reasoning tool_calls_section_begin stuff tool_calls_section_end"
|
||||
expect(hasKimiEmbeddedToolCalls(content)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when content does not contain tool call markers", () => {
|
||||
const content = "Just regular reasoning content without any tool calls"
|
||||
expect(hasKimiEmbeddedToolCalls(content)).toBe(false)
|
||||
|
|
@ -23,7 +28,7 @@ describe("kimi-tool-call-extractor", () => {
|
|||
})
|
||||
|
||||
describe("extractKimiToolCalls", () => {
|
||||
it("should extract single tool call from reasoning content", () => {
|
||||
it("should extract single tool call from reasoning content with delimiters", () => {
|
||||
const content = `Some reasoning here
|
||||
<|tool_calls_section_begin|>
|
||||
<|tool_call_begin|>functions.read_file:0<|tool_call_argument_begin|>{"files":[{"path":"test.txt"}]}<|tool_call_end|>
|
||||
|
|
@ -41,7 +46,30 @@ More content after`
|
|||
arguments: '{"files":[{"path":"test.txt"}]}',
|
||||
},
|
||||
})
|
||||
expect(result.cleanedReasoningContent).not.toContain("<|tool_calls_section_begin|>")
|
||||
expect(result.cleanedReasoningContent).not.toContain("tool_calls_section_begin")
|
||||
expect(result.cleanedReasoningContent).toContain("Some reasoning here")
|
||||
expect(result.cleanedReasoningContent).toContain("More content after")
|
||||
})
|
||||
|
||||
it("should extract single tool call from reasoning content without delimiters", () => {
|
||||
const content = `Some reasoning here
|
||||
tool_calls_section_begin
|
||||
tool_call_begin functions.read_file:0 tool_call_argument_begin {"files":[{"path":"test.txt"}]} tool_call_end
|
||||
tool_calls_section_end
|
||||
More content after`
|
||||
|
||||
const result = extractKimiToolCalls(content)
|
||||
|
||||
expect(result.toolCalls).toHaveLength(1)
|
||||
expect(result.toolCalls[0]).toEqual({
|
||||
id: "kimi-functions.read_file:0",
|
||||
type: "function",
|
||||
function: {
|
||||
name: "read_file",
|
||||
arguments: '{"files":[{"path":"test.txt"}]}',
|
||||
},
|
||||
})
|
||||
expect(result.cleanedReasoningContent).not.toContain("tool_calls_section_begin")
|
||||
expect(result.cleanedReasoningContent).toContain("Some reasoning here")
|
||||
expect(result.cleanedReasoningContent).toContain("More content after")
|
||||
})
|
||||
|
|
@ -110,9 +138,9 @@ More content after`
|
|||
const result = extractKimiToolCalls(content)
|
||||
|
||||
// The cleaned content should not contain tool call markers
|
||||
expect(result.cleanedReasoningContent).not.toContain("<|tool_calls_section_begin|>")
|
||||
expect(result.cleanedReasoningContent).not.toContain("<|tool_calls_section_end|>")
|
||||
expect(result.cleanedReasoningContent).not.toContain("<|tool_call_begin|>")
|
||||
expect(result.cleanedReasoningContent).not.toContain("tool_calls_section_begin")
|
||||
expect(result.cleanedReasoningContent).not.toContain("tool_calls_section_end")
|
||||
expect(result.cleanedReasoningContent).not.toContain("tool_call_begin")
|
||||
expect(result.cleanedReasoningContent).toContain("Before tool calls")
|
||||
expect(result.cleanedReasoningContent).toContain("After tool calls")
|
||||
})
|
||||
|
|
@ -147,6 +175,18 @@ End reasoning`
|
|||
expect(result.toolCalls[0].function.name).toBe("tool1")
|
||||
expect(result.toolCalls[1].function.name).toBe("tool2")
|
||||
})
|
||||
|
||||
it("should handle markers without delimiters", () => {
|
||||
const content = `Some reasoning
|
||||
tool_calls_section_begin
|
||||
tool_call_begin functions.read_file:0 tool_call_argument_begin {"path":"test.txt"} tool_call_end
|
||||
tool_calls_section_end`
|
||||
|
||||
const result = extractKimiToolCalls(content)
|
||||
|
||||
expect(result.toolCalls).toHaveLength(1)
|
||||
expect(result.toolCalls[0].function.name).toBe("read_file")
|
||||
})
|
||||
})
|
||||
|
||||
describe("isKimiThinkingModel", () => {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
* - <|tool_call_begin|> ... <|tool_call_end|> wraps each individual tool call
|
||||
* - <|tool_call_argument_begin|> marks the start of arguments JSON
|
||||
*
|
||||
* Note: The model may output these markers with or without the <| |> delimiters,
|
||||
* so patterns are designed to handle both formats.
|
||||
*
|
||||
* Format example:
|
||||
* <|tool_calls_section_begin|>
|
||||
* <|tool_call_begin|>functions.read_file:0<|tool_call_argument_begin|>{"files":[{"path":"test.txt"}]}<|tool_call_end|>
|
||||
|
|
@ -36,9 +39,11 @@ export interface KimiToolCallExtractionResult {
|
|||
|
||||
/**
|
||||
* Checks if the content contains Kimi K2 Thinking model's embedded tool call markers.
|
||||
* Note: The model may output markers with or without <| |> delimiters, so we check
|
||||
* for the core marker text only.
|
||||
*/
|
||||
export function hasKimiEmbeddedToolCalls(content: string): boolean {
|
||||
return content.includes("<|tool_calls_section_begin|>")
|
||||
return content.includes("tool_calls_section_begin")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -58,7 +63,8 @@ export function extractKimiToolCalls(content: string): KimiToolCallExtractionRes
|
|||
const toolCalls: KimiToolCall[] = []
|
||||
|
||||
// Pattern to match tool call sections
|
||||
const sectionPattern = /<\|tool_calls_section_begin\|>(.*?)<\|tool_calls_section_end\|>/gs
|
||||
// Note: Handles both <|marker|> and marker formats (delimiters are optional)
|
||||
const sectionPattern = /(?:<\|)?tool_calls_section_begin(?:\|>)?(.*?)(?:<\|)?tool_calls_section_end(?:\|>)?/gs
|
||||
const toolCallSections = content.match(sectionPattern)
|
||||
|
||||
if (!toolCallSections || toolCallSections.length === 0) {
|
||||
|
|
@ -70,8 +76,9 @@ export function extractKimiToolCalls(content: string): KimiToolCallExtractionRes
|
|||
|
||||
// Pattern to extract individual tool calls
|
||||
// Format: <|tool_call_begin|>functions.tool_name:index<|tool_call_argument_begin|>JSON_ARGS<|tool_call_end|>
|
||||
// Note: Handles both <|marker|> and marker formats (delimiters are optional)
|
||||
const funcCallPattern =
|
||||
/<\|tool_call_begin\|>\s*([\w.]+:\d+)\s*<\|tool_call_argument_begin\|>\s*(.*?)\s*<\|tool_call_end\|>/gs
|
||||
/(?:<\|)?tool_call_begin(?:\|>)?\s*([\w.]+:\d+)\s*(?:<\|)?tool_call_argument_begin(?:\|>)?\s*(.*?)\s*(?:<\|)?tool_call_end(?:\|>)?/gs
|
||||
|
||||
for (const section of toolCallSections) {
|
||||
let match
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue