|
|
@@ -1,21 +1,18 @@
|
|
|
-import { Anthropic } from "@anthropic-ai/sdk"
|
|
|
-import OpenAI from "openai"
|
|
|
-
|
|
|
-import { ApiHandlerOptions, ModelInfo, requestyModelInfoSaneDefaults } from "../../shared/api"
|
|
|
-import { ApiHandler, SingleCompletionHandler } from "../index"
|
|
|
-import { convertToOpenAiMessages } from "../transform/openai-format"
|
|
|
-import { convertToR1Format } from "../transform/r1-format"
|
|
|
-import { ApiStream } from "../transform/stream"
|
|
|
-
|
|
|
-export class RequestyHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
- protected options: ApiHandlerOptions
|
|
|
- private client: OpenAI
|
|
|
-
|
|
|
- constructor(options: ApiHandlerOptions) {
|
|
|
- this.options = options
|
|
|
- this.client = new OpenAI({
|
|
|
- baseURL: "https://router.requesty.ai/v1",
|
|
|
- apiKey: this.options.requestyApiKey,
|
|
|
+import { OpenAiHandler, OpenAiHandlerOptions } from "./openai"
|
|
|
+import { ModelInfo, requestyModelInfoSaneDefaults, requestyDefaultModelId } from "../../shared/api"
|
|
|
+import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
|
|
|
+
|
|
|
+export class RequestyHandler extends OpenAiHandler {
|
|
|
+ constructor(options: OpenAiHandlerOptions) {
|
|
|
+ if (!options.requestyApiKey) {
|
|
|
+ throw new Error("Requesty API key is required. Please provide it in the settings.")
|
|
|
+ }
|
|
|
+ super({
|
|
|
+ ...options,
|
|
|
+ openAiApiKey: options.requestyApiKey,
|
|
|
+ openAiModelId: options.requestyModelId ?? requestyDefaultModelId,
|
|
|
+ openAiBaseUrl: "https://router.requesty.ai/v1",
|
|
|
+ openAiCustomModelInfo: options.requestyModelInfo ?? requestyModelInfoSaneDefaults,
|
|
|
defaultHeaders: {
|
|
|
"HTTP-Referer": "https://github.com/RooVetGit/Roo-Cline",
|
|
|
"X-Title": "Roo Code",
|
|
|
@@ -23,107 +20,21 @@ export class RequestyHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
|
|
- const modelInfo = this.getModel().info
|
|
|
- const modelId = this.options.requestyModelId ?? ""
|
|
|
-
|
|
|
- const deepseekReasoner = modelId.includes("deepseek-reasoner")
|
|
|
-
|
|
|
- if (this.options.openAiStreamingEnabled ?? true) {
|
|
|
- const systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam = {
|
|
|
- role: "system",
|
|
|
- content: systemPrompt,
|
|
|
- }
|
|
|
- const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
|
|
- model: modelId,
|
|
|
- temperature: 0,
|
|
|
- messages: deepseekReasoner
|
|
|
- ? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
|
|
- : [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
- stream: true as const,
|
|
|
- stream_options: { include_usage: true },
|
|
|
- }
|
|
|
- if (this.options.includeMaxTokens) {
|
|
|
- requestOptions.max_tokens = modelInfo.maxTokens
|
|
|
- }
|
|
|
-
|
|
|
- const stream = await this.client.chat.completions.create(requestOptions)
|
|
|
-
|
|
|
- for await (const chunk of stream) {
|
|
|
- const delta = chunk.choices[0]?.delta ?? {}
|
|
|
-
|
|
|
- if (delta.content) {
|
|
|
- yield {
|
|
|
- type: "text",
|
|
|
- text: delta.content,
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ("reasoning_content" in delta && delta.reasoning_content) {
|
|
|
- yield {
|
|
|
- type: "reasoning",
|
|
|
- text: (delta.reasoning_content as string | undefined) || "",
|
|
|
- }
|
|
|
- }
|
|
|
- if (chunk.usage) {
|
|
|
- yield {
|
|
|
- type: "usage",
|
|
|
- inputTokens: chunk.usage.prompt_tokens || 0,
|
|
|
- outputTokens: chunk.usage.completion_tokens || 0,
|
|
|
- cacheWriteTokens: (chunk.usage as any).cache_creation_input_tokens || undefined,
|
|
|
- cacheReadTokens: (chunk.usage as any).cache_read_input_tokens || undefined,
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // o1 for instance doesnt support streaming, non-1 temp, or system prompt
|
|
|
- const systemMessage: OpenAI.Chat.ChatCompletionUserMessageParam = {
|
|
|
- role: "user",
|
|
|
- content: systemPrompt,
|
|
|
- }
|
|
|
-
|
|
|
- const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
|
|
- model: modelId,
|
|
|
- messages: deepseekReasoner
|
|
|
- ? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
|
|
- : [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
- }
|
|
|
-
|
|
|
- const response = await this.client.chat.completions.create(requestOptions)
|
|
|
-
|
|
|
- yield {
|
|
|
- type: "text",
|
|
|
- text: response.choices[0]?.message.content || "",
|
|
|
- }
|
|
|
- yield {
|
|
|
- type: "usage",
|
|
|
- inputTokens: response.usage?.prompt_tokens || 0,
|
|
|
- outputTokens: response.usage?.completion_tokens || 0,
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- getModel(): { id: string; info: ModelInfo } {
|
|
|
+ override getModel(): { id: string; info: ModelInfo } {
|
|
|
+ const modelId = this.options.requestyModelId ?? requestyDefaultModelId
|
|
|
return {
|
|
|
- id: this.options.requestyModelId ?? "",
|
|
|
+ id: modelId,
|
|
|
info: this.options.requestyModelInfo ?? requestyModelInfoSaneDefaults,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async completePrompt(prompt: string): Promise<string> {
|
|
|
- try {
|
|
|
- const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
|
|
- model: this.getModel().id,
|
|
|
- messages: [{ role: "user", content: prompt }],
|
|
|
- }
|
|
|
-
|
|
|
- const response = await this.client.chat.completions.create(requestOptions)
|
|
|
- return response.choices[0]?.message.content || ""
|
|
|
- } catch (error) {
|
|
|
- if (error instanceof Error) {
|
|
|
- throw new Error(`OpenAI completion error: ${error.message}`)
|
|
|
- }
|
|
|
- throw error
|
|
|
+ protected override processUsageMetrics(usage: any): ApiStreamUsageChunk {
|
|
|
+ return {
|
|
|
+ type: "usage",
|
|
|
+ inputTokens: usage?.prompt_tokens || 0,
|
|
|
+ outputTokens: usage?.completion_tokens || 0,
|
|
|
+ cacheWriteTokens: usage?.cache_creation_input_tokens,
|
|
|
+ cacheReadTokens: usage?.cache_read_input_tokens,
|
|
|
}
|
|
|
}
|
|
|
}
|