UNPKG

@rama-adi/watsonx-unofficial-ai-provider

Version:
1,466 lines (1,445 loc) 45.5 kB
// src/provider.ts import { loadApiKey, loadOptionalSetting, loadSetting, withoutTrailingSlash } from "@ai-sdk/provider-utils"; // src/models/chat-models/watsonx-chat-model.ts import { UnsupportedFunctionalityError as UnsupportedFunctionalityError2, InvalidResponseDataError } from "@ai-sdk/provider"; import { combineHeaders, createEventSourceResponseHandler, createJsonResponseHandler, generateId, isParsableJson, postJsonToApi } from "@ai-sdk/provider-utils"; import "zod/v4"; // src/models/chat-models/watsonx-chat-finish-reason.ts function mapWatsonxChatFinishReason(reason) { switch (reason) { case "stop": return "stop"; case "length": return "length"; case "tool_calls": return "tool-calls"; case "time_limit": return "other"; case "cancelled": return "other"; case "error": return "error"; case null: case void 0: return "unknown"; default: return "unknown"; } } // src/models/chat-models/convert-to-watsonx-chat-messages.ts import { UnsupportedFunctionalityError } from "@ai-sdk/provider"; import "@ai-sdk/provider-utils"; function convertToWatsonxChatMessages(prompt) { const messages = []; for (let i = 0; i < prompt.length; i++) { const { role, content } = prompt[i]; const isLastMessage = i === prompt.length - 1; switch (role) { case "system": { messages.push({ role: "system", content }); break; } case "user": { messages.push({ role: "user", content: content.map((part) => { switch (part.type) { case "text": { return { type: "text", text: part.text }; } case "file": { throw new UnsupportedFunctionalityError({ functionality: "File content in user messages is not supported by watsonx text chat" }); } } }) }); break; } case "assistant": { let text = ""; const toolCalls = []; for (const part of content) { switch (part.type) { case "text": { text += part.text; break; } case "tool-call": { toolCalls.push({ id: part.toolCallId, type: "function", function: { name: part.toolName, arguments: typeof part.input === "string" ? part.input : JSON.stringify(part.input) } }); break; } } } messages.push({ role: "assistant", content: text, tool_calls: toolCalls.length > 0 ? toolCalls : void 0 }); break; } case "tool": { for (const toolResponse of content) { let resultContent = ""; switch (toolResponse.output.type) { case "text": case "error-text": resultContent = toolResponse.output.value; break; case "json": case "error-json": resultContent = JSON.stringify(toolResponse.output.value); break; case "content": resultContent = JSON.stringify(toolResponse.output.value); break; } messages.push({ role: "tool", content: resultContent, tool_call_id: toolResponse.toolCallId }); } break; } default: { throw new Error(`Unsupported role: ${role}`); } } } return messages; } // src/types/watsonx-response-schema.ts import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils"; import { z } from "zod/v4"; var watsonxErrorResponseSchema = z.object({ errors: z.array( z.object({ code: z.string(), message: z.string(), more_info: z.string() }) ), trace: z.string(), status_code: z.number() }); var watsonxFailedResponseHandler = createJsonErrorResponseHandler({ errorSchema: watsonxErrorResponseSchema, errorToMessage: (data) => [ "watsonx API encountered error(s):", data.errors.map((e) => "- " + e.message), "Trace ID: " + data.trace ].join("\n") }); // src/models/chat-models/watsonx-chat-model-settings.ts var ChatModelLists = { "ca-tor": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct" ], "jp-tok": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "meta-llama/llama-guard-3-11b-vision", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "eu-gb": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8" ], "eu-de": [ "ibm/granite-3-3-8b-instruct", "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "us-south": [ "ibm/granite-3-2-8b-instruct", "ibm/granite-3-3-8b-instruct", "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-3-405b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "meta-llama/llama-guard-3-11b-vision", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503", "openai/gpt-oss-120b" ], "au-syd": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-guard-3-11b-vision" ] }; var VisionModelLists = { "ca-tor": ["meta-llama/llama-3-2-11b-vision-instruct"], "jp-tok": [ "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "meta-llama/llama-guard-3-11b-vision", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "eu-gb": [ "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8" ], "eu-de": [ "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "us-south": [ "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "meta-llama/llama-guard-3-11b-vision", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "au-syd": [ "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-guard-3-11b-vision" ] }; var FunctionCallingModelLists = { "ca-tor": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct" ], "jp-tok": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "eu-gb": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8" ], "eu-de": [ "ibm/granite-3-3-8b-instruct", "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503" ], "us-south": [ "ibm/granite-3-2-8b-instruct", "ibm/granite-3-3-8b-instruct", "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct", "meta-llama/llama-3-3-70b-instruct", "meta-llama/llama-3-405b-instruct", "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", "mistralai/mistral-medium-2505", "mistralai/mistral-small-3-1-24b-instruct-2503", "openai/gpt-oss-120b" ], "au-syd": [ "ibm/granite-3-8b-instruct", "meta-llama/llama-3-2-11b-vision-instruct", "meta-llama/llama-3-2-90b-vision-instruct" ] }; // src/models/chat-models/watsonx-chat-schema.ts import { z as z3 } from "zod/v4"; // src/types/watsonx-common-schema.ts import { z as z2 } from "zod/v4"; var WatsonxClusters = [ "ca-tor", "jp-tok", "eu-gb", "eu-de", "us-south", "au-syd" ]; var systemDetailsSchema = z2.object({ warnings: z2.array( z2.object({ message: z2.string().optional(), id: z2.string().optional(), more_info: z2.string().optional(), additional_properties: z2.record(z2.string(), z2.unknown()).optional() }) ).optional() }).optional(); var watsonxModerationsSchema = z2.object({ hap: z2.object({ input: z2.object({ enabled: z2.boolean(), threshold: z2.number().min(0).max(1) }), output: z2.object({ enabled: z2.boolean(), threshold: z2.number().min(0).max(1) }), mask: z2.object({ remove_entity_value: z2.boolean() }) }), pii: z2.object({ input: z2.object({ enabled: z2.boolean() }), output: z2.object({ enabled: z2.boolean() }), mask: z2.object({ remove_entity_value: z2.boolean() }) }) }).optional(); // src/models/chat-models/watsonx-chat-schema.ts var watsonxChatChunkSchema = z3.object({ id: z3.string().nullish(), model_id: z3.string().nullish(), created: z3.number().nullish(), choices: z3.array( z3.object({ delta: z3.object({ role: z3.enum(["assistant"]).optional(), content: z3.string().nullish(), tool_calls: z3.array( z3.object({ index: z3.number(), id: z3.string().optional(), type: z3.literal("function").nullish(), function: z3.object({ name: z3.string(), arguments: z3.string() }) }) ).nullish() }), finish_reason: z3.enum([ "stop", "length", "tool_calls", "time_limit", "cancelled", "error" ]).nullish(), index: z3.number() }) ), model_version: z3.string().nullish(), created_at: z3.string().nullish(), usage: z3.object({ prompt_tokens: z3.number(), completion_tokens: z3.number(), total_tokens: z3.number() }).nullish(), system: systemDetailsSchema }); var watsonxChatResponseSchema = z3.object({ id: z3.string(), model_id: z3.string(), created: z3.number(), choices: z3.array( z3.object({ message: z3.object({ role: z3.literal("assistant"), content: z3.string().nullish(), refusal: z3.string().nullish(), tool_calls: z3.array( z3.object({ id: z3.string(), type: z3.literal("function"), function: z3.object({ name: z3.string(), arguments: z3.string() }) }) ).nullish() }), index: z3.number(), finish_reason: z3.enum([ "stop", "length", "tool_calls", "time_limit", "cancelled", "error" ]) }) ), model_version: z3.string().nullish(), created_at: z3.string(), usage: z3.object({ prompt_tokens: z3.number(), completion_tokens: z3.number(), total_tokens: z3.number() }), system: systemDetailsSchema }); // src/models/chat-models/watsonx-chat-model.ts var WatsonxChatModel = class { specificationVersion = "v2"; provider; defaultObjectGenerationMode = "tool"; supportsImageUrls = false; supportedUrls = {}; modelId; settings; config; constructor(modelId, settings, config) { this.modelId = modelId; this.settings = settings; this.config = config; this.provider = config.provider; } sanityCheck(options) { if (options.tools?.length && !Object.values(FunctionCallingModelLists).some( (models) => models.includes(this.modelId) )) { throw new UnsupportedFunctionalityError2({ functionality: "Tool calling", message: `The model ${this.modelId} does not support tool calling` }); } } getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, stopSequences, responseFormat, seed, tools, toolChoice, providerOptions }) { const warnings = []; if (topK != null) { warnings.push({ type: "unsupported-setting", setting: "topK" }); } const requestedN = providerOptions?.watsonx?.n; let nArg = void 0; if (typeof requestedN === "number") { if (requestedN !== 1) { warnings.push({ type: "unsupported-setting", setting: "n" }); } nArg = 1; } const topLogprobs = providerOptions?.watsonx?.topLogprobs; const topLogprobsNum = typeof topLogprobs === "number" ? topLogprobs : void 0; const requestedLogprobs = providerOptions?.watsonx?.logprobs; const requestedLogprobsBool = typeof requestedLogprobs === "boolean" ? requestedLogprobs : void 0; const requestedContext = providerOptions?.watsonx?.context; const requestedContextStr = typeof requestedContext === "string" ? requestedContext : void 0; const baseArgs = { temperature, model_id: this.modelId, project_id: this.config.projectID, frequency_penalty: frequencyPenalty, // IBM watsonx prefers max_completion_tokens; max_tokens is deprecated ...maxOutputTokens != null ? { max_completion_tokens: maxOutputTokens } : {}, presence_penalty: presencePenalty, top_p: topP, seed, messages: convertToWatsonxChatMessages(prompt), time_limit: providerOptions?.watsonx?.timeLimit, // OpenAPI optional parameters supported via providerOptions.watsonx ...typeof providerOptions?.watsonx?.maxCompletionTokens === "number" ? { max_completion_tokens: providerOptions.watsonx.maxCompletionTokens } : {}, ...requestedLogprobsBool != null ? { logprobs: requestedLogprobsBool } : topLogprobsNum != null ? { logprobs: true } : {}, ...topLogprobsNum != null ? { top_logprobs: topLogprobsNum } : {}, ...providerOptions?.watsonx?.logitBias != null ? { logit_bias: providerOptions.watsonx.logitBias } : {}, ...nArg != null ? { n: nArg } : {}, ...providerOptions?.watsonx?.spaceId != null ? { space_id: providerOptions.watsonx.spaceId } : {}, ...requestedContextStr != null ? { context: requestedContextStr } : {}, ...stopSequences != null ? { stop: stopSequences } : {} }; if (responseFormat?.type === "json") { return { args: { ...baseArgs, response_format: { type: "json_object" } }, warnings }; } if (tools && tools.length > 0) { const mappedTools = tools.filter((tool) => tool.type === "function").map((tool) => ({ type: "function", function: { name: tool.name, description: tool.description, parameters: tool.inputSchema } })); let tool_choice_option = void 0; let tool_choice = void 0; if (toolChoice?.type === "tool") { tool_choice = { type: "function", function: { name: toolChoice.toolName } }; } else if (toolChoice?.type === "auto") { tool_choice_option = "auto"; } else if (toolChoice?.type === "required") { if (mappedTools.length === 1) { tool_choice = { type: "function", function: { name: mappedTools[0].function.name } }; } else { warnings.push({ type: "unsupported-setting", setting: "toolChoice.required" }); tool_choice_option = "auto"; } } return { args: { ...baseArgs, tools: mappedTools, tool_choice_option, tool_choice }, warnings }; } return { args: baseArgs, warnings }; } async doGenerate(options) { this.sanityCheck(options); const { args, warnings } = this.getArgs(options); const { value: response, responseHeaders } = await postJsonToApi({ url: `${this.config.clusterURL}/text/chat?version=${this.config.version}`, headers: combineHeaders(this.config.headers(), options.headers), body: args, failedResponseHandler: watsonxFailedResponseHandler, successfulResponseHandler: createJsonResponseHandler( watsonxChatResponseSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const choice = response.choices[0]; if (!choice) { throw new Error("No choice in response"); } const content = []; if (choice.message.content) { content.push({ type: "text", text: choice.message.content }); } if (choice.message.tool_calls) { for (const toolCall of choice.message.tool_calls) { content.push({ type: "tool-call", toolCallId: toolCall.id, toolName: toolCall.function.name, input: toolCall.function.arguments }); } } return { content, finishReason: mapWatsonxChatFinishReason(choice.finish_reason), usage: { inputTokens: response.usage.prompt_tokens, outputTokens: response.usage.completion_tokens, totalTokens: response.usage.total_tokens }, warnings, request: { body: args }, response: { id: response.id, modelId: response.model_id, headers: responseHeaders } }; } async doStream(options) { this.sanityCheck(options); const { args, warnings } = this.getArgs(options); const url = `${this.config.clusterURL}/text/chat_stream?version=${this.config.version}`; const body = { ...args }; const { value: response, responseHeaders } = await postJsonToApi({ url, headers: combineHeaders(this.config.headers(), options.headers), body, failedResponseHandler: watsonxFailedResponseHandler, successfulResponseHandler: createEventSourceResponseHandler( watsonxChatChunkSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const toolCalls = []; let finishReason = "other"; const usage = { inputTokens: Number.NaN, outputTokens: Number.NaN, totalTokens: Number.NaN }; let chunkNumber = 0; let textStarted = false; let textId; let watsonxResponseId; let trimLeadingSpace = false; return { stream: response.pipeThrough( new TransformStream({ transform(chunk, controller) { if (!chunk.success) { finishReason = "error"; controller.enqueue({ type: "error", error: chunk.error }); return; } chunkNumber++; const value = chunk.value; if (value.id) { watsonxResponseId = value.id; controller.enqueue({ type: "response-metadata", id: value.id }); } if (value.model_id) { controller.enqueue({ type: "response-metadata", modelId: value.model_id }); } if (value.usage != null) { usage.inputTokens = value.usage.prompt_tokens; usage.outputTokens = value.usage.completion_tokens; usage.totalTokens = value.usage.total_tokens; } const choice = value.choices[0]; if (!choice) { return; } if (choice?.finish_reason != null) { finishReason = mapWatsonxChatFinishReason(choice.finish_reason); } if (choice?.delta == null) { return; } const delta = choice.delta; const textContent = delta.content ?? ""; if (chunkNumber <= 2) { const messages = convertToWatsonxChatMessages(options.prompt); const lastMessage = messages[messages.length - 1]; if (lastMessage?.role === "assistant" && lastMessage.content && textContent === lastMessage.content.trimEnd()) { if (textContent.length < lastMessage.content.length) { trimLeadingSpace = true; } return; } } if (textContent != null && textContent !== "") { if (!textStarted) { textId = watsonxResponseId || generateId(); controller.enqueue({ type: "text-start", id: textId }); textStarted = true; } controller.enqueue({ type: "text-delta", delta: trimLeadingSpace ? textContent.trimStart() : textContent, id: textId || generateId() }); trimLeadingSpace = false; } if (delta.tool_calls != null) { for (const toolCallDelta of delta.tool_calls) { const index = toolCallDelta.index ?? toolCalls.length - 1; if (toolCalls[index] == null) { if (toolCallDelta.type !== "function") { throw new InvalidResponseDataError({ data: toolCallDelta, message: `Expected 'function' type.` }); } const toolCallId = toolCallDelta.id ?? generateId(); if (toolCallDelta.function?.name == null) { throw new InvalidResponseDataError({ data: toolCallDelta, message: `Expected 'function.name' to be a string.` }); } toolCalls[index] = { id: toolCallId, type: "function", function: { name: toolCallDelta.function.name, arguments: toolCallDelta.function.arguments ?? "" }, inputStarted: false, sent: false }; const toolCall2 = toolCalls[index]; if (toolCall2 == null) { throw new Error("Tool call is missing"); } if (toolCall2.function?.name != null && toolCall2.function?.arguments != null && isParsableJson(toolCall2.function.arguments)) { toolCall2.inputStarted = true; controller.enqueue({ type: "tool-input-start", id: toolCall2.id, toolName: toolCall2.function.name }); controller.enqueue({ type: "tool-input-delta", id: toolCall2.id, delta: toolCall2.function.arguments }); controller.enqueue({ type: "tool-input-end", id: toolCall2.id }); controller.enqueue({ type: "tool-call", toolCallId: toolCall2.id, toolName: toolCall2.function.name, input: toolCall2.function.arguments }); toolCall2.sent = true; } continue; } const toolCall = toolCalls[index]; if (toolCall == null) { throw new Error("Tool call is missing"); } if (!toolCall.inputStarted) { toolCall.inputStarted = true; controller.enqueue({ type: "tool-input-start", id: toolCall.id, toolName: toolCall.function.name }); } if (toolCallDelta.function?.arguments != null) { toolCall.function.arguments += toolCallDelta.function?.arguments ?? ""; } controller.enqueue({ type: "tool-input-delta", id: toolCall.id, delta: toolCallDelta.function.arguments ?? "" }); if (toolCall.function?.name != null && toolCall.function?.arguments != null && isParsableJson(toolCall.function.arguments)) { controller.enqueue({ type: "tool-call", toolCallId: toolCall.id ?? generateId(), toolName: toolCall.function.name, input: toolCall.function.arguments }); toolCall.sent = true; } } } }, flush(controller) { if (finishReason === "tool-calls") { for (const toolCall of toolCalls) { if (toolCall && !toolCall.sent) { controller.enqueue({ type: "tool-call", toolCallId: toolCall.id ?? generateId(), toolName: toolCall.function.name, // Coerce invalid arguments to an empty JSON object input: isParsableJson(toolCall.function.arguments) ? toolCall.function.arguments : "{}" }); toolCall.sent = true; } } } if (textStarted) { controller.enqueue({ type: "text-end", id: textId || generateId() }); } controller.enqueue({ type: "finish", finishReason, usage }); } }) ), warnings, request: { body }, response: { headers: responseHeaders } }; } }; // src/models/embedding-models/watsonx-embedding-model.ts import { TooManyEmbeddingValuesForCallError } from "@ai-sdk/provider"; import { combineHeaders as combineHeaders2, createJsonResponseHandler as createJsonResponseHandler2, postJsonToApi as postJsonToApi2 } from "@ai-sdk/provider-utils"; import { z as z5 } from "zod/v4"; var WatsonxEmbeddingModel = class { config; specificationVersion = "v2"; modelId; settings; get provider() { return this.config.provider; } get maxEmbeddingsPerCall() { return this.settings.maxEmbeddingsPerCall ?? 32; } get supportsParallelCalls() { return this.settings.supportsParallelCalls ?? false; } constructor(modelId, settings, config) { this.modelId = modelId; this.settings = settings; this.config = config; } #WatsonxTextEmbeddingResponseSchema = z5.object({ model_id: z5.string(), results: z5.array( z5.object({ embedding: z5.array(z5.number()), input: z5.object({ text: z5.string() }).nullish() }) ), created_at: z5.string(), input_token_count: z5.number(), system: systemDetailsSchema }); async doEmbed({ values, abortSignal, headers }) { if (values.length > this.maxEmbeddingsPerCall) { throw new TooManyEmbeddingValuesForCallError({ provider: this.provider, modelId: this.modelId, maxEmbeddingsPerCall: this.maxEmbeddingsPerCall, values }); } const { responseHeaders, value: response } = await postJsonToApi2({ url: `${this.config.clusterURL}/text/embeddings?version=${this.config.version}`, headers: combineHeaders2(this.config.headers(), headers), body: { model_id: this.modelId, project_id: this.config.projectID, inputs: values, encoding_format: "float", ...this.settings.truncate_input_tokens != null || this.settings.return_options != null ? { parameters: { ...this.settings.truncate_input_tokens != null ? { truncate_input_tokens: this.settings.truncate_input_tokens } : {}, ...this.settings.return_options != null ? { return_options: this.settings.return_options } : {} } } : {} }, failedResponseHandler: watsonxFailedResponseHandler, successfulResponseHandler: createJsonResponseHandler2( this.#WatsonxTextEmbeddingResponseSchema ), abortSignal, fetch: this.config.fetch }); return { embeddings: response.results.map((r) => r.embedding), usage: { tokens: response.input_token_count }, response: { headers: responseHeaders } }; } }; // src/models/completion-models/watsonx-completion-model.ts import "@ai-sdk/provider"; import { combineHeaders as combineHeaders3, createEventSourceResponseHandler as createEventSourceResponseHandler2, createJsonResponseHandler as createJsonResponseHandler3, postJsonToApi as postJsonToApi3, generateId as generateId2 } from "@ai-sdk/provider-utils"; import "zod/v4"; // src/models/completion-models/convert-to-watsonx-completion.ts import { InvalidPromptError, UnsupportedFunctionalityError as UnsupportedFunctionalityError3 } from "@ai-sdk/provider"; function convertToWatsonxCompletion({ prompt, inputFormat, user = "user", assistant = "assistant" }) { if (inputFormat === "prompt" && prompt.length === 1 && prompt[0].role === "user" && prompt[0].content.length === 1 && prompt[0].content[0].type === "text") { return { prompt: prompt[0].content[0].text }; } let text = ""; if (prompt[0].role === "system") { text += `${prompt[0].content} `; prompt = prompt.slice(1); } for (const { role, content } of prompt) { switch (role) { case "system": { throw new InvalidPromptError({ message: "Unexpected system message in prompt: ${content}", prompt }); } case "user": { const userMessage = content.map((part) => { switch (part.type) { case "text": { return part.text; } case "file": { throw new UnsupportedFunctionalityError3({ functionality: "file" }); } } }).join(""); text += `${user}: ${userMessage} `; break; } case "assistant": { const assistantMessage = content.map((part) => { switch (part.type) { case "text": { return part.text; } case "tool-call": { throw new UnsupportedFunctionalityError3({ functionality: "tool-call messages" }); } } }).join(""); text += `${assistant}: ${assistantMessage} `; break; } case "tool": { throw new UnsupportedFunctionalityError3({ functionality: "tool messages" }); } default: { throw new Error(`Unsupported role: ${role}`); } } } text += `${assistant}: `; return { prompt: text, stopSequences: [` ${user}:`] }; } // src/models/completion-models/watsonx-completion-schema.ts import { z as z6 } from "zod/v4"; var textgenTokenInfo = z6.array( z6.object({ text: z6.string(), logprob: z6.number(), rank: z6.number(), top_tokens: z6.array( z6.object({ text: z6.string(), logprob: z6.number() }) ) }) ); var watsonxCompletionChunkSchema = z6.object({ id: z6.string().nullish(), model_id: z6.string().nullish(), created: z6.number().nullish(), results: z6.array( z6.object({ generated_text: z6.string(), stop_reason: z6.string(), generated_token_count: z6.number().nullish(), input_token_count: z6.number().nullish(), seed: z6.number().nullish(), generated_tokens: textgenTokenInfo.optional(), input_tokens: textgenTokenInfo.optional(), moderations: watsonxModerationsSchema }) ), model_version: z6.string().nullish(), created_at: z6.string().nullish(), usage: z6.object({ prompt_tokens: z6.number(), completion_tokens: z6.number(), total_tokens: z6.number() }).nullish(), system: systemDetailsSchema }); var watsonxCompletionResponseSchema = z6.object({ id: z6.string().nullish(), model_id: z6.string(), model_version: z6.string().nullish(), created_at: z6.string(), results: z6.array( z6.object({ generated_text: z6.string(), stop_reason: z6.string(), generated_token_count: z6.number(), input_token_count: z6.number(), seed: z6.number().nullish(), generated_tokens: textgenTokenInfo.optional(), input_tokens: textgenTokenInfo.optional(), moderations: watsonxModerationsSchema }) ), usage: z6.object({ prompt_tokens: z6.number(), completion_tokens: z6.number(), total_tokens: z6.number() }).nullish(), system: systemDetailsSchema }); // src/models/completion-models/watsonx-completion-finish-reason.ts function mapWatsonxCompletionFinishReason(reason) { switch (reason) { case "not_finished": return "other"; case "max_tokens": case "token_limit": return "length"; case "eos_token": case "stop_sequence": return "stop"; case "cancelled": return "stop"; case "time_limit": return "unknown"; case "error": return "error"; case null: case void 0: return "unknown"; default: return "unknown"; } } // src/models/completion-models/watsonx-completion-model.ts var WatsonxCompletionModel = class { specificationVersion = "v2"; provider; defaultObjectGenerationMode = void 0; supportsImageUrls = false; supportedUrls = {}; modelId; settings; config; constructor(modelId, settings, config) { this.modelId = modelId; this.settings = settings; this.config = config; this.provider = config.provider; } getArgs(options) { const { prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, stopSequences: userStopSequences, responseFormat, seed, providerOptions } = options; const warnings = []; if (responseFormat != null && responseFormat.type !== "text") { warnings.push({ type: "unsupported-setting", setting: "responseFormat" }); } const { prompt: completionPrompt, stopSequences } = convertToWatsonxCompletion({ prompt, inputFormat: "prompt" }); const stop = [...stopSequences ?? [], ...userStopSequences ?? []]; const baseArgs = { model_id: this.modelId, project_id: this.config.projectID, input: completionPrompt, parameters: { // sampling & decoding decoding_method: this.settings.decodingMethod ?? "greedy", temperature, top_p: topP, top_k: topK, // penalties and limits frequency_penalty: frequencyPenalty, presence_penalty: presencePenalty, max_new_tokens: maxOutputTokens ?? this.settings.maxNewTokens, min_new_tokens: this.settings.minNewTokens, // control & misc stop_sequences: stop, random_seed: seed, time_limit: providerOptions?.watsonx?.timeLimit, ...this.settings.textgenLengthPenalty !== void 0 ? { length_penalty: { decay_factor: this.settings.textgenLengthPenalty.decayFactor, start_index: this.settings.textgenLengthPenalty.startIndex } } : {} }, return_options: { input_text: this.settings.returnOptions?.inputText ?? false, generated_tokens: this.settings.returnOptions?.generatedTokens ?? false } }; return { args: baseArgs, warnings }; } async doGenerate(options) { const { args, warnings } = this.getArgs(options); const { responseHeaders, value: response, rawValue: rawResponse } = await postJsonToApi3({ url: `${this.config.clusterURL}/text/generation?version=${this.config.version}`, headers: combineHeaders3(this.config.headers(), options.headers), body: args, failedResponseHandler: watsonxFailedResponseHandler, successfulResponseHandler: createJsonResponseHandler3( watsonxCompletionResponseSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const { messages: rawPrompt, ...rawSettings } = args; const choice = response.results[0]; if (!choice) { throw new Error("No choice in response"); } return { content: [ { type: "text", text: choice.generated_text } ], finishReason: mapWatsonxCompletionFinishReason(choice.stop_reason), usage: { inputTokens: response.usage?.prompt_tokens ?? NaN, outputTokens: response.usage?.completion_tokens ?? NaN, totalTokens: (response.usage?.prompt_tokens ?? 0) + (response.usage?.completion_tokens ?? 0) }, warnings, request: { body: args }, response: { id: generateId2(), modelId: response.model_id, headers: responseHeaders, body: rawResponse } }; } async doStream(options) { const url = `${this.config.clusterURL}/text/generation_stream?version=${this.config.version}`; const { args, warnings } = this.getArgs(options); const body = { ...args, stream: true }; const { value: response, responseHeaders } = await postJsonToApi3({ url, headers: combineHeaders3(this.config.headers(), options.headers), body, failedResponseHandler: watsonxFailedResponseHandler, successfulResponseHandler: createEventSourceResponseHandler2( watsonxCompletionChunkSchema ), abortSignal: options.abortSignal, fetch: this.config.fetch }); let finishReason = "other"; let usage = { inputTokens: Number.NaN, outputTokens: Number.NaN, totalTokens: Number.NaN }; let isFirstChunk = true; return { stream: response.pipeThrough( new TransformStream({ transform(chunk, controller) { if (!chunk.success) { finishReason = "error"; controller.enqueue({ type: "error", error: chunk.error }); return; } const value = chunk.value; if ("error" in value) { finishReason = "error"; controller.enqueue({ type: "error", error: value.error }); return; } if (isFirstChunk) { isFirstChunk = false; controller.enqueue({ type: "response-metadata", id: value.id ?? generateId2(), modelId: value.model_id ?? void 0, timestamp: value.created != null ? new Date(value.created * 1e3) : void 0 }); } if (value.usage != null) { usage = { inputTokens: value.usage.prompt_tokens, outputTokens: value.usage.completion_tokens, totalTokens: value.usage.prompt_tokens + value.usage.completion_tokens }; } const choice = value.results[0]; if (choice?.stop_reason != null) { finishReason = mapWatsonxCompletionFinishReason( choice.stop_reason ); } if (choice?.generated_text != null) { controller.enqueue({ type: "text-delta", id: generateId2(), delta: choice.generated_text }); } }, flush(controller) { controller.enqueue({ type: "finish", finishReason, usage }); } }) ), warnings, request: { body }, response: { headers: responseHeaders } }; } }; // src/provider.ts function createWatsonx(options = {}) { const clusterURL = loadOptionalSetting({ settingValue: options.clusterURL, environmentVariableName: "WATSONX_CLUSTER_URL" }) ?? (() => { const cluster = loadSetting({ settingValue: options.cluster, settingName: "cluster", environmentVariableName: "WATSONX_CLUSTER", description: "The IBM watsonx Cluster" }); return `${withoutTrailingSlash(`https://${cluster}.ml.cloud.ibm.com`)}/ml/v1`; })(); const projectID = loadSetting({ settingValue: options.projectID, settingName: "projectID", environmentVariableName: "WATSONX_PROJECT_ID", description: "The IBM watsonx Project ID" }); const getHeaders = () => ({ Authorization: `Bearer ${loadApiKey({ apiKey: options.bearerToken, environmentVariableName: "WATSONX_BEARER_TOKEN", description: "Watsonx" })}`, ...options.headers }); const createChatModel = (modelId, settings = {}) => new WatsonxChatModel(modelId, settings, { provider: "watsonx.chat", clusterURL, projectID, headers: getHeaders, fetch: options.fetch, version: "2024-02-13" }); const createEmbeddingModel = (modelId, settings = {}) => new WatsonxEmbeddingModel(modelId, settings, { provider: "watsonx.embedding", clusterURL, projectID, headers: getHeaders, fetch: options.fetch, version: "2024-02-13" }); const createCompletionModel = (modelId, settings = {}) => new WatsonxCompletionModel(modelId, settings, { provider: "watsonx.completion", clusterURL, projectID, headers: getHeaders, fetch: options.fetch, version: "2024-02-13" }); const provider = function(modelId, settings) { if (new.target) { throw new Error( "The watsonx model function cannot be called with the new keyword." ); } return createChatModel(modelId, settings); }; provider.languageModel = (modelId, settings) => createChatModel(modelId, settings); provider.embedding = (modelId, settings) => createEmbeddingModel(modelId, settings); provider.textEmbeddingModel = (modelId, settings) => createEmbeddingModel(modelId, settings); provider.textEmbedding = (modelId, settings) => createEmbeddingModel(modelId, settings); provider.completion = (modelId, settings) => createCompletionModel(modelId, settings); provider.imageModel = () => { throw new Error("Image models are not supported by watsonx provider"); }; return provider; } var watsonx = createWatsonx(); // src/models/embedding-models/watsonx-embedding-model-settings.ts var EmbedingModelLists = { "ca-tor": [ "ibm/granite-embedding-278m-multilingual", "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large" ], "jp-tok": [ "ibm/granite-embedding-278m-multilingual", "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large", "sentence-transformers/all-minilm-l6-v2" ], "eu-gb": [ "ibm/granite-embedding-278m-multilingual", "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large", "sentence-transformers/all-minilm-l6-v2" ], "eu-de": [ "ibm/granite-embedding-278m-multilingual", "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large", "sentence-transformers/all-minilm-l6-v2" ], "us-south": [ "ibm/granite-embedding-278m-multilingual", "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large", "sentence-transformers/all-minilm-l6-v2" ], "au-syd": [ "ibm/slate-125m-english-rtrvr-v2", "ibm/slate-30m-english-rtrvr-v2", "intfloat/multilingual-e5-large" ] }; // src/models/completion-models/watsonx-completion-model-settings.ts var CompletionModelLists = { "ca-tor": [], "jp-tok": [], "eu-gb": [], "eu-de": ["sdaia/allam-1-13b-instruct"], "us-south": ["ibm/granite-8b-code-instruct"], "au-syd": ["ibm/granite-8b-code-instruct"] }; export { ChatModelLists, CompletionModelLists, EmbedingModelLists, FunctionCallingModelLists, VisionModelLists, WatsonxClusters, createWatsonx, watsonx }; //# sourceMappingURL=index.mjs.map