Expose thinking tokens for roo/sonic (#7212)

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
Chris Estreich 2025-08-19 04:01:01 -10:00 committed by GitHub
parent fd3535c21a
commit 532728ee85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 58 additions and 9 deletions

View file

@ -3,3 +3,4 @@ POSTHOG_API_KEY=key-goes-here
# Roo Code Cloud / Local Development
CLERK_BASE_URL=https://epic-chamois-85.clerk.accounts.dev
ROO_CODE_API_URL=http://localhost:3000
ROO_CODE_PROVIDER_URL=http://localhost:8080/proxy/v1

View file

@ -10,10 +10,10 @@ export const rooModels = {
maxTokens: 8192,
contextWindow: 262_144,
supportsImages: false,
supportsPromptCache: false,
supportsPromptCache: true,
inputPrice: 0,
outputPrice: 0,
description:
"Stealth coding model with 262K context window, accessible for free through Roo Code Cloud for a limited time. (Note: prompts and completions are logged by the model creator and used to improve the model.)",
"A stealth reasoning model that is blazing fast and excels at agentic coding, accessible for free through Roo Code Cloud for a limited time. (Note: prompts and completions are logged by the model creator and used to improve the model.)",
},
} as const satisfies Record<string, ModelInfo>

View file

@ -331,7 +331,7 @@ describe("RooHandler", () => {
expect(modelInfo.info.maxTokens).toBe(8192)
expect(modelInfo.info.contextWindow).toBe(262_144)
expect(modelInfo.info.supportsImages).toBe(false)
expect(modelInfo.info.supportsPromptCache).toBe(false)
expect(modelInfo.info.supportsPromptCache).toBe(true)
expect(modelInfo.info.inputPrice).toBe(0)
expect(modelInfo.info.outputPrice).toBe(0)
})

View file

@ -62,11 +62,11 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
})
}
override async *createMessage(
protected createStream(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
): ApiStream {
) {
const {
id: model,
info: { maxTokens: max_tokens },
@ -83,7 +83,15 @@ export abstract class BaseOpenAiCompatibleProvider<ModelName extends string>
stream_options: { include_usage: true },
}
const stream = await this.client.chat.completions.create(params)
return this.client.chat.completions.create(params)
}
override async *createMessage(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
): ApiStream {
const stream = await this.createStream(systemPrompt, messages, metadata)
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta

View file

@ -1,10 +1,14 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { rooDefaultModelId, rooModels, type RooModelId } from "@roo-code/types"
import { CloudService } from "@roo-code/cloud"
import type { ApiHandlerOptions } from "../../shared/api"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
import { ApiStream } from "../transform/stream"
import { t } from "../../i18n"
import type { ApiHandlerCreateMessageMetadata } from "../index"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
export class RooHandler extends BaseOpenAiCompatibleProvider<RooModelId> {
constructor(options: ApiHandlerOptions) {
// Check if CloudService is available and get the session token.
@ -21,7 +25,7 @@ export class RooHandler extends BaseOpenAiCompatibleProvider<RooModelId> {
super({
...options,
providerName: "Roo Code Cloud",
baseURL: "https://api.roocode.com/proxy/v1",
baseURL: process.env.ROO_CODE_PROVIDER_URL ?? "https://api.roocode.com/proxy/v1",
apiKey: sessionToken,
defaultProviderModelId: rooDefaultModelId,
providerModels: rooModels,
@ -29,6 +33,42 @@ export class RooHandler extends BaseOpenAiCompatibleProvider<RooModelId> {
})
}
override async *createMessage(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
): ApiStream {
const stream = await this.createStream(systemPrompt, messages, metadata)
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta
if (delta) {
if (delta.content) {
yield {
type: "text",
text: delta.content,
}
}
if ("reasoning_content" in delta && typeof delta.reasoning_content === "string") {
yield {
type: "reasoning",
text: delta.reasoning_content,
}
}
}
if (chunk.usage) {
yield {
type: "usage",
inputTokens: chunk.usage.prompt_tokens || 0,
outputTokens: chunk.usage.completion_tokens || 0,
}
}
}
}
override getModel() {
const modelId = this.options.apiModelId || rooDefaultModelId
const modelInfo = this.providerModels[modelId as RooModelId] ?? this.providerModels[rooDefaultModelId]
@ -44,7 +84,7 @@ export class RooHandler extends BaseOpenAiCompatibleProvider<RooModelId> {
maxTokens: 8192,
contextWindow: 262_144,
supportsImages: false,
supportsPromptCache: false,
supportsPromptCache: true,
inputPrice: 0,
outputPrice: 0,
},