Skip to content

Commit 8d056f1

Browse files
committed
Enabled reasoning in Roo provider
1 parent 634b1df commit 8d056f1

File tree

28 files changed

+1222
-9
lines changed

28 files changed

+1222
-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: 152 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,134 @@ describe("RooHandler", () => {
446468
expect(handler).toBeInstanceOf(RooHandler)
447469
})
448470
})
471+
472+
describe("reasoning effort support", () => {
473+
it("should not include reasoning 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+
}),
487+
undefined,
488+
)
489+
// Verify reasoning is not included
490+
const callArgs = mockCreate.mock.calls[0][0]
491+
expect(callArgs.reasoning).toBeUndefined()
492+
})
493+
494+
it("should include reasoning with enabled: false when explicitly disabled", async () => {
495+
handler = new RooHandler({
496+
...mockOptions,
497+
enableReasoningEffort: false,
498+
})
499+
const stream = handler.createMessage(systemPrompt, messages)
500+
for await (const _chunk of stream) {
501+
// Consume stream
502+
}
503+
504+
expect(mockCreate).toHaveBeenCalledWith(
505+
expect.objectContaining({
506+
reasoning: { enabled: false },
507+
}),
508+
undefined,
509+
)
510+
})
511+
512+
it("should include reasoning with enabled: true and effort: low", async () => {
513+
handler = new RooHandler({
514+
...mockOptions,
515+
reasoningEffort: "low",
516+
})
517+
const stream = handler.createMessage(systemPrompt, messages)
518+
for await (const _chunk of stream) {
519+
// Consume stream
520+
}
521+
522+
expect(mockCreate).toHaveBeenCalledWith(
523+
expect.objectContaining({
524+
reasoning: { enabled: true, effort: "low" },
525+
}),
526+
undefined,
527+
)
528+
})
529+
530+
it("should include reasoning with enabled: true and effort: medium", async () => {
531+
handler = new RooHandler({
532+
...mockOptions,
533+
reasoningEffort: "medium",
534+
})
535+
const stream = handler.createMessage(systemPrompt, messages)
536+
for await (const _chunk of stream) {
537+
// Consume stream
538+
}
539+
540+
expect(mockCreate).toHaveBeenCalledWith(
541+
expect.objectContaining({
542+
reasoning: { enabled: true, effort: "medium" },
543+
}),
544+
undefined,
545+
)
546+
})
547+
548+
it("should include reasoning with enabled: true and effort: high", async () => {
549+
handler = new RooHandler({
550+
...mockOptions,
551+
reasoningEffort: "high",
552+
})
553+
const stream = handler.createMessage(systemPrompt, messages)
554+
for await (const _chunk of stream) {
555+
// Consume stream
556+
}
557+
558+
expect(mockCreate).toHaveBeenCalledWith(
559+
expect.objectContaining({
560+
reasoning: { enabled: true, effort: "high" },
561+
}),
562+
undefined,
563+
)
564+
})
565+
566+
it("should not include reasoning for minimal (treated as none)", async () => {
567+
handler = new RooHandler({
568+
...mockOptions,
569+
reasoningEffort: "minimal",
570+
})
571+
const stream = handler.createMessage(systemPrompt, messages)
572+
for await (const _chunk of stream) {
573+
// Consume stream
574+
}
575+
576+
// minimal should result in no reasoning parameter
577+
const callArgs = mockCreate.mock.calls[0][0]
578+
expect(callArgs.reasoning).toBeUndefined()
579+
})
580+
581+
it("should handle enableReasoningEffort: false overriding reasoningEffort setting", async () => {
582+
handler = new RooHandler({
583+
...mockOptions,
584+
enableReasoningEffort: false,
585+
reasoningEffort: "high",
586+
})
587+
const stream = handler.createMessage(systemPrompt, messages)
588+
for await (const _chunk of stream) {
589+
// Consume stream
590+
}
591+
592+
// When explicitly disabled, should send enabled: false regardless of effort setting
593+
expect(mockCreate).toHaveBeenCalledWith(
594+
expect.objectContaining({
595+
reasoning: { enabled: false },
596+
}),
597+
undefined,
598+
)
599+
})
600+
})
449601
})

0 commit comments

Comments
 (0)