( systemPrompt: string, messages: Anthropic.Messages.MessageParam[], metadata?: ApiHandlerCreateMessageMetadata, )
| 78 | } |
| 79 | |
| 80 | override async *createMessage( |
| 81 | systemPrompt: string, |
| 82 | messages: Anthropic.Messages.MessageParam[], |
| 83 | metadata?: ApiHandlerCreateMessageMetadata, |
| 84 | ): ApiStream { |
| 85 | const { info: modelInfo, reasoning } = this.getModel() |
| 86 | const modelUrl = this.options.openAiBaseUrl ?? "" |
| 87 | const modelId = this.options.openAiModelId ?? "" |
| 88 | const enabledR1Format = this.options.openAiR1FormatEnabled ?? false |
| 89 | const isAzureAiInference = this._isAzureAiInference(modelUrl) |
| 90 | const deepseekReasoner = modelId.includes("deepseek-reasoner") || enabledR1Format |
| 91 | |
| 92 | if (modelId.includes("o1") || modelId.includes("o3") || modelId.includes("o4")) { |
| 93 | yield* this.handleO3FamilyMessage(modelId, systemPrompt, messages, metadata) |
| 94 | return |
| 95 | } |
| 96 | |
| 97 | let systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam = { |
| 98 | role: "system", |
| 99 | content: systemPrompt, |
| 100 | } |
| 101 | |
| 102 | if (this.options.openAiStreamingEnabled ?? true) { |
| 103 | let convertedMessages |
| 104 | |
| 105 | if (deepseekReasoner) { |
| 106 | convertedMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages]) |
| 107 | } else { |
| 108 | if (modelInfo.supportsPromptCache) { |
| 109 | systemMessage = { |
| 110 | role: "system", |
| 111 | content: [ |
| 112 | { |
| 113 | type: "text", |
| 114 | text: systemPrompt, |
| 115 | // @ts-ignore-next-line |
| 116 | cache_control: { type: "ephemeral" }, |
| 117 | }, |
| 118 | ], |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | convertedMessages = [systemMessage, ...convertToOpenAiMessages(messages)] |
| 123 | |
| 124 | if (modelInfo.supportsPromptCache) { |
| 125 | // Note: the following logic is copied from openrouter: |
| 126 | // Add cache_control to the last two user messages |
| 127 | // (note: this works because we only ever add one user message at a time, but if we added multiple we'd need to mark the user message before the last assistant message) |
| 128 | const lastTwoUserMessages = convertedMessages.filter((msg) => msg.role === "user").slice(-2) |
| 129 | |
| 130 | lastTwoUserMessages.forEach((msg) => { |
| 131 | if (typeof msg.content === "string") { |
| 132 | msg.content = [{ type: "text", text: msg.content }] |
| 133 | } |
| 134 | |
| 135 | if (Array.isArray(msg.content)) { |
| 136 | // NOTE: this is fine since env details will always be added at the end. but if it weren't there, and the user added a image_url type message, it would pop a text part before it and then move it after to the end. |
| 137 | let lastTextPart = msg.content.filter((part) => part.type === "text").pop() |
nothing calls this directly
no test coverage detected