|
|
@@ -1,5 +1,6 @@
|
|
|
import { Anthropic } from "@anthropic-ai/sdk"
|
|
|
import OpenAI, { AzureOpenAI } from "openai"
|
|
|
+
|
|
|
import {
|
|
|
ApiHandlerOptions,
|
|
|
azureOpenAiDefaultApiVersion,
|
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
} 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 OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
@@ -16,7 +18,8 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
|
|
|
constructor(options: ApiHandlerOptions) {
|
|
|
this.options = options
|
|
|
- // Azure API shape slightly differs from the core API shape: https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
|
|
|
+ // Azure API shape slightly differs from the core API shape:
|
|
|
+ // https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
|
|
|
const urlHost = new URL(this.options.openAiBaseUrl ?? "").host
|
|
|
if (urlHost === "azure.com" || urlHost.endsWith(".azure.com") || options.openAiUseAzure) {
|
|
|
this.client = new AzureOpenAI({
|
|
|
@@ -38,7 +41,7 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
|
|
|
const deepseekReasoner = modelId.includes("deepseek-reasoner")
|
|
|
|
|
|
- if (!deepseekReasoner && (this.options.openAiStreamingEnabled ?? true)) {
|
|
|
+ if (this.options.openAiStreamingEnabled ?? true) {
|
|
|
const systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam = {
|
|
|
role: "system",
|
|
|
content: systemPrompt,
|
|
|
@@ -46,7 +49,9 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
|
|
model: modelId,
|
|
|
temperature: 0,
|
|
|
- messages: [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
+ messages: deepseekReasoner
|
|
|
+ ? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
|
|
+ : [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
stream: true as const,
|
|
|
stream_options: { include_usage: true },
|
|
|
}
|
|
|
@@ -64,6 +69,12 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
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",
|
|
|
@@ -73,24 +84,19 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- let systemMessage: OpenAI.Chat.ChatCompletionUserMessageParam | OpenAI.Chat.ChatCompletionSystemMessageParam
|
|
|
-
|
|
|
// o1 for instance doesnt support streaming, non-1 temp, or system prompt
|
|
|
- // deepseek reasoner supports system prompt
|
|
|
- systemMessage = deepseekReasoner
|
|
|
- ? {
|
|
|
- role: "system",
|
|
|
- content: systemPrompt,
|
|
|
- }
|
|
|
- : {
|
|
|
- role: "user",
|
|
|
- content: systemPrompt,
|
|
|
- }
|
|
|
+ const systemMessage: OpenAI.Chat.ChatCompletionUserMessageParam = {
|
|
|
+ role: "user",
|
|
|
+ content: systemPrompt,
|
|
|
+ }
|
|
|
|
|
|
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
|
|
model: modelId,
|
|
|
- messages: [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
+ messages: deepseekReasoner
|
|
|
+ ? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
|
|
+ : [systemMessage, ...convertToOpenAiMessages(messages)],
|
|
|
}
|
|
|
+
|
|
|
const response = await this.client.chat.completions.create(requestOptions)
|
|
|
|
|
|
yield {
|