Skip to content

Commit b72d55e

Browse files
authored
Enabled reasoning in Roo provider (#8874)
1 parent 3cbdbc2 commit b72d55e

File tree

28 files changed

+1223
-9
lines changed

28 files changed

+1223
-9
lines changed

packages/types/src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export const modelInfoSchema = z.object({
6565
supportsTemperature: z.boolean().optional(),
6666
requiredReasoningBudget: z.boolean().optional(),
6767
supportsReasoningEffort: z.boolean().optional(),
68+
requiredReasoningEffort: z.boolean().optional(),
6869
supportedParameters: z.array(modelParametersSchema).optional(),
6970
inputPrice: z.number().optional(),
7071
outputPrice: z.number().optional(),

src/api/providers/__tests__/roo.spec.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,28 @@ vitest.mock("../../../i18n", () => ({
8686
}),
8787
}))
8888

89+
// Mock model cache
90+
vitest.mock("../../providers/fetchers/modelCache", () => ({
91+
getModels: vitest.fn(),
92+
flushModels: vitest.fn(),
93+
getModelsFromCache: vitest.fn((provider: string) => {
94+
if (provider === "roo") {
95+
return {
96+
"xai/grok-code-fast-1": {
97+
maxTokens: 16_384,
98+
contextWindow: 262_144,
99+
supportsImages: false,
100+
supportsReasoningEffort: true, // Enable reasoning for tests
101+
supportsPromptCache: true,
102+
inputPrice: 0,
103+
outputPrice: 0,
104+
},
105+
}
106+
}
107+
return {}
108+
}),
109+
}))
110+
89111
// Import after mocks are set up
90112
import { RooHandler } from "../roo"
91113
import { CloudService } from "@roo-code/cloud"
@@ -446,4 +468,132 @@ describe("RooHandler", () => {
446468
expect(handler).toBeInstanceOf(RooHandler)
447469
})
448470
})
471+
472+
describe("reasoning effort support", () => {
473+
it("should include reasoning with enabled: false when not enabled", async () => {
474+
handler = new RooHandler(mockOptions)
475+
const stream = handler.createMessage(systemPrompt, messages)
476+
for await (const _chunk of stream) {
477+
// Consume stream
478+
}
479+
480+
expect(mockCreate).toHaveBeenCalledWith(
481+
expect.objectContaining({
482+
model: mockOptions.apiModelId,
483+
messages: expect.any(Array),
484+
stream: true,
485+
stream_options: { include_usage: true },
486+
reasoning: { enabled: false },
487+
}),
488+
undefined,
489+
)
490+
})
491+
492+
it("should include reasoning with enabled: false when explicitly disabled", async () => {
493+
handler = new RooHandler({
494+
...mockOptions,
495+
enableReasoningEffort: false,
496+
})
497+
const stream = handler.createMessage(systemPrompt, messages)
498+
for await (const _chunk of stream) {
499+
// Consume stream
500+
}
501+
502+
expect(mockCreate).toHaveBeenCalledWith(
503+
expect.objectContaining({
504+
reasoning: { enabled: false },
505+
}),
506+
undefined,
507+
)
508+
})
509+
510+
it("should include reasoning with enabled: true and effort: low", async () => {
511+
handler = new RooHandler({
512+
...mockOptions,
513+
reasoningEffort: "low",
514+
})
515+
const stream = handler.createMessage(systemPrompt, messages)
516+
for await (const _chunk of stream) {
517+
// Consume stream
518+
}
519+
520+
expect(mockCreate).toHaveBeenCalledWith(
521+
expect.objectContaining({
522+
reasoning: { enabled: true, effort: "low" },
523+
}),
524+
undefined,
525+
)
526+
})
527+
528+
it("should include reasoning with enabled: true and effort: medium", async () => {
529+
handler = new RooHandler({
530+
...mockOptions,
531+
reasoningEffort: "medium",
532+
})
533+
const stream = handler.createMessage(systemPrompt, messages)
534+
for await (const _chunk of stream) {
535+
// Consume stream
536+
}
537+
538+
expect(mockCreate).toHaveBeenCalledWith(
539+
expect.objectContaining({
540+
reasoning: { enabled: true, effort: "medium" },
541+
}),
542+
undefined,
543+
)
544+
})
545+
546+
it("should include reasoning with enabled: true and effort: high", async () => {
547+
handler = new RooHandler({
548+
...mockOptions,
549+
reasoningEffort: "high",
550+
})
551+
const stream = handler.createMessage(systemPrompt, messages)
552+
for await (const _chunk of stream) {
553+
// Consume stream
554+
}
555+
556+
expect(mockCreate).toHaveBeenCalledWith(
557+
expect.objectContaining({
558+
reasoning: { enabled: true, effort: "high" },
559+
}),
560+
undefined,
561+
)
562+
})
563+
564+
it("should not include reasoning for minimal (treated as none)", async () => {
565+
handler = new RooHandler({
566+
...mockOptions,
567+
reasoningEffort: "minimal",
568+
})
569+
const stream = handler.createMessage(systemPrompt, messages)
570+
for await (const _chunk of stream) {
571+
// Consume stream
572+
}
573+
574+
// minimal should result in no reasoning parameter
575+
const callArgs = mockCreate.mock.calls[0][0]
576+
expect(callArgs.reasoning).toBeUndefined()
577+
})
578+
579+
it("should handle enableReasoningEffort: false overriding reasoningEffort setting", async () => {
580+
handler = new RooHandler({
581+
...mockOptions,
582+
enableReasoningEffort: false,
583+
reasoningEffort: "high",
584+
})
585+
const stream = handler.createMessage(systemPrompt, messages)
586+
for await (const _chunk of stream) {
587+
// Consume stream
588+
}
589+
590+
// When explicitly disabled, should send enabled: false regardless of effort setting
591+
expect(mockCreate).toHaveBeenCalledWith(
592+
expect.objectContaining({
593+
reasoning: { enabled: false },
594+
}),
595+
undefined,
596+
)
597+
})
598+
})
449599
})

0 commit comments

Comments
 (0)