mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: improve Qwen-Code provider tool invocation and configuration
- Add support for tools/functions in API calls to fix tool invocation errors - Add configurable temperature support (default 0.2 for better tool usage) - Use max_completion_tokens instead of deprecated max_tokens parameter - Add proper error handling using handleOpenAIError utility - Extract and parse tool definitions from system prompt to help model understand available tools This addresses the issue where subsequent tasks with the same question fail with tool invocation errors like missing required parameters. Fixes #8052
This commit is contained in:
parent
2263d86a20
commit
c9e52f7477
1 changed files with 97 additions and 5 deletions
|
|
@ -10,6 +10,7 @@ import type { ApiHandlerOptions } from "../../shared/api"
|
|||
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import { handleOpenAIError } from "./utils/openai-error-handler"
|
||||
|
||||
import { BaseProvider } from "./base-provider"
|
||||
import type { SingleCompletionHandler } from "../index"
|
||||
|
|
@ -54,6 +55,7 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan
|
|||
private credentials: QwenOAuthCredentials | null = null
|
||||
private client: OpenAI | undefined
|
||||
private refreshPromise: Promise<QwenOAuthCredentials> | null = null
|
||||
private readonly providerName = "QwenCode"
|
||||
|
||||
constructor(options: QwenCodeHandlerOptions) {
|
||||
super()
|
||||
|
|
@ -213,16 +215,27 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan
|
|||
|
||||
const convertedMessages = [systemMessage, ...convertToOpenAiMessages(messages)]
|
||||
|
||||
// Extract tools from the system prompt if present
|
||||
const tools = this.extractToolsFromSystemPrompt(systemPrompt)
|
||||
|
||||
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
||||
model: model.id,
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? 0.2, // Use a slightly higher default for better tool usage
|
||||
messages: convertedMessages,
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
max_completion_tokens: model.info.maxTokens,
|
||||
// Use max_completion_tokens instead of deprecated max_tokens
|
||||
max_completion_tokens: this.options.modelMaxTokens || model.info.maxTokens,
|
||||
// Add tools if they were found in the system prompt
|
||||
...(tools.length > 0 && { tools }),
|
||||
}
|
||||
|
||||
const stream = await this.callApiWithRetry(() => client.chat.completions.create(requestOptions))
|
||||
let stream
|
||||
try {
|
||||
stream = await this.callApiWithRetry(() => client.chat.completions.create(requestOptions))
|
||||
} catch (error) {
|
||||
throw handleOpenAIError(error, this.providerName)
|
||||
}
|
||||
|
||||
let fullContent = ""
|
||||
|
||||
|
|
@ -290,6 +303,78 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan
|
|||
return { id, info }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract tools from the system prompt if they are defined
|
||||
* This helps the model understand what tools are available
|
||||
*/
|
||||
private extractToolsFromSystemPrompt(systemPrompt: string): OpenAI.Chat.Completions.ChatCompletionTool[] {
|
||||
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = []
|
||||
|
||||
// Look for tool definitions in the system prompt
|
||||
// This is a simple pattern matching approach - could be enhanced
|
||||
const toolPattern = /<tool_name>(.*?)<\/tool_name>.*?<parameters>(.*?)<\/parameters>/gs
|
||||
const matches = systemPrompt.matchAll(toolPattern)
|
||||
|
||||
for (const match of matches) {
|
||||
const toolName = match[1].trim()
|
||||
const parametersText = match[2].trim()
|
||||
|
||||
// Try to parse parameters into a schema
|
||||
try {
|
||||
// Create properties and required arrays with proper types
|
||||
const properties: Record<string, any> = {}
|
||||
const required: string[] = []
|
||||
|
||||
// Create a basic function schema for the tool
|
||||
const tool: OpenAI.Chat.Completions.ChatCompletionTool = {
|
||||
type: "function",
|
||||
function: {
|
||||
name: toolName,
|
||||
description: `Tool: ${toolName}`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: properties,
|
||||
required: required,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Parse parameter definitions if they follow a pattern
|
||||
const paramPattern = /- (\w+):\s*\((\w+)\)\s*(.*)/g
|
||||
const paramMatches = parametersText.matchAll(paramPattern)
|
||||
|
||||
for (const paramMatch of paramMatches) {
|
||||
const paramName = paramMatch[1]
|
||||
const paramType = paramMatch[2].toLowerCase()
|
||||
const isRequired = paramMatch[3].includes("required")
|
||||
|
||||
// Map to JSON schema types
|
||||
let schemaType = "string"
|
||||
if (paramType === "boolean") schemaType = "boolean"
|
||||
else if (paramType === "number" || paramType === "integer") schemaType = "number"
|
||||
else if (paramType === "array") schemaType = "array"
|
||||
else if (paramType === "object") schemaType = "object"
|
||||
|
||||
properties[paramName] = {
|
||||
type: schemaType,
|
||||
description: paramMatch[3],
|
||||
}
|
||||
|
||||
if (isRequired) {
|
||||
required.push(paramName)
|
||||
}
|
||||
}
|
||||
|
||||
tools.push(tool)
|
||||
} catch (error) {
|
||||
// If we can't parse the tool definition, skip it
|
||||
console.debug(`Could not parse tool definition for ${toolName}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
return tools
|
||||
}
|
||||
|
||||
async completePrompt(prompt: string): Promise<string> {
|
||||
await this.ensureAuthenticated()
|
||||
const client = this.ensureClient()
|
||||
|
|
@ -298,10 +383,17 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan
|
|||
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
||||
model: model.id,
|
||||
messages: [{ role: "user", content: prompt }],
|
||||
max_completion_tokens: model.info.maxTokens,
|
||||
// Use max_completion_tokens instead of deprecated max_tokens
|
||||
max_completion_tokens: this.options.modelMaxTokens || model.info.maxTokens,
|
||||
temperature: this.options.modelTemperature ?? 0.2,
|
||||
}
|
||||
|
||||
const response = await this.callApiWithRetry(() => client.chat.completions.create(requestOptions))
|
||||
let response
|
||||
try {
|
||||
response = await this.callApiWithRetry(() => client.chat.completions.create(requestOptions))
|
||||
} catch (error) {
|
||||
throw handleOpenAIError(error, this.providerName)
|
||||
}
|
||||
|
||||
return response.choices[0]?.message.content || ""
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue