From cc166f41443bdda215eede4995f2fef3507f534b Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Mon, 17 Feb 2025 18:37:23 +0000 Subject: [PATCH] Requesty provider improvements (#1829) * Requesty: Add cline headers to requests * Requesty: Add support for cache read/write tokens * Requesty: Remove deepseek reasoner conversions that are handled in-flight by Requesty * Requesty: Read o3-mini reasoning effort from Cline settings * Requesty: Add total cost per interaction * Add changeset --- .changeset/fair-snails-confess.md | 10 ++++++++++ src/api/providers/requesty.ts | 31 +++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 .changeset/fair-snails-confess.md diff --git a/.changeset/fair-snails-confess.md b/.changeset/fair-snails-confess.md new file mode 100644 index 0000000000..f54c839141 --- /dev/null +++ b/.changeset/fair-snails-confess.md @@ -0,0 +1,10 @@ +--- +"claude-dev": patch +--- + +Improve Requesty provider integration + +- Adding Cline headers to API requests, to enable targeted optimizations +- Read o3 reasoning effort from Cline config, not model name +- Show token information in task header +- Get total cost from response when available diff --git a/src/api/providers/requesty.ts b/src/api/providers/requesty.ts index 34dd2b4d67..218d4785ad 100644 --- a/src/api/providers/requesty.ts +++ b/src/api/providers/requesty.ts @@ -5,7 +5,6 @@ import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../.. import { ApiHandler } from "../index" import { convertToOpenAiMessages } from "../transform/openai-format" import { ApiStream } from "../transform/stream" -import { convertToR1Format } from "../transform/r1-format" export class RequestyHandler implements ApiHandler { private options: ApiHandlerOptions @@ -16,30 +15,32 @@ export class RequestyHandler implements ApiHandler { this.client = new OpenAI({ baseURL: "https://router.requesty.ai/v1", apiKey: this.options.requestyApiKey, + defaultHeaders: { + "HTTP-Referer": "https://cline.bot", + "X-Title": "Cline", + }, }) } @withRetry() async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream { const modelId = this.options.requestyModelId ?? "" - const isDeepseekReasoner = modelId.includes("deepseek-reasoner") let openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [ { role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages), ] - if (isDeepseekReasoner) { - openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages]) - } - + // @ts-ignore-next-line const stream = await this.client.chat.completions.create({ model: modelId, messages: openAiMessages, temperature: 0, stream: true, stream_options: { include_usage: true }, + ...(modelId === "openai/o3-mini" ? { reasoning_effort: this.options.o3MiniReasoningEffort || "medium" } : {}), }) + for await (const chunk of stream) { const delta = chunk.choices[0]?.delta if (delta?.content) { @@ -56,11 +57,25 @@ export class RequestyHandler implements ApiHandler { } } + // Requesty usage includes an extra field for Anthropic use cases. + // Safely cast the prompt token details section to the appropriate structure. + interface RequestyUsage extends OpenAI.CompletionUsage { + prompt_tokens_details?: { + caching_tokens?: number + cached_tokens?: number + } + total_cost?: number + } + if (chunk.usage) { + const usage = chunk.usage as RequestyUsage yield { type: "usage", - inputTokens: chunk.usage.prompt_tokens || 0, - outputTokens: chunk.usage.completion_tokens || 0, + inputTokens: usage.prompt_tokens || 0, + outputTokens: usage.completion_tokens || 0, + cacheWriteTokens: usage.prompt_tokens_details?.caching_tokens || undefined, + cacheReadTokens: usage.prompt_tokens_details?.cached_tokens || undefined, + totalCost: usage.total_cost || undefined, } } }