UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

241 lines (239 loc) • 10.1 kB
require("reflect-metadata"); const require_runtime = require('../../_virtual/_rolldown/runtime.cjs'); const require_error_utils = require('../shared/error-utils.cjs'); const require_sdk_client_utils = require('../shared/sdk-client-utils.cjs'); const require_utils = require('./utils.cjs'); let _copilotkit_shared = require("@copilotkit/shared"); let _ai_sdk_anthropic = require("@ai-sdk/anthropic"); //#region src/service-adapters/anthropic/anthropic-adapter.ts const DEFAULT_MODEL = "claude-3-5-sonnet-latest"; var AnthropicAdapter = class { get anthropic() { return this._anthropic; } get name() { return "AnthropicAdapter"; } constructor(params) { this.model = DEFAULT_MODEL; this.provider = "anthropic"; if (params?.anthropic) this._anthropic = params.anthropic; if (params?.model) this.model = params.model; this.promptCaching = params?.promptCaching || { enabled: false }; this.maxInputTokens = params?.maxInputTokens; } getLanguageModel() { const anthropic = this.ensureAnthropic(); const options = require_sdk_client_utils.getSdkClientOptions(anthropic); return (0, _ai_sdk_anthropic.createAnthropic)({ baseURL: anthropic.baseURL, apiKey: anthropic.apiKey, headers: options.defaultHeaders, fetch: options.fetch })(this.model); } ensureAnthropic() { if (!this._anthropic) { const Anthropic = require("@anthropic-ai/sdk").default; this._anthropic = new Anthropic({}); } return this._anthropic; } /** * Adds cache control to system prompt */ addSystemPromptCaching(system, debug = false) { if (!this.promptCaching.enabled || !system) return system; const originalTextLength = system.length; if (debug) console.log(`[ANTHROPIC CACHE DEBUG] Added cache control to system prompt (${originalTextLength} chars).`); return [{ type: "text", text: system, cache_control: { type: "ephemeral" } }]; } /** * Adds cache control to the final message */ addIncrementalMessageCaching(messages, debug = false) { if (!this.promptCaching.enabled || messages.length === 0) return messages; const finalMessage = messages[messages.length - 1]; const messageNumber = messages.length; if (Array.isArray(finalMessage.content) && finalMessage.content.length > 0) { const finalBlock = finalMessage.content[finalMessage.content.length - 1]; const updatedMessages = [...messages.slice(0, -1), { ...finalMessage, content: [...finalMessage.content.slice(0, -1), { ...finalBlock, cache_control: { type: "ephemeral" } }] }]; if (debug) console.log(`[ANTHROPIC CACHE DEBUG] Added cache control to final message (message ${messageNumber}).`); return updatedMessages; } return messages; } shouldGenerateFallbackResponse(messages) { if (messages.length === 0) return false; const lastMessage = messages[messages.length - 1]; const endsWithToolResult = lastMessage.role === "user" && Array.isArray(lastMessage.content) && lastMessage.content.some((content) => content.type === "tool_result"); if (messages.length >= 3 && endsWithToolResult) { const lastThree = messages.slice(-3); return lastThree[0]?.role === "user" && lastThree[1]?.role === "assistant" && Array.isArray(lastThree[1].content) && lastThree[1].content.some((content) => content.type === "tool_use") && lastThree[2]?.role === "user" && Array.isArray(lastThree[2].content) && lastThree[2].content.some((content) => content.type === "tool_result"); } return endsWithToolResult; } async process(request) { const { threadId, model = this.model, messages: rawMessages, actions, eventSource, forwardedParameters } = request; const tools = actions.map(require_utils.convertActionInputToAnthropicTool); const knownActionNames = new Set(actions.map((a) => a.name)); const messages = [...rawMessages]; const instructionsMessage = messages.shift(); const instructions = instructionsMessage.isTextMessage() ? instructionsMessage.content : ""; const validToolUseIds = /* @__PURE__ */ new Set(); for (const message of messages) if (message.isActionExecutionMessage()) validToolUseIds.add(message.id); const processedToolResultIds = /* @__PURE__ */ new Set(); const limitedMessages = require_utils.limitMessagesToTokenCount(messages.map((message) => { if (message.isResultMessage()) { if (!validToolUseIds.has(message.actionExecutionId)) return null; if (processedToolResultIds.has(message.actionExecutionId)) return null; processedToolResultIds.add(message.actionExecutionId); return { role: "user", content: [{ type: "tool_result", content: message.result || "Action completed successfully", tool_use_id: message.actionExecutionId }] }; } return require_utils.convertMessageToAnthropicMessage(message); }).filter(Boolean).filter((msg) => { if (msg.role === "assistant" && Array.isArray(msg.content)) return !(msg.content.length === 1 && msg.content[0].type === "text" && (!msg.content[0].text || msg.content[0].text.trim() === "")); return true; }), tools, model, this.maxInputTokens); const cachedSystemPrompt = this.addSystemPromptCaching(instructions, this.promptCaching.debug); const cachedMessages = this.addIncrementalMessageCaching(limitedMessages, this.promptCaching.debug); let toolChoice = forwardedParameters?.toolChoice; if (forwardedParameters?.toolChoice === "function") toolChoice = { type: "tool", name: forwardedParameters.toolChoiceFunctionName }; try { const createParams = { system: cachedSystemPrompt, model: this.model, messages: cachedMessages, max_tokens: forwardedParameters?.maxTokens || 4096, ...forwardedParameters?.temperature ? { temperature: forwardedParameters.temperature } : {}, ...tools.length > 0 && { tools }, ...toolChoice && { tool_choice: toolChoice }, stream: true }; const stream = await this.ensureAnthropic().messages.create(createParams); eventSource.stream(async (eventStream$) => { let mode = null; let didOutputText = false; let currentMessageId = (0, _copilotkit_shared.randomId)(); let currentToolCallId = (0, _copilotkit_shared.randomId)(); let filterThinkingTextBuffer = new FilterThinkingTextBuffer(); let hasReceivedContent = false; try { for await (const chunk of stream) if (chunk.type === "message_start") currentMessageId = chunk.message.id; else if (chunk.type === "content_block_start") { if (chunk.content_block.type === "text") { hasReceivedContent = true; didOutputText = false; filterThinkingTextBuffer.reset(); mode = "message"; } else if (chunk.content_block.type === "tool_use") { if (!knownActionNames.has(chunk.content_block.name)) { mode = null; continue; } hasReceivedContent = true; currentToolCallId = chunk.content_block.id; eventStream$.sendActionExecutionStart({ actionExecutionId: currentToolCallId, actionName: chunk.content_block.name, parentMessageId: currentMessageId }); mode = "function"; } } else if (chunk.type === "content_block_delta") { if (mode === null) continue; if (chunk.delta.type === "text_delta") { const text = filterThinkingTextBuffer.onTextChunk(chunk.delta.text); if (text.length > 0) { if (!didOutputText) { eventStream$.sendTextMessageStart({ messageId: currentMessageId }); didOutputText = true; } eventStream$.sendTextMessageContent({ messageId: currentMessageId, content: text }); } } else if (chunk.delta.type === "input_json_delta") eventStream$.sendActionExecutionArgs({ actionExecutionId: currentToolCallId, args: chunk.delta.partial_json }); } else if (chunk.type === "content_block_stop") { if (mode === "message") { if (didOutputText) eventStream$.sendTextMessageEnd({ messageId: currentMessageId }); } else if (mode === "function") eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId }); } } catch (error) { throw require_error_utils.convertServiceAdapterError(error, "Anthropic"); } if (!hasReceivedContent && this.shouldGenerateFallbackResponse(cachedMessages)) { let fallbackContent = "Task completed successfully."; const lastMessage = cachedMessages[cachedMessages.length - 1]; if (lastMessage?.role === "user" && Array.isArray(lastMessage.content)) { const toolResult = lastMessage.content.find((c) => c.type === "tool_result"); if (toolResult?.content && toolResult.content !== "Action completed successfully") fallbackContent = toolResult.content; } currentMessageId = (0, _copilotkit_shared.randomId)(); eventStream$.sendTextMessageStart({ messageId: currentMessageId }); eventStream$.sendTextMessageContent({ messageId: currentMessageId, content: fallbackContent }); eventStream$.sendTextMessageEnd({ messageId: currentMessageId }); } eventStream$.complete(); }); } catch (error) { throw require_error_utils.convertServiceAdapterError(error, "Anthropic"); } return { threadId: threadId || (0, _copilotkit_shared.randomUUID)() }; } }; const THINKING_TAG = "<thinking>"; const THINKING_TAG_END = "</thinking>"; var FilterThinkingTextBuffer = class { constructor() { this.didFilterThinkingTag = false; this.buffer = ""; } onTextChunk(text) { this.buffer += text; if (this.didFilterThinkingTag) return text; const potentialTag = this.buffer.slice(0, 10); if (THINKING_TAG.startsWith(potentialTag)) if (this.buffer.includes(THINKING_TAG_END)) { const end = this.buffer.indexOf(THINKING_TAG_END); const filteredText = this.buffer.slice(end + 11); this.buffer = filteredText; this.didFilterThinkingTag = true; return filteredText; } else return ""; return text; } reset() { this.buffer = ""; this.didFilterThinkingTag = false; } }; //#endregion exports.AnthropicAdapter = AnthropicAdapter; //# sourceMappingURL=anthropic-adapter.cjs.map