anthropic-vertex-ai
Version:
[nalaso/anthropic-vertex-ai](https://github.com/nalaso/anthropic-vertex-ai) is a community provider that uses Anthropic models through Vertex AI to provide language model support for the Vercel AI SDK.
689 lines (681 loc) • 23.3 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
anthropicVertex: () => anthropicVertex,
createAnthropicVertex: () => createAnthropicVertex
});
module.exports = __toCommonJS(src_exports);
// src/anthropic-vertex-provider.ts
var import_provider_utils4 = require("@ai-sdk/provider-utils");
var import_google_auth_library = require("google-auth-library");
// src/anthropic-messages-language-model.ts
var import_provider2 = require("@ai-sdk/provider");
var import_provider_utils3 = require("@ai-sdk/provider-utils");
var import_zod2 = require("zod");
// src/anthropic-error.ts
var import_provider_utils = require("@ai-sdk/provider-utils");
var import_zod = require("zod");
var anthropicErrorDataSchema = import_zod.z.object({
type: import_zod.z.literal("error"),
error: import_zod.z.object({
type: import_zod.z.string(),
message: import_zod.z.string()
})
});
var anthropicFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
errorSchema: anthropicErrorDataSchema,
errorToMessage: (data) => data.error.message
});
// src/convert-to-anthropic-messages-prompt.ts
var import_provider = require("@ai-sdk/provider");
var import_provider_utils2 = require("@ai-sdk/provider-utils");
function convertToAnthropicMessagesPrompt(prompt) {
var _a;
const blocks = groupIntoBlocks(prompt);
let system = void 0;
const messages = [];
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
const type = block.type;
switch (type) {
case "system": {
if (system != null) {
throw new import_provider.UnsupportedFunctionalityError({
functionality: "Multiple system messages that are separated by user/assistant messages"
});
}
system = block.messages.map(({ content }) => content).join("\n");
break;
}
case "user": {
const anthropicContent = [];
for (const { role, content } of block.messages) {
switch (role) {
case "user": {
for (const part of content) {
switch (part.type) {
case "text": {
anthropicContent.push({ type: "text", text: part.text });
break;
}
case "image": {
if (part.image instanceof URL) {
throw new import_provider.UnsupportedFunctionalityError({
functionality: "Image URLs in user messages"
});
}
anthropicContent.push({
type: "image",
source: {
type: "base64",
media_type: (_a = part.mimeType) != null ? _a : "image/jpeg",
data: (0, import_provider_utils2.convertUint8ArrayToBase64)(part.image)
}
});
break;
}
}
}
break;
}
case "tool": {
for (const part of content) {
anthropicContent.push({
type: "tool_result",
tool_use_id: part.toolCallId,
content: JSON.stringify(part.result),
is_error: part.isError
});
}
break;
}
default: {
const _exhaustiveCheck = role;
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
}
}
}
messages.push({ role: "user", content: anthropicContent });
break;
}
case "assistant": {
if (block.messages.length > 1) {
throw new import_provider.UnsupportedFunctionalityError({
functionality: "Multiple assistant messages in block"
});
}
const { content } = block.messages[0];
messages.push({
role: "assistant",
content: content.map((part, j) => {
switch (part.type) {
case "text": {
if (i === blocks.length - 1 && j === block.messages.length - 1) {
return { type: "text", text: part.text.trim() };
}
return { type: "text", text: part.text };
}
case "tool-call": {
return {
type: "tool_use",
id: part.toolCallId,
name: part.toolName,
input: part.args
};
}
}
})
});
break;
}
default: {
const _exhaustiveCheck = type;
throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
}
}
}
return {
system,
messages
};
}
function groupIntoBlocks(prompt) {
const blocks = [];
let currentBlock = void 0;
for (const { role, content } of prompt) {
switch (role) {
case "system": {
if ((currentBlock == null ? void 0 : currentBlock.type) !== "system") {
currentBlock = { type: "system", messages: [] };
blocks.push(currentBlock);
}
currentBlock.messages.push({ role, content });
break;
}
case "assistant": {
if ((currentBlock == null ? void 0 : currentBlock.type) !== "assistant") {
currentBlock = { type: "assistant", messages: [] };
blocks.push(currentBlock);
}
currentBlock.messages.push({ role, content });
break;
}
case "user": {
if ((currentBlock == null ? void 0 : currentBlock.type) !== "user") {
currentBlock = { type: "user", messages: [] };
blocks.push(currentBlock);
}
currentBlock.messages.push({ role, content });
break;
}
case "tool": {
if ((currentBlock == null ? void 0 : currentBlock.type) !== "user") {
currentBlock = { type: "user", messages: [] };
blocks.push(currentBlock);
}
currentBlock.messages.push({ role, content });
break;
}
default: {
const _exhaustiveCheck = role;
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
}
}
}
return blocks;
}
// src/map-anthropic-stop-reason.ts
function mapAnthropicStopReason(finishReason) {
switch (finishReason) {
case "end_turn":
case "stop_sequence":
return "stop";
case "tool_use":
return "tool-calls";
case "max_tokens":
return "length";
default:
return "other";
}
}
// src/anthropic-messages-language-model.ts
var AnthropicMessagesLanguageModel = class {
constructor(modelId, settings, config) {
this.specificationVersion = "v1";
this.defaultObjectGenerationMode = "tool";
this.supportsImageUrls = false;
this.defaultVersion = "vertex-2023-10-16";
this.modelId = modelId;
this.settings = settings;
this.config = config;
this.path = `/projects/${config.projectId}/locations/${config.region}/publishers/anthropic/models/${modelId}`;
}
get provider() {
return this.config.provider;
}
async getArgs({
mode,
prompt,
maxTokens,
temperature,
topP,
topK,
frequencyPenalty,
presencePenalty,
stopSequences,
responseFormat,
seed
}) {
const type = mode.type;
const warnings = [];
if (frequencyPenalty != null) {
warnings.push({
type: "unsupported-setting",
setting: "frequencyPenalty"
});
}
if (presencePenalty != null) {
warnings.push({
type: "unsupported-setting",
setting: "presencePenalty"
});
}
if (seed != null) {
warnings.push({
type: "unsupported-setting",
setting: "seed"
});
}
if (responseFormat != null && responseFormat.type !== "text") {
warnings.push({
type: "unsupported-setting",
setting: "responseFormat",
details: "JSON response format is not supported."
});
}
const messagesPrompt = convertToAnthropicMessagesPrompt(prompt);
const baseArgs = {
anthropic_version: this.defaultVersion,
// model specific settings:
top_k: topK != null ? topK : this.settings.topK,
// standardized settings:
max_tokens: maxTokens != null ? maxTokens : 4096,
// 4096: max model output tokens
temperature,
top_p: topP,
stop_sequences: stopSequences,
// prompt:
system: messagesPrompt.system,
messages: messagesPrompt.messages
};
switch (type) {
case "regular": {
return {
args: { ...baseArgs, ...prepareToolsAndToolChoice(mode) },
warnings
};
}
case "object-json": {
throw new import_provider2.UnsupportedFunctionalityError({
functionality: "json-mode object generation"
});
}
case "object-tool": {
const { name, description, parameters } = mode.tool;
return {
args: {
...baseArgs,
tools: [{ name, description, input_schema: parameters }],
tool_choice: { type: "tool", name }
},
warnings
};
}
default: {
const _exhaustiveCheck = type;
throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
}
}
}
async doGenerate(options) {
var _a;
const { args, warnings } = await this.getArgs(options);
const authClient = await ((_a = this.config.googleAuth) == null ? void 0 : _a.getClient());
const authHeaders = await (authClient == null ? void 0 : authClient.getRequestHeaders());
options.headers = { ...authHeaders, ...options.headers };
const specifier = "rawPredict";
const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
url: `${this.config.baseURL}${this.path}:${specifier}`,
headers: (0, import_provider_utils3.combineHeaders)(this.config.headers(), options.headers),
body: args,
failedResponseHandler: anthropicFailedResponseHandler,
successfulResponseHandler: (0, import_provider_utils3.createJsonResponseHandler)(
anthropicMessagesResponseSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const { messages: rawPrompt, ...rawSettings } = args;
let text = "";
for (const content of response.content) {
if (content.type === "text") {
text += content.text;
}
}
let toolCalls = void 0;
if (response.content.some((content) => content.type === "tool_use")) {
toolCalls = [];
for (const content of response.content) {
if (content.type === "tool_use") {
toolCalls.push({
toolCallType: "function",
toolCallId: content.id,
toolName: content.name,
args: JSON.stringify(content.input)
});
}
}
}
return {
text,
toolCalls,
finishReason: mapAnthropicStopReason(response.stop_reason),
usage: {
promptTokens: response.usage.input_tokens,
completionTokens: response.usage.output_tokens
},
rawCall: { rawPrompt, rawSettings },
rawResponse: { headers: responseHeaders },
warnings
};
}
async doStream(options) {
var _a;
const { args, warnings } = await this.getArgs(options);
const authClient = await ((_a = this.config.googleAuth) == null ? void 0 : _a.getClient());
const authHeaders = await (authClient == null ? void 0 : authClient.getRequestHeaders());
options.headers = { ...authHeaders, ...options.headers };
const specifier = "streamRawPredict";
const { responseHeaders, value: response } = await (0, import_provider_utils3.postJsonToApi)({
url: `${this.config.baseURL}${this.path}:${specifier}`,
headers: (0, import_provider_utils3.combineHeaders)(this.config.headers(), options.headers),
body: {
...args,
stream: true
},
failedResponseHandler: anthropicFailedResponseHandler,
successfulResponseHandler: (0, import_provider_utils3.createEventSourceResponseHandler)(
anthropicMessagesChunkSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const { messages: rawPrompt, ...rawSettings } = args;
let finishReason = "other";
const usage = {
promptTokens: Number.NaN,
completionTokens: Number.NaN
};
const toolCallContentBlocks = {};
return {
stream: response.pipeThrough(
new TransformStream({
transform(chunk, controller) {
if (!chunk.success) {
controller.enqueue({ type: "error", error: chunk.error });
return;
}
const value = chunk.value;
switch (value.type) {
case "ping": {
return;
}
case "content_block_start": {
const contentBlockType = value.content_block.type;
switch (contentBlockType) {
case "text": {
return;
}
case "tool_use": {
toolCallContentBlocks[value.index] = {
toolCallId: value.content_block.id,
toolName: value.content_block.name,
jsonText: ""
};
return;
}
default: {
const _exhaustiveCheck = contentBlockType;
throw new Error(
`Unsupported content block type: ${_exhaustiveCheck}`
);
}
}
}
case "content_block_stop": {
if (toolCallContentBlocks[value.index] != null) {
const contentBlock = toolCallContentBlocks[value.index];
controller.enqueue({
type: "tool-call",
toolCallType: "function",
toolCallId: contentBlock.toolCallId,
toolName: contentBlock.toolName,
args: contentBlock.jsonText
});
delete toolCallContentBlocks[value.index];
}
return;
}
case "content_block_delta": {
const deltaType = value.delta.type;
switch (deltaType) {
case "text_delta": {
controller.enqueue({
type: "text-delta",
textDelta: value.delta.text
});
return;
}
case "input_json_delta": {
const contentBlock = toolCallContentBlocks[value.index];
controller.enqueue({
type: "tool-call-delta",
toolCallType: "function",
toolCallId: contentBlock.toolCallId,
toolName: contentBlock.toolName,
argsTextDelta: value.delta.partial_json
});
contentBlock.jsonText += value.delta.partial_json;
return;
}
default: {
const _exhaustiveCheck = deltaType;
throw new Error(
`Unsupported delta type: ${_exhaustiveCheck}`
);
}
}
}
case "message_start": {
usage.promptTokens = value.message.usage.input_tokens;
usage.completionTokens = value.message.usage.output_tokens;
return;
}
case "message_delta": {
usage.completionTokens = value.usage.output_tokens;
finishReason = mapAnthropicStopReason(value.delta.stop_reason);
return;
}
case "message_stop": {
controller.enqueue({ type: "finish", finishReason, usage });
return;
}
default: {
const _exhaustiveCheck = value;
throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
}
}
}
})
),
rawCall: { rawPrompt, rawSettings },
rawResponse: { headers: responseHeaders },
warnings
};
}
};
var anthropicMessagesResponseSchema = import_zod2.z.object({
type: import_zod2.z.literal("message"),
content: import_zod2.z.array(
import_zod2.z.discriminatedUnion("type", [
import_zod2.z.object({
type: import_zod2.z.literal("text"),
text: import_zod2.z.string()
}),
import_zod2.z.object({
type: import_zod2.z.literal("tool_use"),
id: import_zod2.z.string(),
name: import_zod2.z.string(),
input: import_zod2.z.unknown()
})
])
),
stop_reason: import_zod2.z.string().optional().nullable(),
usage: import_zod2.z.object({
input_tokens: import_zod2.z.number(),
output_tokens: import_zod2.z.number()
})
});
var anthropicMessagesChunkSchema = import_zod2.z.discriminatedUnion("type", [
import_zod2.z.object({
type: import_zod2.z.literal("message_start"),
message: import_zod2.z.object({
usage: import_zod2.z.object({
input_tokens: import_zod2.z.number(),
output_tokens: import_zod2.z.number()
})
})
}),
import_zod2.z.object({
type: import_zod2.z.literal("content_block_start"),
index: import_zod2.z.number(),
content_block: import_zod2.z.discriminatedUnion("type", [
import_zod2.z.object({
type: import_zod2.z.literal("text"),
text: import_zod2.z.string()
}),
import_zod2.z.object({
type: import_zod2.z.literal("tool_use"),
id: import_zod2.z.string(),
name: import_zod2.z.string()
})
])
}),
import_zod2.z.object({
type: import_zod2.z.literal("content_block_delta"),
index: import_zod2.z.number(),
delta: import_zod2.z.discriminatedUnion("type", [
import_zod2.z.object({
type: import_zod2.z.literal("input_json_delta"),
partial_json: import_zod2.z.string()
}),
import_zod2.z.object({
type: import_zod2.z.literal("text_delta"),
text: import_zod2.z.string()
})
])
}),
import_zod2.z.object({
type: import_zod2.z.literal("content_block_stop"),
index: import_zod2.z.number()
}),
import_zod2.z.object({
type: import_zod2.z.literal("message_delta"),
delta: import_zod2.z.object({ stop_reason: import_zod2.z.string().optional().nullable() }),
usage: import_zod2.z.object({ output_tokens: import_zod2.z.number() })
}),
import_zod2.z.object({
type: import_zod2.z.literal("message_stop")
}),
import_zod2.z.object({
type: import_zod2.z.literal("ping")
})
]);
function prepareToolsAndToolChoice(mode) {
var _a;
const tools = ((_a = mode.tools) == null ? void 0 : _a.length) ? mode.tools : void 0;
if (tools == null) {
return { tools: void 0, tool_choice: void 0 };
}
const mappedTools = tools.map((tool) => ({
name: tool.name,
description: tool.description,
input_schema: tool.parameters
}));
const toolChoice = mode.toolChoice;
if (toolChoice == null) {
return { tools: mappedTools, tool_choice: void 0 };
}
const type = toolChoice.type;
switch (type) {
case "auto":
return { tools: mappedTools, tool_choice: { type: "auto" } };
case "required":
return { tools: mappedTools, tool_choice: { type: "any" } };
case "none":
return { tools: void 0, tool_choice: void 0 };
case "tool":
return {
tools: mappedTools,
tool_choice: { type: "tool", name: toolChoice.toolName }
};
default: {
const _exhaustiveCheck = type;
throw new Error(`Unsupported tool choice type: ${_exhaustiveCheck}`);
}
}
}
// src/anthropic-vertex-provider.ts
function createAnthropicVertex(options = {}) {
const getConfig = () => {
const config = {
projectId: (0, import_provider_utils4.loadSetting)({
settingValue: options.projectId,
settingName: "projectId",
environmentVariableName: "GOOGLE_VERTEX_PROJECT_ID",
description: "Google Vertex project id"
}),
region: (0, import_provider_utils4.loadSetting)({
settingValue: options.region,
settingName: "region",
environmentVariableName: "GOOGLE_VERTEX_REGION",
description: "Google Vertex region"
}),
googleAuth: options.googleAuth
};
if (!config.region) {
throw new Error(
"No region was given. The client should be instantiated with the `region` option or the `GOOGLE_VERTEX_REGION` environment variable should be set."
);
}
if (!config.projectId) {
throw new Error(
"No project was given. The client should be instantiated with the `projectID` option or the `GOOGLE_VERTEX_PROJECT_ID` environment variable should be set."
);
}
return config;
};
const createChatModel = (modelId, settings = {}) => {
var _a, _b;
const config = getConfig();
const baseURL = (_a = (0, import_provider_utils4.withoutTrailingSlash)(options.baseURL)) != null ? _a : `https://${config.region}-aiplatform.googleapis.com/v1`;
const auth = (_b = options.googleAuth) != null ? _b : new import_google_auth_library.GoogleAuth({ scopes: "https://www.googleapis.com/auth/cloud-platform" });
return new AnthropicMessagesLanguageModel(modelId, settings, {
provider: "anthropic.messages",
baseURL,
headers: () => ({
...options.headers
}),
fetch: options.fetch,
projectId: config.projectId,
region: config.region,
googleAuth: auth
});
};
const provider = function(modelId, settings) {
if (new.target) {
throw new Error(
"The Anthropic model function cannot be called with the new keyword."
);
}
return createChatModel(modelId, settings);
};
provider.languageModel = createChatModel;
provider.chat = createChatModel;
return provider;
}
var anthropicVertex = createAnthropicVertex();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
anthropicVertex,
createAnthropicVertex
});
//# sourceMappingURL=index.js.map