Skip to content

Commit e8bd1ee

Browse files
committed
feat(llm): improve model-specific patches
1 parent 5162056 commit e8bd1ee

3 files changed

Lines changed: 60 additions & 51 deletions

File tree

src/llms/OpenAIClient.ts

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@
33
*/
44
import { InvokeError, InvokeErrorType } from './errors'
55
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
6-
import { zodToOpenAITool } from './utils'
7-
8-
// Claude's openAI-API has different format for some fields
9-
const CLAUDE_PATCH = {
10-
tool_choice: { type: 'tool', name: 'AgentOutput' },
11-
thinking: { type: 'disabled' },
12-
}
6+
import { modelPatch, zodToOpenAITool } from './utils'
137

148
export class OpenAIClient implements LLMClient {
159
config: OpenAIClientConfig
@@ -26,9 +20,10 @@ export class OpenAIClient implements LLMClient {
2620
// 1. Convert tools to OpenAI format
2721
const openaiTools = Object.entries(tools).map(([name, tool]) => zodToOpenAITool(name, tool))
2822

29-
// 2. Detect if Claude (auto-compatibility)
23+
// 2. Detect patch (auto-compatibility)
3024
// TODO: Gemini also uses slightly different format than OpenAI
3125
const isClaude = this.config.model.toLowerCase().startsWith('claude')
26+
const isGrok = this.config.model.toLowerCase().startsWith('grok')
3227

3328
// 3. Call API
3429
let response: Response
@@ -39,24 +34,24 @@ export class OpenAIClient implements LLMClient {
3934
'Content-Type': 'application/json',
4035
Authorization: `Bearer ${this.config.apiKey}`,
4136
},
42-
body: JSON.stringify({
43-
model: this.config.model,
44-
temperature: this.config.temperature,
45-
max_tokens: this.config.maxTokens,
46-
messages,
47-
48-
tools: openaiTools,
49-
// tool_choice: 'required',
50-
tool_choice: { type: 'function', function: { name: 'AgentOutput' } },
51-
52-
// model specific params
53-
54-
// reasoning_effort: 'minimal',
55-
// verbosity: 'low',
56-
parallel_tool_calls: false,
57-
58-
...(isClaude ? CLAUDE_PATCH : {}),
59-
}),
37+
body: JSON.stringify(
38+
modelPatch({
39+
model: this.config.model,
40+
temperature: this.config.temperature,
41+
max_tokens: this.config.maxTokens,
42+
messages,
43+
44+
tools: openaiTools,
45+
// tool_choice: 'required',
46+
tool_choice: { type: 'function', function: { name: 'AgentOutput' } },
47+
48+
// model specific params
49+
50+
// reasoning_effort: 'minimal',
51+
// verbosity: 'low',
52+
parallel_tool_calls: false,
53+
})
54+
),
6055
signal: abortSignal,
6156
})
6257
} catch (error: unknown) {

src/llms/OpenAILenientClient.ts

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ import type { MacroToolInput } from '@/PageAgent'
55

66
import { InvokeError, InvokeErrorType } from './errors'
77
import type { InvokeResult, LLMClient, Message, OpenAIClientConfig, Tool } from './types'
8-
import { lenientParseMacroToolCall, zodToOpenAITool } from './utils'
9-
10-
// Claude's openAI-API has different format for some fields
11-
const CLAUDE_PATCH = {
12-
tool_choice: { type: 'tool', name: 'AgentOutput' },
13-
thinking: { type: 'disabled' },
14-
}
8+
import { lenientParseMacroToolCall, modelPatch, zodToOpenAITool } from './utils'
159

1610
export class OpenAIClient implements LLMClient {
1711
config: OpenAIClientConfig
@@ -41,24 +35,24 @@ export class OpenAIClient implements LLMClient {
4135
'Content-Type': 'application/json',
4236
Authorization: `Bearer ${this.config.apiKey}`,
4337
},
44-
body: JSON.stringify({
45-
model: this.config.model,
46-
temperature: this.config.temperature,
47-
max_tokens: this.config.maxTokens,
48-
messages,
49-
50-
tools: openaiTools,
51-
// tool_choice: 'required',
52-
tool_choice: { type: 'function', function: { name: 'AgentOutput' } },
53-
54-
// model specific params
55-
56-
// reasoning_effort: 'minimal',
57-
// verbosity: 'low',
58-
parallel_tool_calls: false,
59-
60-
...(isClaude ? CLAUDE_PATCH : {}),
61-
}),
38+
body: JSON.stringify(
39+
modelPatch({
40+
model: this.config.model,
41+
temperature: this.config.temperature,
42+
max_tokens: this.config.maxTokens,
43+
messages,
44+
45+
tools: openaiTools,
46+
// tool_choice: 'required',
47+
tool_choice: { type: 'function', function: { name: 'AgentOutput' } },
48+
49+
// model specific params
50+
51+
// reasoning_effort: 'minimal',
52+
// verbosity: 'low',
53+
parallel_tool_calls: false,
54+
})
55+
),
6256
signal: abortSignal,
6357
})
6458
} catch (error: unknown) {

src/llms/utils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,23 @@ export function lenientParseMacroToolCall(
192192
)
193193
}
194194
}
195+
196+
export function modelPatch(body: Record<string, any>) {
197+
const model: string = body.model || ''
198+
199+
if (model.toLowerCase().startsWith('claude')) {
200+
body.tool_choice = { type: 'tool', name: 'AgentOutput' }
201+
body.thinking = { type: 'disabled' }
202+
// body.reasoning = { enabled: 'disabled' }
203+
}
204+
205+
if (model.toLowerCase().includes('grok')) {
206+
console.log('Applying Grok patch: removing tool_choice')
207+
delete body.tool_choice
208+
console.log('Applying Grok patch: disable reasoning and thinking')
209+
body.thinking = { type: 'disabled', effort: 'minimal' }
210+
body.reasoning = { enabled: false, effort: 'low' }
211+
}
212+
213+
return body
214+
}

0 commit comments

Comments
 (0)