@jerome-benoit/sap-ai-provider 3.0.0 → 4.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -24766,7 +24766,7 @@ var require_form_data = __commonJS({
24766
24766
  var parseUrl = require("url").parse;
24767
24767
  var fs = require("fs");
24768
24768
  var Stream = require("stream").Stream;
24769
- var crypto = require("crypto");
24769
+ var crypto2 = require("crypto");
24770
24770
  var mime = require_mime_types();
24771
24771
  var asynckit = require_asynckit();
24772
24772
  var setToStringTag = require_es_set_tostringtag();
@@ -24972,7 +24972,7 @@ var require_form_data = __commonJS({
24972
24972
  return Buffer.concat([dataBuffer, Buffer.from(this._lastBoundary())]);
24973
24973
  };
24974
24974
  FormData2.prototype._generateBoundary = function() {
24975
- this._boundary = "--------------------------" + crypto.randomBytes(12).toString("hex");
24975
+ this._boundary = "--------------------------" + crypto2.randomBytes(12).toString("hex");
24976
24976
  };
24977
24977
  FormData2.prototype.getLengthSync = function() {
24978
24978
  var knownLength = this._overheadLength + this._valueLength;
@@ -26202,7 +26202,7 @@ var require_axios = __commonJS({
26202
26202
  "node_modules/axios/dist/node/axios.cjs"(exports2, module2) {
26203
26203
  "use strict";
26204
26204
  var FormData$1 = require_form_data();
26205
- var crypto = require("crypto");
26205
+ var crypto2 = require("crypto");
26206
26206
  var url = require("url");
26207
26207
  var proxyFromEnv = require_proxy_from_env();
26208
26208
  var http = require("http");
@@ -26217,7 +26217,7 @@ var require_axios = __commonJS({
26217
26217
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
26218
26218
  }
26219
26219
  var FormData__default = /* @__PURE__ */ _interopDefaultLegacy(FormData$1);
26220
- var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto);
26220
+ var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto2);
26221
26221
  var url__default = /* @__PURE__ */ _interopDefaultLegacy(url);
26222
26222
  var proxyFromEnv__default = /* @__PURE__ */ _interopDefaultLegacy(proxyFromEnv);
26223
26223
  var http__default = /* @__PURE__ */ _interopDefaultLegacy(http);
@@ -29737,22 +29737,22 @@ var require_dist = __commonJS({
29737
29737
  // src/index.ts
29738
29738
  var index_exports = {};
29739
29739
  __export(index_exports, {
29740
- OrchestrationClient: () => import_orchestration5.OrchestrationClient,
29741
- OrchestrationResponse: () => import_orchestration4.OrchestrationResponse,
29742
- OrchestrationStreamChunkResponse: () => import_orchestration4.OrchestrationStreamChunkResponse,
29743
- OrchestrationStreamResponse: () => import_orchestration4.OrchestrationStreamResponse,
29740
+ OrchestrationClient: () => import_orchestration4.OrchestrationClient,
29741
+ OrchestrationResponse: () => import_orchestration3.OrchestrationResponse,
29742
+ OrchestrationStreamChunkResponse: () => import_orchestration3.OrchestrationStreamChunkResponse,
29743
+ OrchestrationStreamResponse: () => import_orchestration3.OrchestrationStreamResponse,
29744
29744
  buildAzureContentSafetyFilter: () => import_orchestration2.buildAzureContentSafetyFilter,
29745
29745
  buildDocumentGroundingConfig: () => import_orchestration2.buildDocumentGroundingConfig,
29746
29746
  buildDpiMaskingProvider: () => import_orchestration2.buildDpiMaskingProvider,
29747
29747
  buildLlamaGuard38BFilter: () => import_orchestration2.buildLlamaGuard38BFilter,
29748
29748
  buildTranslationConfig: () => import_orchestration2.buildTranslationConfig,
29749
29749
  createSAPAIProvider: () => createSAPAIProvider,
29750
- isConfigReference: () => import_orchestration3.isConfigReference,
29750
+ isConfigReference: () => import_orchestration2.isConfigReference,
29751
29751
  sapai: () => sapai
29752
29752
  });
29753
29753
  module.exports = __toCommonJS(index_exports);
29754
29754
 
29755
- // src/sap-ai-chat-language-model.ts
29755
+ // src/sap-ai-language-model.ts
29756
29756
  var import_orchestration = require("@sap-ai-sdk/orchestration");
29757
29757
  var import_zod_to_json_schema = require("zod-to-json-schema");
29758
29758
 
@@ -29764,25 +29764,78 @@ function convertToSAPMessages(prompt, options = {}) {
29764
29764
  const includeReasoning = options.includeReasoning ?? false;
29765
29765
  for (const message of prompt) {
29766
29766
  switch (message.role) {
29767
+ case "assistant": {
29768
+ let text = "";
29769
+ const toolCalls = [];
29770
+ for (const part of message.content) {
29771
+ switch (part.type) {
29772
+ case "reasoning": {
29773
+ if (includeReasoning && part.text) {
29774
+ text += `<reasoning>${part.text}</reasoning>`;
29775
+ }
29776
+ break;
29777
+ }
29778
+ case "text": {
29779
+ text += part.text;
29780
+ break;
29781
+ }
29782
+ case "tool-call": {
29783
+ let argumentsJson;
29784
+ if (typeof part.input === "string") {
29785
+ try {
29786
+ JSON.parse(part.input);
29787
+ argumentsJson = part.input;
29788
+ } catch {
29789
+ argumentsJson = JSON.stringify(part.input);
29790
+ }
29791
+ } else {
29792
+ argumentsJson = JSON.stringify(part.input);
29793
+ }
29794
+ toolCalls.push({
29795
+ function: {
29796
+ arguments: argumentsJson,
29797
+ name: part.toolName
29798
+ },
29799
+ id: part.toolCallId,
29800
+ type: "function"
29801
+ });
29802
+ break;
29803
+ }
29804
+ }
29805
+ }
29806
+ const assistantMessage = {
29807
+ content: text || "",
29808
+ role: "assistant",
29809
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
29810
+ };
29811
+ messages.push(assistantMessage);
29812
+ break;
29813
+ }
29767
29814
  case "system": {
29768
29815
  const systemMessage = {
29769
- role: "system",
29770
- content: message.content
29816
+ content: message.content,
29817
+ role: "system"
29771
29818
  };
29772
29819
  messages.push(systemMessage);
29773
29820
  break;
29774
29821
  }
29822
+ case "tool": {
29823
+ for (const part of message.content) {
29824
+ if (part.type === "tool-result") {
29825
+ const toolMessage = {
29826
+ content: JSON.stringify(part.output),
29827
+ role: "tool",
29828
+ tool_call_id: part.toolCallId
29829
+ };
29830
+ messages.push(toolMessage);
29831
+ }
29832
+ }
29833
+ break;
29834
+ }
29775
29835
  case "user": {
29776
29836
  const contentParts = [];
29777
29837
  for (const part of message.content) {
29778
29838
  switch (part.type) {
29779
- case "text": {
29780
- contentParts.push({
29781
- type: "text",
29782
- text: part.text
29783
- });
29784
- break;
29785
- }
29786
29839
  case "file": {
29787
29840
  if (!part.mediaType.startsWith("image/")) {
29788
29841
  throw new import_provider.UnsupportedFunctionalityError({
@@ -29824,10 +29877,17 @@ function convertToSAPMessages(prompt, options = {}) {
29824
29877
  }
29825
29878
  }
29826
29879
  contentParts.push({
29827
- type: "image_url",
29828
29880
  image_url: {
29829
29881
  url: imageUrl
29830
- }
29882
+ },
29883
+ type: "image_url"
29884
+ });
29885
+ break;
29886
+ }
29887
+ case "text": {
29888
+ contentParts.push({
29889
+ text: part.text,
29890
+ type: "text"
29831
29891
  });
29832
29892
  break;
29833
29893
  }
@@ -29839,73 +29899,15 @@ function convertToSAPMessages(prompt, options = {}) {
29839
29899
  }
29840
29900
  }
29841
29901
  const userMessage = contentParts.length === 1 && contentParts[0].type === "text" ? {
29842
- role: "user",
29843
- content: contentParts[0].text ?? ""
29902
+ content: contentParts[0].text ?? "",
29903
+ role: "user"
29844
29904
  } : {
29845
- role: "user",
29846
- content: contentParts
29905
+ content: contentParts,
29906
+ role: "user"
29847
29907
  };
29848
29908
  messages.push(userMessage);
29849
29909
  break;
29850
29910
  }
29851
- case "assistant": {
29852
- let text = "";
29853
- const toolCalls = [];
29854
- for (const part of message.content) {
29855
- switch (part.type) {
29856
- case "text": {
29857
- text += part.text;
29858
- break;
29859
- }
29860
- case "reasoning": {
29861
- if (includeReasoning && part.text) {
29862
- text += `<reasoning>${part.text}</reasoning>`;
29863
- }
29864
- break;
29865
- }
29866
- case "tool-call": {
29867
- let argumentsJson;
29868
- if (typeof part.input === "string") {
29869
- try {
29870
- JSON.parse(part.input);
29871
- argumentsJson = part.input;
29872
- } catch {
29873
- argumentsJson = JSON.stringify(part.input);
29874
- }
29875
- } else {
29876
- argumentsJson = JSON.stringify(part.input);
29877
- }
29878
- toolCalls.push({
29879
- id: part.toolCallId,
29880
- type: "function",
29881
- function: {
29882
- name: part.toolName,
29883
- arguments: argumentsJson
29884
- }
29885
- });
29886
- break;
29887
- }
29888
- }
29889
- }
29890
- const assistantMessage = {
29891
- role: "assistant",
29892
- content: text || "",
29893
- tool_calls: toolCalls.length > 0 ? toolCalls : void 0
29894
- };
29895
- messages.push(assistantMessage);
29896
- break;
29897
- }
29898
- case "tool": {
29899
- for (const part of message.content) {
29900
- const toolMessage = {
29901
- role: "tool",
29902
- tool_call_id: part.toolCallId,
29903
- content: JSON.stringify(part.output)
29904
- };
29905
- messages.push(toolMessage);
29906
- }
29907
- break;
29908
- }
29909
29911
  default: {
29910
29912
  const _exhaustiveCheck = message;
29911
29913
  throw new Error(
@@ -29920,16 +29922,6 @@ function convertToSAPMessages(prompt, options = {}) {
29920
29922
  // src/sap-ai-error.ts
29921
29923
  var import_provider2 = require("@ai-sdk/provider");
29922
29924
  var import_util = __toESM(require_dist(), 1);
29923
- function getStatusCodeFromSAPError(code) {
29924
- if (!code) return 500;
29925
- if (code >= 100 && code < 600) {
29926
- return code;
29927
- }
29928
- return 500;
29929
- }
29930
- function isRetryable(statusCode) {
29931
- return statusCode === 429 || statusCode >= 500 && statusCode < 600;
29932
- }
29933
29925
  function convertSAPErrorToAPICallError(errorResponse, context) {
29934
29926
  const error = errorResponse.error;
29935
29927
  let message;
@@ -29951,9 +29943,9 @@ function convertSAPErrorToAPICallError(errorResponse, context) {
29951
29943
  const statusCode = getStatusCodeFromSAPError(code);
29952
29944
  const responseBody = JSON.stringify({
29953
29945
  error: {
29954
- message,
29955
29946
  code,
29956
29947
  location,
29948
+ message,
29957
29949
  request_id: requestId
29958
29950
  }
29959
29951
  });
@@ -29976,53 +29968,14 @@ Error location: ${location}`;
29976
29968
  Request ID: ${requestId}`;
29977
29969
  }
29978
29970
  return new import_provider2.APICallError({
29971
+ isRetryable: isRetryable(statusCode),
29979
29972
  message: enhancedMessage,
29980
- url: context?.url ?? "",
29981
29973
  requestBodyValues: context?.requestBody,
29982
- statusCode,
29983
- responseHeaders: context?.responseHeaders,
29984
29974
  responseBody,
29985
- isRetryable: isRetryable(statusCode)
29986
- });
29987
- }
29988
- function isOrchestrationErrorResponse(error) {
29989
- if (error === null || typeof error !== "object" || !("error" in error)) {
29990
- return false;
29991
- }
29992
- const errorEnvelope = error;
29993
- const innerError = errorEnvelope.error;
29994
- if (innerError === void 0) return false;
29995
- if (Array.isArray(innerError)) {
29996
- return innerError.every(
29997
- (entry) => entry !== null && typeof entry === "object" && "message" in entry && typeof entry.message === "string"
29998
- );
29999
- }
30000
- return typeof innerError === "object" && innerError !== null && "message" in innerError && typeof innerError.message === "string";
30001
- }
30002
- function normalizeHeaders(headers) {
30003
- if (!headers || typeof headers !== "object") return void 0;
30004
- const record = headers;
30005
- const entries = Object.entries(record).flatMap(([key, value]) => {
30006
- if (typeof value === "string") return [[key, value]];
30007
- if (Array.isArray(value)) {
30008
- const strings = value.filter((item) => typeof item === "string").join("; ");
30009
- return strings.length > 0 ? [[key, strings]] : [];
30010
- }
30011
- if (typeof value === "number" || typeof value === "boolean") {
30012
- return [[key, String(value)]];
30013
- }
30014
- return [];
29975
+ responseHeaders: context?.responseHeaders,
29976
+ statusCode,
29977
+ url: context?.url ?? ""
30015
29978
  });
30016
- if (entries.length === 0) return void 0;
30017
- return Object.fromEntries(entries);
30018
- }
30019
- function getAxiosResponseHeaders(error) {
30020
- if (!(error instanceof Error)) return void 0;
30021
- const rootCause = (0, import_util.isErrorWithCause)(error) ? error.rootCause : error;
30022
- if (typeof rootCause !== "object") return void 0;
30023
- const maybeAxios = rootCause;
30024
- if (maybeAxios.isAxiosError !== true) return void 0;
30025
- return normalizeHeaders(maybeAxios.response?.headers);
30026
29979
  }
30027
29980
  function convertToAISDKError(error, context) {
30028
29981
  if (error instanceof import_provider2.APICallError || error instanceof import_provider2.LoadAPIKeyError) {
@@ -30047,167 +30000,92 @@ See: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-serv
30047
30000
  }
30048
30001
  if (errorMsg.includes("econnrefused") || errorMsg.includes("enotfound") || errorMsg.includes("network") || errorMsg.includes("timeout")) {
30049
30002
  return new import_provider2.APICallError({
30003
+ cause: error,
30004
+ isRetryable: true,
30050
30005
  message: `Network error connecting to SAP AI Core: ${error.message}`,
30051
- url: context?.url ?? "",
30052
30006
  requestBodyValues: context?.requestBody,
30053
- statusCode: 503,
30054
- isRetryable: true,
30055
30007
  responseHeaders,
30056
- cause: error
30008
+ statusCode: 503,
30009
+ url: context?.url ?? ""
30057
30010
  });
30058
30011
  }
30059
30012
  }
30060
30013
  const message = error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown error occurred";
30061
30014
  const fullMessage = context?.operation ? `SAP AI Core ${context.operation} failed: ${message}` : `SAP AI Core error: ${message}`;
30062
30015
  return new import_provider2.APICallError({
30016
+ cause: error,
30017
+ isRetryable: false,
30063
30018
  message: fullMessage,
30064
- url: context?.url ?? "",
30065
30019
  requestBodyValues: context?.requestBody,
30066
- statusCode: 500,
30067
- isRetryable: false,
30068
30020
  responseHeaders,
30069
- cause: error
30021
+ statusCode: 500,
30022
+ url: context?.url ?? ""
30070
30023
  });
30071
30024
  }
30072
-
30073
- // src/sap-ai-chat-language-model.ts
30074
- function validateModelParameters(params, warnings) {
30075
- if (params.temperature !== void 0 && (params.temperature < 0 || params.temperature > 2)) {
30076
- warnings.push({
30077
- type: "other",
30078
- message: `temperature=${String(params.temperature)} is outside typical range [0, 2]. The API may reject this value.`
30079
- });
30080
- }
30081
- if (params.topP !== void 0 && (params.topP < 0 || params.topP > 1)) {
30082
- warnings.push({
30083
- type: "other",
30084
- message: `topP=${String(params.topP)} is outside valid range [0, 1]. The API may reject this value.`
30085
- });
30086
- }
30087
- if (params.frequencyPenalty !== void 0 && (params.frequencyPenalty < -2 || params.frequencyPenalty > 2)) {
30088
- warnings.push({
30089
- type: "other",
30090
- message: `frequencyPenalty=${String(params.frequencyPenalty)} is outside typical range [-2, 2]. The API may reject this value.`
30091
- });
30092
- }
30093
- if (params.presencePenalty !== void 0 && (params.presencePenalty < -2 || params.presencePenalty > 2)) {
30094
- warnings.push({
30095
- type: "other",
30096
- message: `presencePenalty=${String(params.presencePenalty)} is outside typical range [-2, 2]. The API may reject this value.`
30097
- });
30098
- }
30099
- if (params.maxTokens !== void 0 && params.maxTokens <= 0) {
30100
- warnings.push({
30101
- type: "other",
30102
- message: `maxTokens=${String(params.maxTokens)} must be positive. The API will likely reject this value.`
30103
- });
30104
- }
30105
- if (params.n !== void 0 && params.n <= 0) {
30106
- warnings.push({
30107
- type: "other",
30108
- message: `n=${String(params.n)} must be positive. The API will likely reject this value.`
30109
- });
30110
- }
30111
- }
30112
- function createAISDKRequestBodySummary(options) {
30113
- return {
30114
- promptMessages: options.prompt.length,
30115
- hasImageParts: options.prompt.some(
30116
- (message) => message.role === "user" && message.content.some(
30117
- (part) => part.type === "file" && part.mediaType.startsWith("image/")
30118
- )
30119
- ),
30120
- tools: options.tools?.length ?? 0,
30121
- temperature: options.temperature,
30122
- topP: options.topP,
30123
- topK: options.topK,
30124
- maxOutputTokens: options.maxOutputTokens,
30125
- stopSequences: options.stopSequences?.length,
30126
- seed: options.seed,
30127
- toolChoiceType: options.toolChoice?.type,
30128
- responseFormatType: options.responseFormat?.type
30129
- };
30025
+ function getAxiosResponseHeaders(error) {
30026
+ if (!(error instanceof Error)) return void 0;
30027
+ const rootCause = (0, import_util.isErrorWithCause)(error) ? error.rootCause : error;
30028
+ if (typeof rootCause !== "object") return void 0;
30029
+ const maybeAxios = rootCause;
30030
+ if (maybeAxios.isAxiosError !== true) return void 0;
30031
+ return normalizeHeaders(maybeAxios.response?.headers);
30130
30032
  }
30131
- function hasCallableParse(obj) {
30132
- return typeof obj.parse === "function";
30033
+ function getStatusCodeFromSAPError(code) {
30034
+ if (!code) return 500;
30035
+ if (code >= 100 && code < 600) {
30036
+ return code;
30037
+ }
30038
+ return 500;
30133
30039
  }
30134
- function isZodSchema(obj) {
30135
- if (obj === null || typeof obj !== "object") {
30040
+ function isOrchestrationErrorResponse(error) {
30041
+ if (error === null || typeof error !== "object" || !("error" in error)) {
30136
30042
  return false;
30137
30043
  }
30138
- const record = obj;
30139
- return "_def" in record && "parse" in record && hasCallableParse(record);
30140
- }
30141
- function buildSAPToolParameters(schema) {
30142
- const schemaType = schema.type;
30143
- if (schemaType !== void 0 && schemaType !== "object") {
30144
- return {
30145
- type: "object",
30146
- properties: {},
30147
- required: []
30148
- };
30044
+ const errorEnvelope = error;
30045
+ const innerError = errorEnvelope.error;
30046
+ if (innerError === void 0) return false;
30047
+ if (Array.isArray(innerError)) {
30048
+ return innerError.every(
30049
+ (entry) => entry !== null && typeof entry === "object" && "message" in entry && typeof entry.message === "string"
30050
+ );
30149
30051
  }
30150
- const properties = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
30151
- const required = Array.isArray(schema.required) && schema.required.every((item) => typeof item === "string") ? schema.required : [];
30152
- const additionalFields = Object.fromEntries(
30153
- Object.entries(schema).filter(
30154
- ([key]) => key !== "type" && key !== "properties" && key !== "required"
30155
- )
30156
- );
30157
- return {
30158
- type: "object",
30159
- properties,
30160
- required,
30161
- ...additionalFields
30162
- };
30052
+ return typeof innerError === "object" && innerError !== null && "message" in innerError && typeof innerError.message === "string";
30163
30053
  }
30164
- var SAPAIChatLanguageModel = class {
30165
- specificationVersion = "v2";
30166
- modelId;
30167
- config;
30168
- settings;
30169
- /**
30170
- * Creates a new SAP AI Chat Language Model instance.
30171
- *
30172
- * @param modelId - The model identifier
30173
- * @param settings - Model-specific configuration settings
30174
- * @param config - Internal configuration (deployment config, destination, etc.)
30175
- *
30176
- * @internal This constructor is not meant to be called directly.
30177
- * Use the provider function instead.
30178
- */
30179
- constructor(modelId, settings, config) {
30180
- this.settings = settings;
30181
- this.config = config;
30182
- this.modelId = modelId;
30183
- }
30184
- /**
30185
- * Checks if a URL is supported for file/image uploads.
30186
- *
30187
- * @param url - The URL to check
30188
- * @returns True if the URL protocol is HTTPS or data (content-type rules are enforced via supportedUrls)
30189
- */
30190
- supportsUrl(url) {
30191
- return url.protocol === "https:" || url.protocol === "data:";
30192
- }
30193
- /**
30194
- * Returns supported URL patterns for different content types.
30195
- *
30196
- * @returns Record of content types to regex patterns
30197
- */
30198
- get supportedUrls() {
30199
- return {
30200
- "image/*": [/^https:\/\/.+$/i, /^data:image\/.*$/]
30201
- };
30202
- }
30054
+ function isRetryable(statusCode) {
30055
+ return statusCode === 429 || statusCode >= 500 && statusCode < 600;
30056
+ }
30057
+ function normalizeHeaders(headers) {
30058
+ if (!headers || typeof headers !== "object") return void 0;
30059
+ const record = headers;
30060
+ const entries = Object.entries(record).flatMap(([key, value]) => {
30061
+ if (typeof value === "string") return [[key, value]];
30062
+ if (Array.isArray(value)) {
30063
+ const strings = value.filter((item) => typeof item === "string").join("; ");
30064
+ return strings.length > 0 ? [[key, strings]] : [];
30065
+ }
30066
+ if (typeof value === "number" || typeof value === "boolean") {
30067
+ return [[key, String(value)]];
30068
+ }
30069
+ return [];
30070
+ });
30071
+ if (entries.length === 0) return void 0;
30072
+ return Object.fromEntries(entries);
30073
+ }
30074
+
30075
+ // src/sap-ai-language-model.ts
30076
+ var StreamIdGenerator = class {
30203
30077
  /**
30204
- * Gets the provider identifier.
30078
+ * Generates a unique ID for a text block.
30205
30079
  *
30206
- * @returns The provider name ('sap-ai')
30080
+ * @returns RFC 4122-compliant UUID string
30207
30081
  */
30208
- get provider() {
30209
- return this.config.provider;
30082
+ generateTextBlockId() {
30083
+ return crypto.randomUUID();
30210
30084
  }
30085
+ };
30086
+ var SAPAILanguageModel = class {
30087
+ modelId;
30088
+ specificationVersion = "v3";
30211
30089
  /**
30212
30090
  * Model capabilities.
30213
30091
  *
@@ -30216,203 +30094,91 @@ var SAPAIChatLanguageModel = class {
30216
30094
  * SAP AI Core will fail the request at runtime.
30217
30095
  */
30218
30096
  supportsImageUrls = true;
30219
- /** Structured JSON outputs (json_schema response format). */
30220
- supportsStructuredOutputs = true;
30221
- /** Tool/function calling. */
30222
- supportsToolCalls = true;
30223
- /** Streaming responses. */
30224
- supportsStreaming = true;
30225
30097
  /** Multiple completions via the `n` parameter (provider-specific support). */
30226
30098
  supportsMultipleCompletions = true;
30227
30099
  /** Parallel tool calls. */
30228
30100
  supportsParallelToolCalls = true;
30101
+ /** Streaming responses. */
30102
+ supportsStreaming = true;
30103
+ /** Structured JSON outputs (json_schema response format). */
30104
+ supportsStructuredOutputs = true;
30105
+ /** Tool/function calling. */
30106
+ supportsToolCalls = true;
30229
30107
  /**
30230
- * Builds orchestration module config for SAP AI SDK.
30108
+ * Generates text completion using SAP AI Core's Orchestration API.
30231
30109
  *
30232
- * @param options - Call options from the AI SDK
30233
- * @returns Object containing orchestration config, messages, and warnings
30234
- * @internal
30110
+ * This method implements the `LanguageModelV3.doGenerate` interface,
30111
+ * providing synchronous (non-streaming) text generation with support for:
30112
+ * - Multi-turn conversations with system/user/assistant messages
30113
+ * - Tool calling (function calling) with structured outputs
30114
+ * - Multi-modal inputs (text + images)
30115
+ * - Data masking via SAP DPI
30116
+ * - Content filtering via Azure Content Safety or Llama Guard
30117
+ *
30118
+ * **Return Structure:**
30119
+ * - Finish reason: `{ unified: string, raw?: string }`
30120
+ * - Usage: Nested structure with token breakdown `{ inputTokens: { total, ... }, outputTokens: { total, ... } }`
30121
+ * - Warnings: Array of warnings with `type` and optional `feature` field
30122
+ *
30123
+ * @param options - Generation options including prompt, tools, temperature, etc.
30124
+ * @returns Promise resolving to generation result with content, usage, and metadata
30125
+ *
30126
+ * @throws {InvalidPromptError} If prompt format is invalid
30127
+ * @throws {InvalidArgumentError} If arguments are malformed
30128
+ * @throws {APICallError} If the SAP AI Core API call fails
30129
+ *
30130
+ * @example
30131
+ * ```typescript
30132
+ * const result = await model.doGenerate({
30133
+ * prompt: [
30134
+ * { role: 'user', content: [{ type: 'text', text: 'Hello!' }] }
30135
+ * ],
30136
+ * temperature: 0.7,
30137
+ * maxTokens: 100
30138
+ * });
30139
+ *
30140
+ * console.log(result.content); // Array of V3 content parts
30141
+ * console.log(result.finishReason.unified); // "stop", "length", "tool-calls", etc.
30142
+ * console.log(result.usage.inputTokens.total); // Total input tokens
30143
+ * ```
30144
+ *
30145
+ * @since 1.0.0
30146
+ * @since 4.0.0 Updated to LanguageModelV3 interface
30235
30147
  */
30236
- buildOrchestrationConfig(options) {
30237
- const providerOptions = options.providerOptions?.sap ?? {};
30238
- const warnings = [];
30239
- const messages = convertToSAPMessages(options.prompt, {
30240
- includeReasoning: providerOptions.includeReasoning ?? this.settings.includeReasoning ?? false
30241
- });
30242
- let tools;
30243
- const settingsTools = providerOptions.tools ?? this.settings.tools;
30244
- const optionsTools = options.tools;
30245
- const shouldUseSettingsTools = settingsTools && settingsTools.length > 0 && (!optionsTools || optionsTools.length === 0);
30246
- const shouldUseOptionsTools = !!(optionsTools && optionsTools.length > 0);
30247
- if (settingsTools && settingsTools.length > 0 && optionsTools && optionsTools.length > 0) {
30248
- warnings.push({
30249
- type: "other",
30250
- message: "Both settings.tools and call options.tools were provided; preferring call options.tools."
30251
- });
30252
- }
30253
- if (shouldUseSettingsTools) {
30254
- tools = settingsTools;
30255
- } else {
30256
- const availableTools = shouldUseOptionsTools ? optionsTools : void 0;
30257
- tools = availableTools?.map((tool) => {
30258
- if (tool.type === "function") {
30259
- const inputSchema = tool.inputSchema;
30260
- const toolWithParams = tool;
30261
- let parameters;
30262
- if (toolWithParams.parameters && isZodSchema(toolWithParams.parameters)) {
30263
- try {
30264
- const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(
30265
- toolWithParams.parameters,
30266
- {
30267
- $refStrategy: "none"
30268
- }
30269
- );
30270
- const schemaRecord = jsonSchema;
30271
- delete schemaRecord.$schema;
30272
- parameters = buildSAPToolParameters(schemaRecord);
30273
- } catch {
30274
- warnings.push({
30275
- type: "unsupported-tool",
30276
- tool,
30277
- details: "Failed to convert tool Zod schema to JSON Schema. Falling back to empty object schema."
30278
- });
30279
- parameters = buildSAPToolParameters({});
30280
- }
30281
- } else if (inputSchema && Object.keys(inputSchema).length > 0) {
30282
- const hasProperties = inputSchema.properties && typeof inputSchema.properties === "object" && Object.keys(inputSchema.properties).length > 0;
30283
- if (hasProperties) {
30284
- parameters = buildSAPToolParameters(inputSchema);
30285
- } else {
30286
- parameters = buildSAPToolParameters({});
30287
- }
30288
- } else {
30289
- parameters = buildSAPToolParameters({});
30290
- }
30291
- return {
30292
- type: "function",
30293
- function: {
30294
- name: tool.name,
30295
- description: tool.description,
30296
- parameters
30297
- }
30298
- };
30299
- } else {
30300
- warnings.push({
30301
- type: "unsupported-tool",
30302
- tool
30303
- });
30304
- return null;
30305
- }
30306
- }).filter((t) => t !== null);
30307
- }
30308
- const supportsN = !this.modelId.startsWith("amazon--") && !this.modelId.startsWith("anthropic--");
30309
- const modelParams = {};
30310
- const maxTokens = options.maxOutputTokens ?? providerOptions.modelParams?.maxTokens ?? this.settings.modelParams?.maxTokens;
30311
- if (maxTokens !== void 0) modelParams.max_tokens = maxTokens;
30312
- const temperature = options.temperature ?? providerOptions.modelParams?.temperature ?? this.settings.modelParams?.temperature;
30313
- if (temperature !== void 0) modelParams.temperature = temperature;
30314
- const topP = options.topP ?? providerOptions.modelParams?.topP ?? this.settings.modelParams?.topP;
30315
- if (topP !== void 0) modelParams.top_p = topP;
30316
- if (options.topK !== void 0) modelParams.top_k = options.topK;
30317
- const frequencyPenalty = options.frequencyPenalty ?? providerOptions.modelParams?.frequencyPenalty ?? this.settings.modelParams?.frequencyPenalty;
30318
- if (frequencyPenalty !== void 0) {
30319
- modelParams.frequency_penalty = frequencyPenalty;
30320
- }
30321
- const presencePenalty = options.presencePenalty ?? providerOptions.modelParams?.presencePenalty ?? this.settings.modelParams?.presencePenalty;
30322
- if (presencePenalty !== void 0) {
30323
- modelParams.presence_penalty = presencePenalty;
30324
- }
30325
- if (supportsN) {
30326
- const nValue = providerOptions.modelParams?.n ?? this.settings.modelParams?.n;
30327
- if (nValue !== void 0) {
30328
- modelParams.n = nValue;
30329
- }
30330
- }
30331
- const parallelToolCalls = providerOptions.modelParams?.parallel_tool_calls ?? this.settings.modelParams?.parallel_tool_calls;
30332
- if (parallelToolCalls !== void 0) {
30333
- modelParams.parallel_tool_calls = parallelToolCalls;
30334
- }
30335
- if (options.stopSequences && options.stopSequences.length > 0) {
30336
- modelParams.stop = options.stopSequences;
30337
- }
30338
- if (options.seed !== void 0) {
30339
- modelParams.seed = options.seed;
30340
- }
30341
- validateModelParameters(
30342
- {
30343
- temperature,
30344
- topP,
30345
- frequencyPenalty,
30346
- presencePenalty,
30347
- maxTokens,
30348
- n: modelParams.n
30349
- },
30350
- warnings
30351
- );
30352
- if (options.toolChoice && options.toolChoice.type !== "auto") {
30353
- warnings.push({
30354
- type: "unsupported-setting",
30355
- setting: "toolChoice",
30356
- details: `SAP AI SDK does not support toolChoice '${options.toolChoice.type}'. Using default 'auto' behavior.`
30357
- });
30358
- }
30359
- if (options.responseFormat?.type === "json") {
30360
- warnings.push({
30361
- type: "other",
30362
- message: "responseFormat JSON mode is forwarded to the underlying model; support and schema adherence depend on the model/deployment."
30363
- });
30364
- }
30365
- const responseFormat = options.responseFormat?.type === "json" ? options.responseFormat.schema ? {
30366
- type: "json_schema",
30367
- json_schema: {
30368
- name: options.responseFormat.name ?? "response",
30369
- description: options.responseFormat.description,
30370
- schema: options.responseFormat.schema,
30371
- strict: null
30372
- }
30373
- } : { type: "json_object" } : void 0;
30374
- const orchestrationConfig = {
30375
- promptTemplating: {
30376
- model: {
30377
- name: this.modelId,
30378
- version: providerOptions.modelVersion ?? this.settings.modelVersion ?? "latest",
30379
- params: modelParams
30380
- },
30381
- prompt: {
30382
- template: [],
30383
- tools: tools && tools.length > 0 ? tools : void 0,
30384
- ...responseFormat ? { response_format: responseFormat } : {}
30385
- }
30386
- },
30387
- ...(() => {
30388
- const masking = providerOptions.masking ?? this.settings.masking;
30389
- return masking && Object.keys(masking).length > 0 ? { masking } : {};
30390
- })(),
30391
- ...(() => {
30392
- const filtering = providerOptions.filtering ?? this.settings.filtering;
30393
- return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
30394
- })()
30148
+ get provider() {
30149
+ return this.config.provider;
30150
+ }
30151
+ /**
30152
+ * Returns supported URL patterns for different content types.
30153
+ *
30154
+ * @returns Record of content types to regex patterns
30155
+ */
30156
+ get supportedUrls() {
30157
+ return {
30158
+ "image/*": [/^https:\/\/.+$/i, /^data:image\/.*$/]
30395
30159
  };
30396
- return { orchestrationConfig, messages, warnings };
30397
30160
  }
30161
+ config;
30162
+ settings;
30398
30163
  /**
30399
- * Creates an OrchestrationClient instance.
30164
+ * Creates a new SAP AI Chat Language Model instance.
30400
30165
  *
30401
- * @param config - Orchestration module configuration
30402
- * @returns OrchestrationClient instance
30403
- * @internal
30166
+ * @param modelId - The model identifier
30167
+ * @param settings - Model-specific configuration settings
30168
+ * @param config - Internal configuration (deployment config, destination, etc.)
30169
+ *
30170
+ * @internal This constructor is not meant to be called directly.
30171
+ * Use the provider function instead.
30404
30172
  */
30405
- createClient(config) {
30406
- return new import_orchestration.OrchestrationClient(
30407
- config,
30408
- this.config.deploymentConfig,
30409
- this.config.destination
30410
- );
30173
+ constructor(modelId, settings, config) {
30174
+ this.settings = settings;
30175
+ this.config = config;
30176
+ this.modelId = modelId;
30411
30177
  }
30412
30178
  /**
30413
30179
  * Generates a single completion (non-streaming).
30414
30180
  *
30415
- * This method implements the `LanguageModelV2.doGenerate` interface,
30181
+ * This method implements the `LanguageModelV3.doGenerate` interface,
30416
30182
  * sending a request to SAP AI Core and returning the complete response.
30417
30183
  *
30418
30184
  * **Features:**
@@ -30420,6 +30186,13 @@ var SAPAIChatLanguageModel = class {
30420
30186
  * - Multi-modal input (text + images)
30421
30187
  * - Data masking (if configured)
30422
30188
  * - Content filtering (if configured)
30189
+ * - Abort signal support (via Promise.race)
30190
+ *
30191
+ * **Note on Abort Signal:**
30192
+ * The abort signal implementation uses Promise.race to reject the promise when
30193
+ * the signal is aborted. However, this does not cancel the underlying HTTP request
30194
+ * to SAP AI Core - the request continues executing on the server. This is a
30195
+ * limitation of the SAP AI SDK's chatCompletion API.
30423
30196
  *
30424
30197
  * @param options - Generation options including prompt, tools, and settings
30425
30198
  * @returns Promise resolving to the generation result with content, usage, and metadata
@@ -30438,7 +30211,7 @@ var SAPAIChatLanguageModel = class {
30438
30211
  */
30439
30212
  async doGenerate(options) {
30440
30213
  try {
30441
- const { orchestrationConfig, messages, warnings } = this.buildOrchestrationConfig(options);
30214
+ const { messages, orchestrationConfig, warnings } = this.buildOrchestrationConfig(options);
30442
30215
  const client = this.createClient(orchestrationConfig);
30443
30216
  const promptTemplating = orchestrationConfig.promptTemplating;
30444
30217
  const requestBody = {
@@ -30455,6 +30228,14 @@ var SAPAIChatLanguageModel = class {
30455
30228
  ...(() => {
30456
30229
  const filtering = orchestrationConfig.filtering;
30457
30230
  return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
30231
+ })(),
30232
+ ...(() => {
30233
+ const grounding = orchestrationConfig.grounding;
30234
+ return grounding && Object.keys(grounding).length > 0 ? { grounding } : {};
30235
+ })(),
30236
+ ...(() => {
30237
+ const translation = orchestrationConfig.translation;
30238
+ return translation && Object.keys(translation).length > 0 ? { translation } : {};
30458
30239
  })()
30459
30240
  };
30460
30241
  const response = await (async () => {
@@ -30492,7 +30273,7 @@ var SAPAIChatLanguageModel = class {
30492
30273
  Object.entries(responseHeadersRaw).flatMap(([key, value]) => {
30493
30274
  if (typeof value === "string") return [[key, value]];
30494
30275
  if (Array.isArray(value)) {
30495
- const strings = value.filter((item) => typeof item === "string").join(",");
30276
+ const strings = value.filter((item) => typeof item === "string").join("; ");
30496
30277
  return strings.length > 0 ? [[key, strings]] : [];
30497
30278
  }
30498
30279
  if (typeof value === "number" || typeof value === "boolean") {
@@ -30505,18 +30286,18 @@ var SAPAIChatLanguageModel = class {
30505
30286
  const textContent = response.getContent();
30506
30287
  if (textContent) {
30507
30288
  content.push({
30508
- type: "text",
30509
- text: textContent
30289
+ text: textContent,
30290
+ type: "text"
30510
30291
  });
30511
30292
  }
30512
30293
  const toolCalls = response.getToolCalls();
30513
30294
  if (toolCalls) {
30514
30295
  for (const toolCall of toolCalls) {
30515
30296
  content.push({
30516
- type: "tool-call",
30297
+ input: toolCall.function.arguments,
30517
30298
  toolCallId: toolCall.id,
30518
30299
  toolName: toolCall.function.name,
30519
- input: toolCall.function.arguments
30300
+ type: "tool-call"
30520
30301
  });
30521
30302
  }
30522
30303
  }
@@ -30525,18 +30306,13 @@ var SAPAIChatLanguageModel = class {
30525
30306
  const finishReason = mapFinishReason(finishReasonRaw);
30526
30307
  const rawResponseBody = {
30527
30308
  content: textContent,
30528
- toolCalls,
30309
+ finishReason: finishReasonRaw,
30529
30310
  tokenUsage,
30530
- finishReason: finishReasonRaw
30311
+ toolCalls
30531
30312
  };
30532
30313
  return {
30533
30314
  content,
30534
30315
  finishReason,
30535
- usage: {
30536
- inputTokens: tokenUsage.prompt_tokens,
30537
- outputTokens: tokenUsage.completion_tokens,
30538
- totalTokens: tokenUsage.total_tokens
30539
- },
30540
30316
  providerMetadata: {
30541
30317
  "sap-ai": {
30542
30318
  finishReason: finishReasonRaw ?? "unknown",
@@ -30548,37 +30324,61 @@ var SAPAIChatLanguageModel = class {
30548
30324
  body: requestBody
30549
30325
  },
30550
30326
  response: {
30551
- timestamp: /* @__PURE__ */ new Date(),
30552
- modelId: this.modelId,
30327
+ body: rawResponseBody,
30553
30328
  headers: responseHeaders,
30554
- body: rawResponseBody
30329
+ modelId: this.modelId,
30330
+ timestamp: /* @__PURE__ */ new Date()
30331
+ },
30332
+ usage: {
30333
+ inputTokens: {
30334
+ cacheRead: void 0,
30335
+ cacheWrite: void 0,
30336
+ noCache: tokenUsage.prompt_tokens,
30337
+ total: tokenUsage.prompt_tokens
30338
+ },
30339
+ outputTokens: {
30340
+ reasoning: void 0,
30341
+ text: tokenUsage.completion_tokens,
30342
+ total: tokenUsage.completion_tokens
30343
+ }
30555
30344
  },
30556
30345
  warnings
30557
30346
  };
30558
30347
  } catch (error) {
30559
30348
  throw convertToAISDKError(error, {
30560
30349
  operation: "doGenerate",
30561
- url: "sap-ai:orchestration",
30562
- requestBody: createAISDKRequestBodySummary(options)
30350
+ requestBody: createAISDKRequestBodySummary(options),
30351
+ url: "sap-ai:orchestration"
30563
30352
  });
30564
30353
  }
30565
30354
  }
30566
30355
  /**
30567
30356
  * Generates a streaming completion.
30568
30357
  *
30569
- * This method implements the `LanguageModelV2.doStream` interface,
30358
+ * This method implements the `LanguageModelV3.doStream` interface,
30570
30359
  * sending a streaming request to SAP AI Core and returning a stream of response parts.
30571
30360
  *
30572
30361
  * **Stream Events:**
30573
- * - `stream-start` - Stream initialization
30362
+ * - `stream-start` - Stream initialization with warnings
30574
30363
  * - `response-metadata` - Response metadata (model, timestamp)
30575
- * - `text-start` - Text generation starts
30576
- * - `text-delta` - Incremental text chunks
30577
- * - `text-end` - Text generation completes
30578
- * - `tool-call` - Tool call detected
30364
+ * - `text-start` - Text block begins (with unique ID)
30365
+ * - `text-delta` - Incremental text chunks (with block ID)
30366
+ * - `text-end` - Text block completes (with accumulated text)
30367
+ * - `tool-input-start` - Tool input begins
30368
+ * - `tool-input-delta` - Tool input chunk
30369
+ * - `tool-input-end` - Tool input completes
30370
+ * - `tool-call` - Complete tool call
30579
30371
  * - `finish` - Stream completes with usage and finish reason
30580
30372
  * - `error` - Error occurred
30581
30373
  *
30374
+ * **Stream Structure:**
30375
+ * - Text blocks have explicit lifecycle with unique IDs
30376
+ * - Finish reason format: `{ unified: string, raw?: string }`
30377
+ * - Usage format: `{ inputTokens: { total, ... }, outputTokens: { total, ... } }`
30378
+ * - Warnings only in `stream-start` event
30379
+ *
30380
+ * @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/streaming Vercel AI SDK Streaming}
30381
+ *
30582
30382
  * @param options - Streaming options including prompt, tools, and settings
30583
30383
  * @returns Promise resolving to stream and request metadata
30584
30384
  *
@@ -30594,12 +30394,17 @@ var SAPAIChatLanguageModel = class {
30594
30394
  * if (part.type === 'text-delta') {
30595
30395
  * process.stdout.write(part.delta);
30596
30396
  * }
30397
+ * if (part.type === 'text-end') {
30398
+ * console.log('Block complete:', part.id, part.text);
30399
+ * }
30597
30400
  * }
30598
30401
  * ```
30402
+ *
30403
+ * @since 4.0.0
30599
30404
  */
30600
30405
  async doStream(options) {
30601
30406
  try {
30602
- const { orchestrationConfig, messages, warnings } = this.buildOrchestrationConfig(options);
30407
+ const { messages, orchestrationConfig, warnings } = this.buildOrchestrationConfig(options);
30603
30408
  const client = this.createClient(orchestrationConfig);
30604
30409
  const promptTemplating = orchestrationConfig.promptTemplating;
30605
30410
  const requestBody = {
@@ -30623,15 +30428,28 @@ var SAPAIChatLanguageModel = class {
30623
30428
  options.abortSignal,
30624
30429
  { promptTemplating: { include_usage: true } }
30625
30430
  );
30431
+ const idGenerator = new StreamIdGenerator();
30432
+ let textBlockId = null;
30626
30433
  const streamState = {
30627
- finishReason: "unknown",
30628
- usage: {
30629
- inputTokens: void 0,
30630
- outputTokens: void 0,
30631
- totalTokens: void 0
30434
+ activeText: false,
30435
+ finishReason: {
30436
+ raw: void 0,
30437
+ unified: "other"
30632
30438
  },
30633
30439
  isFirstChunk: true,
30634
- activeText: false
30440
+ usage: {
30441
+ inputTokens: {
30442
+ cacheRead: void 0,
30443
+ cacheWrite: void 0,
30444
+ noCache: void 0,
30445
+ total: void 0
30446
+ },
30447
+ outputTokens: {
30448
+ reasoning: void 0,
30449
+ text: void 0,
30450
+ total: void 0
30451
+ }
30452
+ }
30635
30453
  };
30636
30454
  const toolCallsInProgress = /* @__PURE__ */ new Map();
30637
30455
  const sdkStream = streamResponse.stream;
@@ -30639,6 +30457,11 @@ var SAPAIChatLanguageModel = class {
30639
30457
  const warningsSnapshot = [...warnings];
30640
30458
  const warningsOut = [...warningsSnapshot];
30641
30459
  const transformedStream = new ReadableStream({
30460
+ cancel(reason) {
30461
+ if (reason) {
30462
+ console.debug("SAP AI stream cancelled:", reason);
30463
+ }
30464
+ },
30642
30465
  async start(controller) {
30643
30466
  controller.enqueue({
30644
30467
  type: "stream-start",
@@ -30649,26 +30472,32 @@ var SAPAIChatLanguageModel = class {
30649
30472
  if (streamState.isFirstChunk) {
30650
30473
  streamState.isFirstChunk = false;
30651
30474
  controller.enqueue({
30652
- type: "response-metadata",
30653
30475
  modelId,
30654
- timestamp: /* @__PURE__ */ new Date()
30476
+ timestamp: /* @__PURE__ */ new Date(),
30477
+ type: "response-metadata"
30655
30478
  });
30656
30479
  }
30657
30480
  const deltaToolCalls = chunk.getDeltaToolCalls();
30658
30481
  if (Array.isArray(deltaToolCalls) && deltaToolCalls.length > 0) {
30659
- streamState.finishReason = "tool-calls";
30482
+ streamState.finishReason = {
30483
+ raw: void 0,
30484
+ unified: "tool-calls"
30485
+ };
30660
30486
  }
30661
30487
  const deltaContent = chunk.getDeltaContent();
30662
- if (typeof deltaContent === "string" && deltaContent.length > 0 && streamState.finishReason !== "tool-calls") {
30488
+ if (typeof deltaContent === "string" && deltaContent.length > 0 && streamState.finishReason.unified !== "tool-calls") {
30663
30489
  if (!streamState.activeText) {
30664
- controller.enqueue({ type: "text-start", id: "0" });
30490
+ textBlockId = idGenerator.generateTextBlockId();
30491
+ controller.enqueue({ id: textBlockId, type: "text-start" });
30665
30492
  streamState.activeText = true;
30666
30493
  }
30667
- controller.enqueue({
30668
- type: "text-delta",
30669
- id: "0",
30670
- delta: deltaContent
30671
- });
30494
+ if (textBlockId) {
30495
+ controller.enqueue({
30496
+ delta: deltaContent,
30497
+ id: textBlockId,
30498
+ type: "text-delta"
30499
+ });
30500
+ }
30672
30501
  }
30673
30502
  if (Array.isArray(deltaToolCalls) && deltaToolCalls.length > 0) {
30674
30503
  for (const toolCallChunk of deltaToolCalls) {
@@ -30678,11 +30507,11 @@ var SAPAIChatLanguageModel = class {
30678
30507
  }
30679
30508
  if (!toolCallsInProgress.has(index)) {
30680
30509
  toolCallsInProgress.set(index, {
30681
- id: toolCallChunk.id ?? `tool_${String(index)}`,
30682
- toolName: toolCallChunk.function?.name,
30683
30510
  arguments: "",
30511
+ didEmitCall: false,
30684
30512
  didEmitInputStart: false,
30685
- didEmitCall: false
30513
+ id: toolCallChunk.id ?? `tool_${String(index)}`,
30514
+ toolName: toolCallChunk.function?.name
30686
30515
  });
30687
30516
  }
30688
30517
  const tc = toolCallsInProgress.get(index);
@@ -30697,9 +30526,9 @@ var SAPAIChatLanguageModel = class {
30697
30526
  if (!tc.didEmitInputStart && tc.toolName) {
30698
30527
  tc.didEmitInputStart = true;
30699
30528
  controller.enqueue({
30700
- type: "tool-input-start",
30701
30529
  id: tc.id,
30702
- toolName: tc.toolName
30530
+ toolName: tc.toolName,
30531
+ type: "tool-input-start"
30703
30532
  });
30704
30533
  }
30705
30534
  const argumentsDelta = toolCallChunk.function?.arguments;
@@ -30707,9 +30536,9 @@ var SAPAIChatLanguageModel = class {
30707
30536
  tc.arguments += argumentsDelta;
30708
30537
  if (tc.didEmitInputStart) {
30709
30538
  controller.enqueue({
30710
- type: "tool-input-delta",
30539
+ delta: argumentsDelta,
30711
30540
  id: tc.id,
30712
- delta: argumentsDelta
30541
+ type: "tool-input-delta"
30713
30542
  });
30714
30543
  }
30715
30544
  }
@@ -30718,7 +30547,7 @@ var SAPAIChatLanguageModel = class {
30718
30547
  const chunkFinishReason = chunk.getFinishReason();
30719
30548
  if (chunkFinishReason) {
30720
30549
  streamState.finishReason = mapFinishReason(chunkFinishReason);
30721
- if (streamState.finishReason === "tool-calls") {
30550
+ if (streamState.finishReason.unified === "tool-calls") {
30722
30551
  const toolCalls2 = Array.from(toolCallsInProgress.values());
30723
30552
  for (const tc of toolCalls2) {
30724
30553
  if (tc.didEmitCall) {
@@ -30727,28 +30556,28 @@ var SAPAIChatLanguageModel = class {
30727
30556
  if (!tc.didEmitInputStart) {
30728
30557
  tc.didEmitInputStart = true;
30729
30558
  controller.enqueue({
30730
- type: "tool-input-start",
30731
30559
  id: tc.id,
30732
- toolName: tc.toolName ?? ""
30560
+ toolName: tc.toolName ?? "",
30561
+ type: "tool-input-start"
30733
30562
  });
30734
30563
  }
30735
30564
  if (!tc.toolName) {
30736
30565
  warningsOut.push({
30737
- type: "other",
30738
- message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name."
30566
+ message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name.",
30567
+ type: "other"
30739
30568
  });
30740
30569
  }
30741
30570
  tc.didEmitCall = true;
30742
- controller.enqueue({ type: "tool-input-end", id: tc.id });
30571
+ controller.enqueue({ id: tc.id, type: "tool-input-end" });
30743
30572
  controller.enqueue({
30744
- type: "tool-call",
30573
+ input: tc.arguments,
30745
30574
  toolCallId: tc.id,
30746
30575
  toolName: tc.toolName ?? "",
30747
- input: tc.arguments
30576
+ type: "tool-call"
30748
30577
  });
30749
30578
  }
30750
- if (streamState.activeText) {
30751
- controller.enqueue({ type: "text-end", id: "0" });
30579
+ if (streamState.activeText && textBlockId) {
30580
+ controller.enqueue({ id: textBlockId, type: "text-end" });
30752
30581
  streamState.activeText = false;
30753
30582
  }
30754
30583
  }
@@ -30763,105 +30592,399 @@ var SAPAIChatLanguageModel = class {
30763
30592
  if (!tc.didEmitInputStart) {
30764
30593
  tc.didEmitInputStart = true;
30765
30594
  controller.enqueue({
30766
- type: "tool-input-start",
30767
30595
  id: tc.id,
30768
- toolName: tc.toolName ?? ""
30596
+ toolName: tc.toolName ?? "",
30597
+ type: "tool-input-start"
30769
30598
  });
30770
30599
  }
30771
30600
  if (!tc.toolName) {
30772
30601
  warningsOut.push({
30773
- type: "other",
30774
- message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name."
30602
+ message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name.",
30603
+ type: "other"
30775
30604
  });
30776
30605
  }
30777
30606
  didEmitAnyToolCalls = true;
30778
30607
  tc.didEmitCall = true;
30779
- controller.enqueue({ type: "tool-input-end", id: tc.id });
30608
+ controller.enqueue({ id: tc.id, type: "tool-input-end" });
30780
30609
  controller.enqueue({
30781
- type: "tool-call",
30610
+ input: tc.arguments,
30782
30611
  toolCallId: tc.id,
30783
30612
  toolName: tc.toolName ?? "",
30784
- input: tc.arguments
30613
+ type: "tool-call"
30614
+ });
30615
+ }
30616
+ if (streamState.activeText && textBlockId) {
30617
+ controller.enqueue({ id: textBlockId, type: "text-end" });
30618
+ }
30619
+ const finalFinishReason = streamResponse.getFinishReason();
30620
+ if (finalFinishReason) {
30621
+ streamState.finishReason = mapFinishReason(finalFinishReason);
30622
+ } else if (didEmitAnyToolCalls) {
30623
+ streamState.finishReason = {
30624
+ raw: void 0,
30625
+ unified: "tool-calls"
30626
+ };
30627
+ }
30628
+ const finalUsage = streamResponse.getTokenUsage();
30629
+ if (finalUsage) {
30630
+ streamState.usage.inputTokens.total = finalUsage.prompt_tokens;
30631
+ streamState.usage.inputTokens.noCache = finalUsage.prompt_tokens;
30632
+ streamState.usage.outputTokens.total = finalUsage.completion_tokens;
30633
+ streamState.usage.outputTokens.text = finalUsage.completion_tokens;
30634
+ }
30635
+ controller.enqueue({
30636
+ finishReason: streamState.finishReason,
30637
+ type: "finish",
30638
+ usage: streamState.usage
30639
+ });
30640
+ controller.close();
30641
+ } catch (error) {
30642
+ const aiError = convertToAISDKError(error, {
30643
+ operation: "doStream",
30644
+ requestBody: createAISDKRequestBodySummary(options),
30645
+ url: "sap-ai:orchestration"
30646
+ });
30647
+ controller.enqueue({
30648
+ error: aiError instanceof Error ? aiError : new Error(String(aiError)),
30649
+ type: "error"
30650
+ });
30651
+ controller.close();
30652
+ }
30653
+ }
30654
+ });
30655
+ return {
30656
+ request: {
30657
+ body: requestBody
30658
+ },
30659
+ stream: transformedStream
30660
+ };
30661
+ } catch (error) {
30662
+ throw convertToAISDKError(error, {
30663
+ operation: "doStream",
30664
+ requestBody: createAISDKRequestBodySummary(options),
30665
+ url: "sap-ai:orchestration"
30666
+ });
30667
+ }
30668
+ }
30669
+ /**
30670
+ * Checks if a URL is supported for file/image uploads.
30671
+ *
30672
+ * @param url - The URL to check
30673
+ * @returns True if the URL protocol is HTTPS or data with valid image format
30674
+ */
30675
+ supportsUrl(url) {
30676
+ if (url.protocol === "https:") return true;
30677
+ if (url.protocol === "data:") {
30678
+ return /^data:image\//i.test(url.href);
30679
+ }
30680
+ return false;
30681
+ }
30682
+ /**
30683
+ * Builds orchestration module config for SAP AI SDK.
30684
+ *
30685
+ * @param options - Call options from the AI SDK
30686
+ * @returns Object containing orchestration config, messages, and warnings
30687
+ * @internal
30688
+ */
30689
+ buildOrchestrationConfig(options) {
30690
+ const providerOptions = options.providerOptions?.sap ?? {};
30691
+ const warnings = [];
30692
+ const messages = convertToSAPMessages(options.prompt, {
30693
+ includeReasoning: providerOptions.includeReasoning ?? this.settings.includeReasoning ?? false
30694
+ });
30695
+ let tools;
30696
+ const settingsTools = providerOptions.tools ?? this.settings.tools;
30697
+ const optionsTools = options.tools;
30698
+ const shouldUseSettingsTools = settingsTools && settingsTools.length > 0 && (!optionsTools || optionsTools.length === 0);
30699
+ const shouldUseOptionsTools = !!(optionsTools && optionsTools.length > 0);
30700
+ if (settingsTools && settingsTools.length > 0 && optionsTools && optionsTools.length > 0) {
30701
+ warnings.push({
30702
+ message: "Both settings.tools and call options.tools were provided; preferring call options.tools.",
30703
+ type: "other"
30704
+ });
30705
+ }
30706
+ if (shouldUseSettingsTools) {
30707
+ tools = settingsTools;
30708
+ } else {
30709
+ const availableTools = shouldUseOptionsTools ? optionsTools : void 0;
30710
+ tools = availableTools?.map((tool) => {
30711
+ if (tool.type === "function") {
30712
+ const inputSchema = tool.inputSchema;
30713
+ const toolWithParams = tool;
30714
+ let parameters;
30715
+ if (toolWithParams.parameters && isZodSchema(toolWithParams.parameters)) {
30716
+ try {
30717
+ const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(
30718
+ toolWithParams.parameters,
30719
+ {
30720
+ $refStrategy: "none"
30721
+ }
30722
+ );
30723
+ const schemaRecord = jsonSchema;
30724
+ delete schemaRecord.$schema;
30725
+ parameters = buildSAPToolParameters(schemaRecord);
30726
+ } catch (error) {
30727
+ warnings.push({
30728
+ details: `Failed to convert tool Zod schema: ${error instanceof Error ? error.message : String(error)}. Falling back to empty object schema.`,
30729
+ feature: `tool schema conversion for ${tool.name}`,
30730
+ type: "unsupported"
30785
30731
  });
30732
+ parameters = buildSAPToolParameters({});
30786
30733
  }
30787
- if (streamState.activeText) {
30788
- controller.enqueue({ type: "text-end", id: "0" });
30789
- }
30790
- const finalFinishReason = streamResponse.getFinishReason();
30791
- if (finalFinishReason) {
30792
- streamState.finishReason = mapFinishReason(finalFinishReason);
30793
- } else if (didEmitAnyToolCalls) {
30794
- streamState.finishReason = "tool-calls";
30795
- }
30796
- const finalUsage = streamResponse.getTokenUsage();
30797
- if (finalUsage) {
30798
- streamState.usage.inputTokens = finalUsage.prompt_tokens;
30799
- streamState.usage.outputTokens = finalUsage.completion_tokens;
30800
- streamState.usage.totalTokens = finalUsage.total_tokens;
30734
+ } else if (inputSchema && Object.keys(inputSchema).length > 0) {
30735
+ const hasProperties = inputSchema.properties && typeof inputSchema.properties === "object" && Object.keys(inputSchema.properties).length > 0;
30736
+ if (hasProperties) {
30737
+ parameters = buildSAPToolParameters(inputSchema);
30738
+ } else {
30739
+ parameters = buildSAPToolParameters({});
30801
30740
  }
30802
- controller.enqueue({
30803
- type: "finish",
30804
- finishReason: streamState.finishReason,
30805
- usage: streamState.usage
30806
- });
30807
- controller.close();
30808
- } catch (error) {
30809
- const aiError = convertToAISDKError(error, {
30810
- operation: "doStream",
30811
- url: "sap-ai:orchestration",
30812
- requestBody: createAISDKRequestBodySummary(options)
30813
- });
30814
- controller.enqueue({
30815
- type: "error",
30816
- error: aiError instanceof Error ? aiError : new Error(String(aiError))
30817
- });
30818
- controller.close();
30819
- }
30820
- },
30821
- cancel(reason) {
30822
- if (reason) {
30823
- console.debug("SAP AI stream cancelled:", reason);
30741
+ } else {
30742
+ parameters = buildSAPToolParameters({});
30824
30743
  }
30744
+ return {
30745
+ function: {
30746
+ description: tool.description,
30747
+ name: tool.name,
30748
+ parameters
30749
+ },
30750
+ type: "function"
30751
+ };
30752
+ } else {
30753
+ warnings.push({
30754
+ details: "Only 'function' tool type is supported.",
30755
+ feature: `tool type for ${tool.name}`,
30756
+ type: "unsupported"
30757
+ });
30758
+ return null;
30825
30759
  }
30760
+ }).filter((t) => t !== null);
30761
+ }
30762
+ const supportsN = !this.modelId.startsWith("amazon--") && !this.modelId.startsWith("anthropic--");
30763
+ const modelParams = {};
30764
+ const maxTokens = options.maxOutputTokens ?? providerOptions.modelParams?.maxTokens ?? this.settings.modelParams?.maxTokens;
30765
+ if (maxTokens !== void 0) modelParams.max_tokens = maxTokens;
30766
+ const temperature = options.temperature ?? providerOptions.modelParams?.temperature ?? this.settings.modelParams?.temperature;
30767
+ if (temperature !== void 0) modelParams.temperature = temperature;
30768
+ const topP = options.topP ?? providerOptions.modelParams?.topP ?? this.settings.modelParams?.topP;
30769
+ if (topP !== void 0) modelParams.top_p = topP;
30770
+ if (options.topK !== void 0) modelParams.top_k = options.topK;
30771
+ const frequencyPenalty = options.frequencyPenalty ?? providerOptions.modelParams?.frequencyPenalty ?? this.settings.modelParams?.frequencyPenalty;
30772
+ if (frequencyPenalty !== void 0) {
30773
+ modelParams.frequency_penalty = frequencyPenalty;
30774
+ }
30775
+ const presencePenalty = options.presencePenalty ?? providerOptions.modelParams?.presencePenalty ?? this.settings.modelParams?.presencePenalty;
30776
+ if (presencePenalty !== void 0) {
30777
+ modelParams.presence_penalty = presencePenalty;
30778
+ }
30779
+ if (supportsN) {
30780
+ const nValue = providerOptions.modelParams?.n ?? this.settings.modelParams?.n;
30781
+ if (nValue !== void 0) {
30782
+ modelParams.n = nValue;
30783
+ }
30784
+ }
30785
+ const parallelToolCalls = providerOptions.modelParams?.parallel_tool_calls ?? this.settings.modelParams?.parallel_tool_calls;
30786
+ if (parallelToolCalls !== void 0) {
30787
+ modelParams.parallel_tool_calls = parallelToolCalls;
30788
+ }
30789
+ if (options.stopSequences && options.stopSequences.length > 0) {
30790
+ modelParams.stop = options.stopSequences;
30791
+ }
30792
+ if (options.seed !== void 0) {
30793
+ modelParams.seed = options.seed;
30794
+ }
30795
+ validateModelParameters(
30796
+ {
30797
+ frequencyPenalty,
30798
+ maxTokens,
30799
+ n: modelParams.n,
30800
+ presencePenalty,
30801
+ temperature,
30802
+ topP
30803
+ },
30804
+ warnings
30805
+ );
30806
+ if (options.toolChoice && options.toolChoice.type !== "auto") {
30807
+ warnings.push({
30808
+ details: `SAP AI SDK does not support toolChoice '${options.toolChoice.type}'. Using default 'auto' behavior.`,
30809
+ feature: "toolChoice",
30810
+ type: "unsupported"
30826
30811
  });
30827
- return {
30828
- stream: transformedStream,
30829
- request: {
30830
- body: requestBody
30831
- },
30832
- warnings: warningsOut
30833
- };
30834
- } catch (error) {
30835
- throw convertToAISDKError(error, {
30836
- operation: "doStream",
30837
- url: "sap-ai:orchestration",
30838
- requestBody: createAISDKRequestBodySummary(options)
30812
+ }
30813
+ if (options.responseFormat?.type === "json") {
30814
+ warnings.push({
30815
+ message: "responseFormat JSON mode is forwarded to the underlying model; support and schema adherence depend on the model/deployment.",
30816
+ type: "other"
30839
30817
  });
30840
30818
  }
30819
+ const responseFormat = options.responseFormat?.type === "json" ? options.responseFormat.schema ? {
30820
+ json_schema: {
30821
+ description: options.responseFormat.description,
30822
+ name: options.responseFormat.name ?? "response",
30823
+ schema: options.responseFormat.schema,
30824
+ strict: null
30825
+ },
30826
+ type: "json_schema"
30827
+ } : { type: "json_object" } : void 0;
30828
+ const orchestrationConfig = {
30829
+ promptTemplating: {
30830
+ model: {
30831
+ name: this.modelId,
30832
+ params: modelParams,
30833
+ version: providerOptions.modelVersion ?? this.settings.modelVersion ?? "latest"
30834
+ },
30835
+ prompt: {
30836
+ template: [],
30837
+ tools: tools && tools.length > 0 ? tools : void 0,
30838
+ ...responseFormat ? { response_format: responseFormat } : {}
30839
+ }
30840
+ },
30841
+ ...(() => {
30842
+ const masking = providerOptions.masking ?? this.settings.masking;
30843
+ return masking && Object.keys(masking).length > 0 ? { masking } : {};
30844
+ })(),
30845
+ ...(() => {
30846
+ const filtering = providerOptions.filtering ?? this.settings.filtering;
30847
+ return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
30848
+ })(),
30849
+ ...(() => {
30850
+ const grounding = providerOptions.grounding ?? this.settings.grounding;
30851
+ return grounding && Object.keys(grounding).length > 0 ? { grounding } : {};
30852
+ })(),
30853
+ ...(() => {
30854
+ const translation = providerOptions.translation ?? this.settings.translation;
30855
+ return translation && Object.keys(translation).length > 0 ? { translation } : {};
30856
+ })()
30857
+ };
30858
+ return { messages, orchestrationConfig, warnings };
30859
+ }
30860
+ /**
30861
+ * Creates an OrchestrationClient instance.
30862
+ *
30863
+ * @param config - Orchestration module configuration
30864
+ * @returns OrchestrationClient instance
30865
+ * @internal
30866
+ */
30867
+ createClient(config) {
30868
+ return new import_orchestration.OrchestrationClient(
30869
+ config,
30870
+ this.config.deploymentConfig,
30871
+ this.config.destination
30872
+ );
30841
30873
  }
30842
30874
  };
30875
+ function buildSAPToolParameters(schema) {
30876
+ const schemaType = schema.type;
30877
+ if (schemaType !== void 0 && schemaType !== "object") {
30878
+ return {
30879
+ properties: {},
30880
+ required: [],
30881
+ type: "object"
30882
+ };
30883
+ }
30884
+ const properties = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
30885
+ const required = Array.isArray(schema.required) && schema.required.every((item) => typeof item === "string") ? schema.required : [];
30886
+ const additionalFields = Object.fromEntries(
30887
+ Object.entries(schema).filter(
30888
+ ([key]) => key !== "type" && key !== "properties" && key !== "required"
30889
+ )
30890
+ );
30891
+ return {
30892
+ properties,
30893
+ required,
30894
+ type: "object",
30895
+ ...additionalFields
30896
+ };
30897
+ }
30898
+ function createAISDKRequestBodySummary(options) {
30899
+ return {
30900
+ hasImageParts: options.prompt.some(
30901
+ (message) => message.role === "user" && message.content.some(
30902
+ (part) => part.type === "file" && part.mediaType.startsWith("image/")
30903
+ )
30904
+ ),
30905
+ maxOutputTokens: options.maxOutputTokens,
30906
+ promptMessages: options.prompt.length,
30907
+ responseFormatType: options.responseFormat?.type,
30908
+ seed: options.seed,
30909
+ stopSequences: options.stopSequences?.length,
30910
+ temperature: options.temperature,
30911
+ toolChoiceType: options.toolChoice?.type,
30912
+ tools: options.tools?.length ?? 0,
30913
+ topK: options.topK,
30914
+ topP: options.topP
30915
+ };
30916
+ }
30917
+ function hasCallableParse(obj) {
30918
+ return typeof obj.parse === "function";
30919
+ }
30920
+ function isZodSchema(obj) {
30921
+ if (obj === null || typeof obj !== "object") {
30922
+ return false;
30923
+ }
30924
+ const record = obj;
30925
+ return "_def" in record && "parse" in record && hasCallableParse(record);
30926
+ }
30843
30927
  function mapFinishReason(reason) {
30844
- if (!reason) return "unknown";
30928
+ const raw = reason;
30929
+ if (!reason) return { raw, unified: "other" };
30845
30930
  switch (reason.toLowerCase()) {
30846
- case "stop":
30931
+ case "content_filter":
30932
+ return { raw, unified: "content-filter" };
30847
30933
  case "end_turn":
30848
- case "stop_sequence":
30849
30934
  case "eos":
30850
- return "stop";
30935
+ case "stop":
30936
+ case "stop_sequence":
30937
+ return { raw, unified: "stop" };
30938
+ case "error":
30939
+ return { raw, unified: "error" };
30940
+ case "function_call":
30941
+ case "tool_call":
30942
+ case "tool_calls":
30943
+ return { raw, unified: "tool-calls" };
30851
30944
  case "length":
30852
30945
  case "max_tokens":
30853
30946
  case "max_tokens_reached":
30854
- return "length";
30855
- case "tool_calls":
30856
- case "tool_call":
30857
- case "function_call":
30858
- return "tool-calls";
30859
- case "content_filter":
30860
- return "content-filter";
30861
- case "error":
30862
- return "error";
30947
+ return { raw, unified: "length" };
30863
30948
  default:
30864
- return "other";
30949
+ return { raw, unified: "other" };
30950
+ }
30951
+ }
30952
+ function validateModelParameters(params, warnings) {
30953
+ if (params.temperature !== void 0 && (params.temperature < 0 || params.temperature > 2)) {
30954
+ warnings.push({
30955
+ message: `temperature=${String(params.temperature)} is outside typical range [0, 2]. The API may reject this value.`,
30956
+ type: "other"
30957
+ });
30958
+ }
30959
+ if (params.topP !== void 0 && (params.topP < 0 || params.topP > 1)) {
30960
+ warnings.push({
30961
+ message: `topP=${String(params.topP)} is outside valid range [0, 1]. The API may reject this value.`,
30962
+ type: "other"
30963
+ });
30964
+ }
30965
+ if (params.frequencyPenalty !== void 0 && (params.frequencyPenalty < -2 || params.frequencyPenalty > 2)) {
30966
+ warnings.push({
30967
+ message: `frequencyPenalty=${String(params.frequencyPenalty)} is outside typical range [-2, 2]. The API may reject this value.`,
30968
+ type: "other"
30969
+ });
30970
+ }
30971
+ if (params.presencePenalty !== void 0 && (params.presencePenalty < -2 || params.presencePenalty > 2)) {
30972
+ warnings.push({
30973
+ message: `presencePenalty=${String(params.presencePenalty)} is outside typical range [-2, 2]. The API may reject this value.`,
30974
+ type: "other"
30975
+ });
30976
+ }
30977
+ if (params.maxTokens !== void 0 && params.maxTokens <= 0) {
30978
+ warnings.push({
30979
+ message: `maxTokens=${String(params.maxTokens)} must be positive. The API will likely reject this value.`,
30980
+ type: "other"
30981
+ });
30982
+ }
30983
+ if (params.n !== void 0 && params.n <= 0) {
30984
+ warnings.push({
30985
+ message: `n=${String(params.n)} must be positive. The API will likely reject this value.`,
30986
+ type: "other"
30987
+ });
30865
30988
  }
30866
30989
  }
30867
30990
 
@@ -30879,19 +31002,19 @@ function createSAPAIProvider(options = {}) {
30879
31002
  const mergedSettings = {
30880
31003
  ...options.defaultSettings,
30881
31004
  ...settings,
31005
+ filtering: settings.filtering ?? options.defaultSettings?.filtering,
31006
+ // Complex objects: override, do not merge
31007
+ masking: settings.masking ?? options.defaultSettings?.masking,
30882
31008
  modelParams: {
30883
31009
  ...options.defaultSettings?.modelParams ?? {},
30884
31010
  ...settings.modelParams ?? {}
30885
31011
  },
30886
- // Complex objects: override, do not merge
30887
- masking: settings.masking ?? options.defaultSettings?.masking,
30888
- filtering: settings.filtering ?? options.defaultSettings?.filtering,
30889
31012
  tools: settings.tools ?? options.defaultSettings?.tools
30890
31013
  };
30891
- return new SAPAIChatLanguageModel(modelId, mergedSettings, {
30892
- provider: "sap-ai",
31014
+ return new SAPAILanguageModel(modelId, mergedSettings, {
30893
31015
  deploymentConfig,
30894
- destination: options.destination
31016
+ destination: options.destination,
31017
+ provider: "sap-ai"
30895
31018
  });
30896
31019
  };
30897
31020
  const provider = function(modelId, settings) {
@@ -30907,17 +31030,12 @@ function createSAPAIProvider(options = {}) {
30907
31030
  }
30908
31031
  var sapai = createSAPAIProvider();
30909
31032
 
30910
- // src/sap-ai-chat-settings.ts
31033
+ // src/sap-ai-settings.ts
30911
31034
  var import_orchestration2 = require("@sap-ai-sdk/orchestration");
30912
-
30913
- // src/types/completion-request.ts
30914
31035
  var import_orchestration3 = require("@sap-ai-sdk/orchestration");
30915
31036
 
30916
- // src/types/completion-response.ts
30917
- var import_orchestration4 = require("@sap-ai-sdk/orchestration");
30918
-
30919
31037
  // src/index.ts
30920
- var import_orchestration5 = require("@sap-ai-sdk/orchestration");
31038
+ var import_orchestration4 = require("@sap-ai-sdk/orchestration");
30921
31039
  // Annotate the CommonJS export names for ESM import in node:
30922
31040
  0 && (module.exports = {
30923
31041
  OrchestrationClient,