UNPKG

@genkit-ai/vertexai

Version:

Genkit AI framework plugin for Google Cloud Vertex AI APIs including Gemini APIs, Imagen, and more.

355 lines 8.95 kB
import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"; import { GENKIT_CLIENT_HEADER, z } from "genkit"; import { GenerationCommonConfigSchema, getBasicUsageStats, modelRef } from "genkit/model"; const AnthropicConfigSchema = GenerationCommonConfigSchema.extend({ location: z.string().optional() }); const claude35SonnetV2 = modelRef({ name: "vertexai/claude-3-5-sonnet-v2", info: { label: "Vertex AI Model Garden - Claude 3.5 Sonnet", versions: ["claude-3-5-sonnet-v2@20241022"], supports: { multiturn: true, media: true, tools: true, systemRole: true, output: ["text"] } }, configSchema: AnthropicConfigSchema }); const claude35Sonnet = modelRef({ name: "vertexai/claude-3-5-sonnet", info: { label: "Vertex AI Model Garden - Claude 3.5 Sonnet", versions: ["claude-3-5-sonnet@20240620"], supports: { multiturn: true, media: true, tools: true, systemRole: true, output: ["text"] } }, configSchema: AnthropicConfigSchema }); const claude3Sonnet = modelRef({ name: "vertexai/claude-3-sonnet", info: { label: "Vertex AI Model Garden - Claude 3 Sonnet", versions: ["claude-3-sonnet@20240229"], supports: { multiturn: true, media: true, tools: true, systemRole: true, output: ["text"] } }, configSchema: AnthropicConfigSchema }); const claude3Haiku = modelRef({ name: "vertexai/claude-3-haiku", info: { label: "Vertex AI Model Garden - Claude 3 Haiku", versions: ["claude-3-haiku@20240307"], supports: { multiturn: true, media: true, tools: true, systemRole: true, output: ["text"] } }, configSchema: AnthropicConfigSchema }); const claude3Opus = modelRef({ name: "vertexai/claude-3-opus", info: { label: "Vertex AI Model Garden - Claude 3 Opus", versions: ["claude-3-opus@20240229"], supports: { multiturn: true, media: true, tools: true, systemRole: true, output: ["text"] } }, configSchema: AnthropicConfigSchema }); const SUPPORTED_ANTHROPIC_MODELS = { "claude-3-5-sonnet-v2": claude35SonnetV2, "claude-3-5-sonnet": claude35Sonnet, "claude-3-sonnet": claude3Sonnet, "claude-3-opus": claude3Opus, "claude-3-haiku": claude3Haiku }; function toAnthropicRequest(model, input) { let system = void 0; const messages = []; for (const msg of input.messages) { if (msg.role === "system") { system = msg.content.map((c) => { if (!c.text) { throw new Error( "Only text context is supported for system messages." ); } return c.text; }).join(); } else if (msg.content[msg.content.length - 1].toolResponse) { messages.push({ role: "user", content: toAnthropicContent(msg.content) }); } else { messages.push({ role: toAnthropicRole(msg.role), content: toAnthropicContent(msg.content) }); } } const request = { model, messages, // https://docs.anthropic.com/claude/docs/models-overview#model-comparison max_tokens: input.config?.maxOutputTokens ?? 4096 }; if (system) { request["system"] = system; } if (input.tools) { request.tools = input.tools?.map((tool) => { return { name: tool.name, description: tool.description, input_schema: tool.inputSchema }; }); } if (input.config?.stopSequences) { request.stop_sequences = input.config?.stopSequences; } if (input.config?.temperature) { request.temperature = input.config?.temperature; } if (input.config?.topK) { request.top_k = input.config?.topK; } if (input.config?.topP) { request.top_p = input.config?.topP; } return request; } function toAnthropicContent(content) { return content.map((p) => { if (p.text) { return { type: "text", text: p.text }; } if (p.media) { let b64Data = p.media.url; if (b64Data.startsWith("data:")) { b64Data = b64Data.substring(b64Data.indexOf(",") + 1); } return { type: "image", source: { type: "base64", data: b64Data, media_type: p.media.contentType } }; } if (p.toolRequest) { return toAnthropicToolRequest(p.toolRequest); } if (p.toolResponse) { return toAnthropicToolResponse(p); } throw new Error(`Unsupported content type: ${JSON.stringify(p)}`); }); } function toAnthropicRole(role) { if (role === "model") { return "assistant"; } if (role === "user") { return "user"; } if (role === "tool") { return "assistant"; } throw new Error(`Unsupported role type ${role}`); } function fromAnthropicTextPart(part) { return { text: part.text }; } function fromAnthropicToolCallPart(part) { return { toolRequest: { name: part.name, input: part.input, ref: part.id } }; } function fromAnthropicPart(part) { if (part.type === "text") return fromAnthropicTextPart(part); if (part.type === "tool_use") return fromAnthropicToolCallPart(part); throw new Error( "Part type is unsupported/corrupted. Either data is missing or type cannot be inferred from type." ); } function fromAnthropicResponse(input, response) { const parts = response.content; const message = { role: "model", content: parts.map(fromAnthropicPart) }; return { message, finishReason: toGenkitFinishReason( response.stop_reason ), custom: { id: response.id, model: response.model, type: response.type }, usage: { ...getBasicUsageStats(input.messages, message), inputTokens: response.usage.input_tokens, outputTokens: response.usage.output_tokens } }; } function toGenkitFinishReason(reason) { switch (reason) { case "end_turn": return "stop"; case "max_tokens": return "length"; case "stop_sequence": return "stop"; case "tool_use": return "stop"; case null: return "unknown"; default: return "other"; } } function toAnthropicToolRequest(tool) { if (!tool.name) { throw new Error("Tool name is required"); } if (!/^[a-zA-Z0-9_-]{1,64}$/.test(tool.name)) { throw new Error( `Tool name ${tool.name} contains invalid characters. Only letters, numbers, and underscores are allowed, and the name must be between 1 and 64 characters long.` ); } const declaration = { type: "tool_use", id: tool.ref, name: tool.name, input: tool.input }; return declaration; } function toAnthropicToolResponse(part) { if (!part.toolResponse?.ref) { throw new Error("Tool response reference is required"); } if (!part.toolResponse.output) { throw new Error("Tool response output is required"); } return { type: "tool_result", tool_use_id: part.toolResponse.ref, content: JSON.stringify(part.toolResponse.output) }; } function anthropicModel(ai, modelName, projectId, region) { const clients = {}; const clientFactory = (region2) => { if (!clients[region2]) { clients[region2] = new AnthropicVertex({ region: region2, projectId, defaultHeaders: { "X-Goog-Api-Client": GENKIT_CLIENT_HEADER } }); } return clients[region2]; }; const model = SUPPORTED_ANTHROPIC_MODELS[modelName]; if (!model) { throw new Error(`unsupported Anthropic model name ${modelName}`); } return ai.defineModel( { name: model.name, label: model.info?.label, configSchema: AnthropicConfigSchema, supports: model.info?.supports, versions: model.info?.versions }, async (input, sendChunk) => { const client = clientFactory(input.config?.location || region); if (!sendChunk) { const response = await client.messages.create({ ...toAnthropicRequest(input.config?.version ?? modelName, input), stream: false }); return fromAnthropicResponse(input, response); } else { const stream = await client.messages.stream( toAnthropicRequest(input.config?.version ?? modelName, input) ); for await (const event of stream) { if (event.type === "content_block_delta") { sendChunk({ index: 0, content: [ { text: event.delta.text } ] }); } } return fromAnthropicResponse(input, await stream.finalMessage()); } } ); } export { AnthropicConfigSchema, SUPPORTED_ANTHROPIC_MODELS, anthropicModel, claude35Sonnet, claude35SonnetV2, claude3Haiku, claude3Opus, claude3Sonnet, fromAnthropicResponse, toAnthropicRequest }; //# sourceMappingURL=anthropic.mjs.map