Skip to content

Commit 0b6df73

Browse files
authored
Merge pull request #87 from trypear/agent/model-provider-refresh-2026-06-12
2 parents 6e1e0c6 + 703a404 commit 0b6df73

40 files changed

Lines changed: 830 additions & 845 deletions

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ module.exports = {
3636
"^default-shell$": "<rootDir>/src/__mocks__/default-shell.js",
3737
"^os-name$": "<rootDir>/src/__mocks__/os-name.js",
3838
"^strip-bom$": "<rootDir>/src/__mocks__/strip-bom.js",
39+
"^execa$": "<rootDir>/src/__mocks__/execa.js",
3940
"^@roo/(.*)$": "<rootDir>/src/$1",
4041
"^@src/(.*)$": "<rootDir>/webview-ui/src/$1",
4142
},

package-lock.json

Lines changed: 24 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@
409409
"monaco-vscode-textmate-theme-converter": "^0.1.7",
410410
"node-cache": "^5.1.2",
411411
"node-ipc": "^12.0.0",
412-
"openai": "^4.78.1",
412+
"openai": "^6.42.0",
413413
"os-name": "^6.0.0",
414414
"p-wait-for": "^5.0.2",
415415
"pdf-parse": "^1.1.1",
@@ -435,7 +435,7 @@
435435
"vscode-material-icons": "^0.1.1",
436436
"web-tree-sitter": "^0.22.6",
437437
"workerpool": "^9.2.0",
438-
"zod": "^3.23.8"
438+
"zod": "^3.25.76"
439439
},
440440
"devDependencies": {
441441
"@changesets/cli": "^2.27.10",

src/__mocks__/execa.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
class ExecaError extends Error {
2+
constructor(message = "Command failed", options = {}) {
3+
super(message)
4+
this.name = "ExecaError"
5+
this.exitCode = options.exitCode ?? 1
6+
this.signal = options.signal
7+
}
8+
}
9+
10+
const mockFn = (implementation) => (typeof jest === "undefined" ? implementation : jest.fn(implementation))
11+
12+
const createSubprocess = () => {
13+
const subprocess = Promise.resolve({
14+
exitCode: 0,
15+
stdout: "",
16+
stderr: "",
17+
all: "",
18+
})
19+
20+
subprocess.pid = 1234
21+
subprocess.iterable = mockFn(async function* () {})
22+
subprocess.kill = mockFn(() => true)
23+
24+
return subprocess
25+
}
26+
27+
const execa = mockFn((firstArg) => {
28+
if (firstArg && typeof firstArg === "object" && !Array.isArray(firstArg)) {
29+
return mockFn(() => createSubprocess())
30+
}
31+
32+
return createSubprocess()
33+
})
34+
35+
module.exports = {
36+
execa,
37+
ExecaError,
38+
}

src/__mocks__/vscode.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ const vscode = {
6060
Workspace: 2,
6161
WorkspaceFolder: 3,
6262
},
63+
CodeActionKind: {
64+
QuickFix: { value: "quickfix" },
65+
RefactorRewrite: { value: "refactor.rewrite" },
66+
},
6367
Position: class {
6468
constructor(line, character) {
6569
this.line = line

src/api/providers/__tests__/deepseek.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,17 @@ describe("DeepSeekHandler", () => {
165165
...mockOptions,
166166
apiModelId: "invalid-model",
167167
})
168+
const defaultHandler = new DeepSeekHandler({
169+
...mockOptions,
170+
apiModelId: undefined,
171+
})
168172
const model = handlerWithInvalidModel.getModel()
169173
expect(model.id).toBe("invalid-model") // Returns provided ID
170174
expect(model.info).toBeDefined()
171175
// With the current implementation, it's the same object reference when using default model info
172-
expect(model.info).toBe(handler.getModel().info)
176+
expect(model.info).toBe(defaultHandler.getModel().info)
173177
// Should have the same base properties
174-
expect(model.info.contextWindow).toBe(handler.getModel().info.contextWindow)
178+
expect(model.info.contextWindow).toBe(defaultHandler.getModel().info.contextWindow)
175179
// And should have supportsPromptCache set to true
176180
expect(model.info.supportsPromptCache).toBe(true)
177181
})

src/api/providers/__tests__/openai-native.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ describe("OpenAiNativeHandler", () => {
383383
openAiNativeApiKey: "test-api-key",
384384
})
385385
const modelInfo = handlerWithoutModel.getModel()
386-
expect(modelInfo.id).toBe("gpt-4.1") // Default model
386+
expect(modelInfo.id).toBe("gpt-5.5") // Default model
387387
expect(modelInfo.info).toBeDefined()
388388
})
389389
})

src/api/providers/__tests__/xai.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,17 @@ describe("XAIHandler", () => {
6161
})
6262

6363
test("should return specified model when valid model is provided", () => {
64-
const testModelId = "grok-2-latest"
64+
const testModelId = "grok-build-0.1"
6565
const handlerWithModel = new XAIHandler({ apiModelId: testModelId })
6666
const model = handlerWithModel.getModel()
6767

6868
expect(model.id).toBe(testModelId)
6969
expect(model.info).toEqual(xaiModels[testModelId])
7070
})
7171

72-
test("should include reasoning_effort parameter for mini models", async () => {
73-
const miniModelHandler = new XAIHandler({
74-
apiModelId: "grok-3-mini-beta",
72+
test("should include reasoning_effort parameter for Grok 4.3", async () => {
73+
const reasoningModelHandler = new XAIHandler({
74+
apiModelId: "grok-4.3",
7575
reasoningEffort: "high",
7676
})
7777

@@ -87,7 +87,7 @@ describe("XAIHandler", () => {
8787
})
8888

8989
// Start generating a message
90-
const messageGenerator = miniModelHandler.createMessage("test prompt", [])
90+
const messageGenerator = reasoningModelHandler.createMessage("test prompt", [])
9191
await messageGenerator.next() // Start the generator
9292

9393
// Check that reasoning_effort was included
@@ -98,9 +98,9 @@ describe("XAIHandler", () => {
9898
)
9999
})
100100

101-
test("should not include reasoning_effort parameter for non-mini models", async () => {
101+
test("should not include reasoning_effort parameter for non-reasoning models", async () => {
102102
const regularModelHandler = new XAIHandler({
103-
apiModelId: "grok-2-latest",
103+
apiModelId: "grok-build-0.1",
104104
reasoningEffort: "high",
105105
})
106106

@@ -254,7 +254,7 @@ describe("XAIHandler", () => {
254254

255255
test("createMessage should pass correct parameters to OpenAI client", async () => {
256256
// Setup a handler with specific model
257-
const modelId = "grok-2-latest"
257+
const modelId = "grok-build-0.1"
258258
const modelInfo = xaiModels[modelId]
259259
const handlerWithModel = new XAIHandler({ apiModelId: modelId })
260260

src/api/providers/anthropic.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import { BaseProvider } from "./base-provider"
1313
import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "./constants"
1414
import { SingleCompletionHandler, getModelParams } from "../index"
1515

16+
const ANTHROPIC_MODELS_WITHOUT_SAMPLING_PARAMS = new Set(["claude-fable-5", "claude-opus-4-8", "claude-sonnet-4-6"])
17+
18+
function omitsSamplingParams(modelId: string) {
19+
return ANTHROPIC_MODELS_WITHOUT_SAMPLING_PARAMS.has(modelId) || modelId.startsWith("claude-opus-4-7")
20+
}
21+
1622
export class AnthropicHandler extends BaseProvider implements SingleCompletionHandler {
1723
private options: ApiHandlerOptions
1824
private client: Anthropic
@@ -34,8 +40,16 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
3440
let stream: AnthropicStream<Anthropic.Messages.RawMessageStreamEvent>
3541
const cacheControl: CacheControlEphemeral = { type: "ephemeral" }
3642
let { id: modelId, maxTokens, thinking, temperature, virtualId } = this.getModel()
43+
let requestTemperature: number | undefined = temperature
44+
if (omitsSamplingParams(modelId)) {
45+
requestTemperature = undefined
46+
}
3747

3848
switch (modelId) {
49+
case "claude-fable-5":
50+
case "claude-opus-4-8":
51+
case "claude-sonnet-4-6":
52+
case "claude-haiku-4-5-20251001":
3953
case "claude-3-7-sonnet-20250219":
4054
case "claude-3-5-sonnet-20241022":
4155
case "claude-3-5-haiku-20241022":
@@ -63,7 +77,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
6377
{
6478
model: modelId,
6579
max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS,
66-
temperature,
80+
temperature: requestTemperature,
6781
thinking,
6882
// Setting cache breakpoint for system prompt so new tasks can reuse it.
6983
system: [{ text: systemPrompt, type: "text", cache_control: cacheControl }],
@@ -129,7 +143,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
129143
stream = (await this.client.messages.create({
130144
model: modelId,
131145
max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS,
132-
temperature,
146+
temperature: requestTemperature,
133147
system: [{ text: systemPrompt, type: "text" }],
134148
messages,
135149
stream: true,
@@ -273,12 +287,16 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
273287

274288
async completePrompt(prompt: string) {
275289
let { id: model, temperature } = this.getModel()
290+
let requestTemperature: number | undefined = temperature
291+
if (omitsSamplingParams(model)) {
292+
requestTemperature = undefined
293+
}
276294

277295
const message = await this.client.messages.create({
278296
model,
279297
max_tokens: ANTHROPIC_DEFAULT_MAX_TOKENS,
280298
thinking: undefined,
281-
temperature,
299+
temperature: requestTemperature,
282300
messages: [{ role: "user", content: prompt }],
283301
stream: false,
284302
})

0 commit comments

Comments
 (0)