feat(llm): improve model-specific patches
This commit is contained in:
@@ -3,13 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import { InvokeError, InvokeErrorType } from './errors'
|
import { InvokeError, InvokeErrorType } from './errors'
|
||||||
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
|
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
|
||||||
import { zodToOpenAITool } from './utils'
|
import { modelPatch, zodToOpenAITool } from './utils'
|
||||||
|
|
||||||
// Claude's openAI-API has different format for some fields
|
|
||||||
const CLAUDE_PATCH = {
|
|
||||||
tool_choice: { type: 'tool', name: 'AgentOutput' },
|
|
||||||
thinking: { type: 'disabled' },
|
|
||||||
}
|
|
||||||
|
|
||||||
export class OpenAIClient implements LLMClient {
|
export class OpenAIClient implements LLMClient {
|
||||||
config: OpenAIClientConfig
|
config: OpenAIClientConfig
|
||||||
@@ -26,9 +20,10 @@ export class OpenAIClient implements LLMClient {
|
|||||||
// 1. Convert tools to OpenAI format
|
// 1. Convert tools to OpenAI format
|
||||||
const openaiTools = Object.entries(tools).map(([name, tool]) => zodToOpenAITool(name, tool))
|
const openaiTools = Object.entries(tools).map(([name, tool]) => zodToOpenAITool(name, tool))
|
||||||
|
|
||||||
// 2. Detect if Claude (auto-compatibility)
|
// 2. Detect patch (auto-compatibility)
|
||||||
// TODO: Gemini also uses slightly different format than OpenAI
|
// TODO: Gemini also uses slightly different format than OpenAI
|
||||||
const isClaude = this.config.model.toLowerCase().startsWith('claude')
|
const isClaude = this.config.model.toLowerCase().startsWith('claude')
|
||||||
|
const isGrok = this.config.model.toLowerCase().startsWith('grok')
|
||||||
|
|
||||||
// 3. Call API
|
// 3. Call API
|
||||||
let response: Response
|
let response: Response
|
||||||
@@ -39,7 +34,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Authorization: `Bearer ${this.config.apiKey}`,
|
Authorization: `Bearer ${this.config.apiKey}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(
|
||||||
|
modelPatch({
|
||||||
model: this.config.model,
|
model: this.config.model,
|
||||||
temperature: this.config.temperature,
|
temperature: this.config.temperature,
|
||||||
max_tokens: this.config.maxTokens,
|
max_tokens: this.config.maxTokens,
|
||||||
@@ -54,9 +50,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
// reasoning_effort: 'minimal',
|
// reasoning_effort: 'minimal',
|
||||||
// verbosity: 'low',
|
// verbosity: 'low',
|
||||||
parallel_tool_calls: false,
|
parallel_tool_calls: false,
|
||||||
|
})
|
||||||
...(isClaude ? CLAUDE_PATCH : {}),
|
),
|
||||||
}),
|
|
||||||
signal: abortSignal,
|
signal: abortSignal,
|
||||||
})
|
})
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
@@ -5,13 +5,7 @@ import type { MacroToolInput } from '@/PageAgent'
|
|||||||
|
|
||||||
import { InvokeError, InvokeErrorType } from './errors'
|
import { InvokeError, InvokeErrorType } from './errors'
|
||||||
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
|
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
|
||||||
import { lenientParseMacroToolCall, zodToOpenAITool } from './utils'
|
import { lenientParseMacroToolCall, modelPatch, zodToOpenAITool } from './utils'
|
||||||
|
|
||||||
// Claude's openAI-API has different format for some fields
|
|
||||||
const CLAUDE_PATCH = {
|
|
||||||
tool_choice: { type: 'tool', name: 'AgentOutput' },
|
|
||||||
thinking: { type: 'disabled' },
|
|
||||||
}
|
|
||||||
|
|
||||||
export class OpenAIClient implements LLMClient {
|
export class OpenAIClient implements LLMClient {
|
||||||
config: OpenAIClientConfig
|
config: OpenAIClientConfig
|
||||||
@@ -41,7 +35,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Authorization: `Bearer ${this.config.apiKey}`,
|
Authorization: `Bearer ${this.config.apiKey}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(
|
||||||
|
modelPatch({
|
||||||
model: this.config.model,
|
model: this.config.model,
|
||||||
temperature: this.config.temperature,
|
temperature: this.config.temperature,
|
||||||
max_tokens: this.config.maxTokens,
|
max_tokens: this.config.maxTokens,
|
||||||
@@ -56,9 +51,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
// reasoning_effort: 'minimal',
|
// reasoning_effort: 'minimal',
|
||||||
// verbosity: 'low',
|
// verbosity: 'low',
|
||||||
parallel_tool_calls: false,
|
parallel_tool_calls: false,
|
||||||
|
})
|
||||||
...(isClaude ? CLAUDE_PATCH : {}),
|
),
|
||||||
}),
|
|
||||||
signal: abortSignal,
|
signal: abortSignal,
|
||||||
})
|
})
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
@@ -192,3 +192,23 @@ export function lenientParseMacroToolCall(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function modelPatch(body: Record<string, any>) {
|
||||||
|
const model: string = body.model || ''
|
||||||
|
|
||||||
|
if (model.toLowerCase().startsWith('claude')) {
|
||||||
|
body.tool_choice = { type: 'tool', name: 'AgentOutput' }
|
||||||
|
body.thinking = { type: 'disabled' }
|
||||||
|
// body.reasoning = { enabled: 'disabled' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.toLowerCase().includes('grok')) {
|
||||||
|
console.log('Applying Grok patch: removing tool_choice')
|
||||||
|
delete body.tool_choice
|
||||||
|
console.log('Applying Grok patch: disable reasoning and thinking')
|
||||||
|
body.thinking = { type: 'disabled', effort: 'minimal' }
|
||||||
|
body.reasoning = { enabled: false, effort: 'low' }
|
||||||
|
}
|
||||||
|
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user