@jerome-benoit/sap-ai-provider 4.0.0-rc.1 → 4.0.0
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/README.md +120 -102
- package/dist/index.cjs +627 -620
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +265 -188
- package/dist/index.d.ts +265 -188
- package/dist/index.js +628 -622
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
package/dist/index.cjs
CHANGED
|
@@ -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: () =>
|
|
29741
|
-
OrchestrationResponse: () =>
|
|
29742
|
-
OrchestrationStreamChunkResponse: () =>
|
|
29743
|
-
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: () =>
|
|
29750
|
+
isConfigReference: () => import_orchestration2.isConfigReference,
|
|
29751
29751
|
sapai: () => sapai
|
|
29752
29752
|
});
|
|
29753
29753
|
module.exports = __toCommonJS(index_exports);
|
|
29754
29754
|
|
|
29755
|
-
// src/sap-ai-
|
|
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
|
-
|
|
29770
|
-
|
|
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,80 +29899,18 @@ function convertToSAPMessages(prompt, options = {}) {
|
|
|
29839
29899
|
}
|
|
29840
29900
|
}
|
|
29841
29901
|
const userMessage = contentParts.length === 1 && contentParts[0].type === "text" ? {
|
|
29842
|
-
|
|
29843
|
-
|
|
29902
|
+
content: contentParts[0].text ?? "",
|
|
29903
|
+
role: "user"
|
|
29844
29904
|
} : {
|
|
29845
|
-
|
|
29846
|
-
|
|
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
|
-
if (part.type === "tool-result") {
|
|
29901
|
-
const toolMessage = {
|
|
29902
|
-
role: "tool",
|
|
29903
|
-
tool_call_id: part.toolCallId,
|
|
29904
|
-
content: JSON.stringify(part.output)
|
|
29905
|
-
};
|
|
29906
|
-
messages.push(toolMessage);
|
|
29907
|
-
}
|
|
29908
|
-
}
|
|
29909
|
-
break;
|
|
29910
|
-
}
|
|
29911
29911
|
default: {
|
|
29912
29912
|
const _exhaustiveCheck = message;
|
|
29913
|
-
throw new Error(
|
|
29914
|
-
`Unsupported role: ${_exhaustiveCheck.role}`
|
|
29915
|
-
);
|
|
29913
|
+
throw new Error(`Unsupported role: ${_exhaustiveCheck.role}`);
|
|
29916
29914
|
}
|
|
29917
29915
|
}
|
|
29918
29916
|
}
|
|
@@ -29922,16 +29920,6 @@ function convertToSAPMessages(prompt, options = {}) {
|
|
|
29922
29920
|
// src/sap-ai-error.ts
|
|
29923
29921
|
var import_provider2 = require("@ai-sdk/provider");
|
|
29924
29922
|
var import_util = __toESM(require_dist(), 1);
|
|
29925
|
-
function getStatusCodeFromSAPError(code) {
|
|
29926
|
-
if (!code) return 500;
|
|
29927
|
-
if (code >= 100 && code < 600) {
|
|
29928
|
-
return code;
|
|
29929
|
-
}
|
|
29930
|
-
return 500;
|
|
29931
|
-
}
|
|
29932
|
-
function isRetryable(statusCode) {
|
|
29933
|
-
return statusCode === 429 || statusCode >= 500 && statusCode < 600;
|
|
29934
|
-
}
|
|
29935
29923
|
function convertSAPErrorToAPICallError(errorResponse, context) {
|
|
29936
29924
|
const error = errorResponse.error;
|
|
29937
29925
|
let message;
|
|
@@ -29953,9 +29941,9 @@ function convertSAPErrorToAPICallError(errorResponse, context) {
|
|
|
29953
29941
|
const statusCode = getStatusCodeFromSAPError(code);
|
|
29954
29942
|
const responseBody = JSON.stringify({
|
|
29955
29943
|
error: {
|
|
29956
|
-
message,
|
|
29957
29944
|
code,
|
|
29958
29945
|
location,
|
|
29946
|
+
message,
|
|
29959
29947
|
request_id: requestId
|
|
29960
29948
|
}
|
|
29961
29949
|
});
|
|
@@ -29978,53 +29966,14 @@ Error location: ${location}`;
|
|
|
29978
29966
|
Request ID: ${requestId}`;
|
|
29979
29967
|
}
|
|
29980
29968
|
return new import_provider2.APICallError({
|
|
29969
|
+
isRetryable: isRetryable(statusCode),
|
|
29981
29970
|
message: enhancedMessage,
|
|
29982
|
-
url: context?.url ?? "",
|
|
29983
29971
|
requestBodyValues: context?.requestBody,
|
|
29984
|
-
statusCode,
|
|
29985
|
-
responseHeaders: context?.responseHeaders,
|
|
29986
29972
|
responseBody,
|
|
29987
|
-
|
|
29988
|
-
|
|
29989
|
-
|
|
29990
|
-
function isOrchestrationErrorResponse(error) {
|
|
29991
|
-
if (error === null || typeof error !== "object" || !("error" in error)) {
|
|
29992
|
-
return false;
|
|
29993
|
-
}
|
|
29994
|
-
const errorEnvelope = error;
|
|
29995
|
-
const innerError = errorEnvelope.error;
|
|
29996
|
-
if (innerError === void 0) return false;
|
|
29997
|
-
if (Array.isArray(innerError)) {
|
|
29998
|
-
return innerError.every(
|
|
29999
|
-
(entry) => entry !== null && typeof entry === "object" && "message" in entry && typeof entry.message === "string"
|
|
30000
|
-
);
|
|
30001
|
-
}
|
|
30002
|
-
return typeof innerError === "object" && innerError !== null && "message" in innerError && typeof innerError.message === "string";
|
|
30003
|
-
}
|
|
30004
|
-
function normalizeHeaders(headers) {
|
|
30005
|
-
if (!headers || typeof headers !== "object") return void 0;
|
|
30006
|
-
const record = headers;
|
|
30007
|
-
const entries = Object.entries(record).flatMap(([key, value]) => {
|
|
30008
|
-
if (typeof value === "string") return [[key, value]];
|
|
30009
|
-
if (Array.isArray(value)) {
|
|
30010
|
-
const strings = value.filter((item) => typeof item === "string").join("; ");
|
|
30011
|
-
return strings.length > 0 ? [[key, strings]] : [];
|
|
30012
|
-
}
|
|
30013
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
30014
|
-
return [[key, String(value)]];
|
|
30015
|
-
}
|
|
30016
|
-
return [];
|
|
29973
|
+
responseHeaders: context?.responseHeaders,
|
|
29974
|
+
statusCode,
|
|
29975
|
+
url: context?.url ?? ""
|
|
30017
29976
|
});
|
|
30018
|
-
if (entries.length === 0) return void 0;
|
|
30019
|
-
return Object.fromEntries(entries);
|
|
30020
|
-
}
|
|
30021
|
-
function getAxiosResponseHeaders(error) {
|
|
30022
|
-
if (!(error instanceof Error)) return void 0;
|
|
30023
|
-
const rootCause = (0, import_util.isErrorWithCause)(error) ? error.rootCause : error;
|
|
30024
|
-
if (typeof rootCause !== "object") return void 0;
|
|
30025
|
-
const maybeAxios = rootCause;
|
|
30026
|
-
if (maybeAxios.isAxiosError !== true) return void 0;
|
|
30027
|
-
return normalizeHeaders(maybeAxios.response?.headers);
|
|
30028
29977
|
}
|
|
30029
29978
|
function convertToAISDKError(error, context) {
|
|
30030
29979
|
if (error instanceof import_provider2.APICallError || error instanceof import_provider2.LoadAPIKeyError) {
|
|
@@ -30049,30 +29998,79 @@ See: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-serv
|
|
|
30049
29998
|
}
|
|
30050
29999
|
if (errorMsg.includes("econnrefused") || errorMsg.includes("enotfound") || errorMsg.includes("network") || errorMsg.includes("timeout")) {
|
|
30051
30000
|
return new import_provider2.APICallError({
|
|
30001
|
+
cause: error,
|
|
30002
|
+
isRetryable: true,
|
|
30052
30003
|
message: `Network error connecting to SAP AI Core: ${error.message}`,
|
|
30053
|
-
url: context?.url ?? "",
|
|
30054
30004
|
requestBodyValues: context?.requestBody,
|
|
30055
|
-
statusCode: 503,
|
|
30056
|
-
isRetryable: true,
|
|
30057
30005
|
responseHeaders,
|
|
30058
|
-
|
|
30006
|
+
statusCode: 503,
|
|
30007
|
+
url: context?.url ?? ""
|
|
30059
30008
|
});
|
|
30060
30009
|
}
|
|
30061
30010
|
}
|
|
30062
30011
|
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown error occurred";
|
|
30063
30012
|
const fullMessage = context?.operation ? `SAP AI Core ${context.operation} failed: ${message}` : `SAP AI Core error: ${message}`;
|
|
30064
30013
|
return new import_provider2.APICallError({
|
|
30014
|
+
cause: error,
|
|
30015
|
+
isRetryable: false,
|
|
30065
30016
|
message: fullMessage,
|
|
30066
|
-
url: context?.url ?? "",
|
|
30067
30017
|
requestBodyValues: context?.requestBody,
|
|
30068
|
-
statusCode: 500,
|
|
30069
|
-
isRetryable: false,
|
|
30070
30018
|
responseHeaders,
|
|
30071
|
-
|
|
30019
|
+
statusCode: 500,
|
|
30020
|
+
url: context?.url ?? ""
|
|
30021
|
+
});
|
|
30022
|
+
}
|
|
30023
|
+
function getAxiosResponseHeaders(error) {
|
|
30024
|
+
if (!(error instanceof Error)) return void 0;
|
|
30025
|
+
const rootCause = (0, import_util.isErrorWithCause)(error) ? error.rootCause : error;
|
|
30026
|
+
if (typeof rootCause !== "object") return void 0;
|
|
30027
|
+
const maybeAxios = rootCause;
|
|
30028
|
+
if (maybeAxios.isAxiosError !== true) return void 0;
|
|
30029
|
+
return normalizeHeaders(maybeAxios.response?.headers);
|
|
30030
|
+
}
|
|
30031
|
+
function getStatusCodeFromSAPError(code) {
|
|
30032
|
+
if (!code) return 500;
|
|
30033
|
+
if (code >= 100 && code < 600) {
|
|
30034
|
+
return code;
|
|
30035
|
+
}
|
|
30036
|
+
return 500;
|
|
30037
|
+
}
|
|
30038
|
+
function isOrchestrationErrorResponse(error) {
|
|
30039
|
+
if (error === null || typeof error !== "object" || !("error" in error)) {
|
|
30040
|
+
return false;
|
|
30041
|
+
}
|
|
30042
|
+
const errorEnvelope = error;
|
|
30043
|
+
const innerError = errorEnvelope.error;
|
|
30044
|
+
if (innerError === void 0) return false;
|
|
30045
|
+
if (Array.isArray(innerError)) {
|
|
30046
|
+
return innerError.every(
|
|
30047
|
+
(entry) => entry !== null && typeof entry === "object" && "message" in entry && typeof entry.message === "string"
|
|
30048
|
+
);
|
|
30049
|
+
}
|
|
30050
|
+
return typeof innerError === "object" && innerError !== null && "message" in innerError && typeof innerError.message === "string";
|
|
30051
|
+
}
|
|
30052
|
+
function isRetryable(statusCode) {
|
|
30053
|
+
return statusCode === 429 || statusCode >= 500 && statusCode < 600;
|
|
30054
|
+
}
|
|
30055
|
+
function normalizeHeaders(headers) {
|
|
30056
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
30057
|
+
const record = headers;
|
|
30058
|
+
const entries = Object.entries(record).flatMap(([key, value]) => {
|
|
30059
|
+
if (typeof value === "string") return [[key, value]];
|
|
30060
|
+
if (Array.isArray(value)) {
|
|
30061
|
+
const strings = value.filter((item) => typeof item === "string").join("; ");
|
|
30062
|
+
return strings.length > 0 ? [[key, strings]] : [];
|
|
30063
|
+
}
|
|
30064
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
30065
|
+
return [[key, String(value)]];
|
|
30066
|
+
}
|
|
30067
|
+
return [];
|
|
30072
30068
|
});
|
|
30069
|
+
if (entries.length === 0) return void 0;
|
|
30070
|
+
return Object.fromEntries(entries);
|
|
30073
30071
|
}
|
|
30074
30072
|
|
|
30075
|
-
// src/sap-ai-
|
|
30073
|
+
// src/sap-ai-language-model.ts
|
|
30076
30074
|
var StreamIdGenerator = class {
|
|
30077
30075
|
/**
|
|
30078
30076
|
* Generates a unique ID for a text block.
|
|
@@ -30083,139 +30081,27 @@ var StreamIdGenerator = class {
|
|
|
30083
30081
|
return crypto.randomUUID();
|
|
30084
30082
|
}
|
|
30085
30083
|
};
|
|
30086
|
-
|
|
30087
|
-
if (params.temperature !== void 0 && (params.temperature < 0 || params.temperature > 2)) {
|
|
30088
|
-
warnings.push({
|
|
30089
|
-
type: "other",
|
|
30090
|
-
message: `temperature=${String(params.temperature)} is outside typical range [0, 2]. The API may reject this value.`
|
|
30091
|
-
});
|
|
30092
|
-
}
|
|
30093
|
-
if (params.topP !== void 0 && (params.topP < 0 || params.topP > 1)) {
|
|
30094
|
-
warnings.push({
|
|
30095
|
-
type: "other",
|
|
30096
|
-
message: `topP=${String(params.topP)} is outside valid range [0, 1]. The API may reject this value.`
|
|
30097
|
-
});
|
|
30098
|
-
}
|
|
30099
|
-
if (params.frequencyPenalty !== void 0 && (params.frequencyPenalty < -2 || params.frequencyPenalty > 2)) {
|
|
30100
|
-
warnings.push({
|
|
30101
|
-
type: "other",
|
|
30102
|
-
message: `frequencyPenalty=${String(params.frequencyPenalty)} is outside typical range [-2, 2]. The API may reject this value.`
|
|
30103
|
-
});
|
|
30104
|
-
}
|
|
30105
|
-
if (params.presencePenalty !== void 0 && (params.presencePenalty < -2 || params.presencePenalty > 2)) {
|
|
30106
|
-
warnings.push({
|
|
30107
|
-
type: "other",
|
|
30108
|
-
message: `presencePenalty=${String(params.presencePenalty)} is outside typical range [-2, 2]. The API may reject this value.`
|
|
30109
|
-
});
|
|
30110
|
-
}
|
|
30111
|
-
if (params.maxTokens !== void 0 && params.maxTokens <= 0) {
|
|
30112
|
-
warnings.push({
|
|
30113
|
-
type: "other",
|
|
30114
|
-
message: `maxTokens=${String(params.maxTokens)} must be positive. The API will likely reject this value.`
|
|
30115
|
-
});
|
|
30116
|
-
}
|
|
30117
|
-
if (params.n !== void 0 && params.n <= 0) {
|
|
30118
|
-
warnings.push({
|
|
30119
|
-
type: "other",
|
|
30120
|
-
message: `n=${String(params.n)} must be positive. The API will likely reject this value.`
|
|
30121
|
-
});
|
|
30122
|
-
}
|
|
30123
|
-
}
|
|
30124
|
-
function createAISDKRequestBodySummary(options) {
|
|
30125
|
-
return {
|
|
30126
|
-
promptMessages: options.prompt.length,
|
|
30127
|
-
hasImageParts: options.prompt.some(
|
|
30128
|
-
(message) => message.role === "user" && message.content.some(
|
|
30129
|
-
(part) => part.type === "file" && part.mediaType.startsWith("image/")
|
|
30130
|
-
)
|
|
30131
|
-
),
|
|
30132
|
-
tools: options.tools?.length ?? 0,
|
|
30133
|
-
temperature: options.temperature,
|
|
30134
|
-
topP: options.topP,
|
|
30135
|
-
topK: options.topK,
|
|
30136
|
-
maxOutputTokens: options.maxOutputTokens,
|
|
30137
|
-
stopSequences: options.stopSequences?.length,
|
|
30138
|
-
seed: options.seed,
|
|
30139
|
-
toolChoiceType: options.toolChoice?.type,
|
|
30140
|
-
responseFormatType: options.responseFormat?.type
|
|
30141
|
-
};
|
|
30142
|
-
}
|
|
30143
|
-
function hasCallableParse(obj) {
|
|
30144
|
-
return typeof obj.parse === "function";
|
|
30145
|
-
}
|
|
30146
|
-
function isZodSchema(obj) {
|
|
30147
|
-
if (obj === null || typeof obj !== "object") {
|
|
30148
|
-
return false;
|
|
30149
|
-
}
|
|
30150
|
-
const record = obj;
|
|
30151
|
-
return "_def" in record && "parse" in record && hasCallableParse(record);
|
|
30152
|
-
}
|
|
30153
|
-
function buildSAPToolParameters(schema) {
|
|
30154
|
-
const schemaType = schema.type;
|
|
30155
|
-
if (schemaType !== void 0 && schemaType !== "object") {
|
|
30156
|
-
return {
|
|
30157
|
-
type: "object",
|
|
30158
|
-
properties: {},
|
|
30159
|
-
required: []
|
|
30160
|
-
};
|
|
30161
|
-
}
|
|
30162
|
-
const properties = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
|
|
30163
|
-
const required = Array.isArray(schema.required) && schema.required.every((item) => typeof item === "string") ? schema.required : [];
|
|
30164
|
-
const additionalFields = Object.fromEntries(
|
|
30165
|
-
Object.entries(schema).filter(
|
|
30166
|
-
([key]) => key !== "type" && key !== "properties" && key !== "required"
|
|
30167
|
-
)
|
|
30168
|
-
);
|
|
30169
|
-
return {
|
|
30170
|
-
type: "object",
|
|
30171
|
-
properties,
|
|
30172
|
-
required,
|
|
30173
|
-
...additionalFields
|
|
30174
|
-
};
|
|
30175
|
-
}
|
|
30176
|
-
var SAPAIChatLanguageModel = class {
|
|
30177
|
-
specificationVersion = "v3";
|
|
30084
|
+
var SAPAILanguageModel = class {
|
|
30178
30085
|
modelId;
|
|
30179
|
-
|
|
30180
|
-
settings;
|
|
30181
|
-
/**
|
|
30182
|
-
* Creates a new SAP AI Chat Language Model instance.
|
|
30183
|
-
*
|
|
30184
|
-
* @param modelId - The model identifier
|
|
30185
|
-
* @param settings - Model-specific configuration settings
|
|
30186
|
-
* @param config - Internal configuration (deployment config, destination, etc.)
|
|
30187
|
-
*
|
|
30188
|
-
* @internal This constructor is not meant to be called directly.
|
|
30189
|
-
* Use the provider function instead.
|
|
30190
|
-
*/
|
|
30191
|
-
constructor(modelId, settings, config) {
|
|
30192
|
-
this.settings = settings;
|
|
30193
|
-
this.config = config;
|
|
30194
|
-
this.modelId = modelId;
|
|
30195
|
-
}
|
|
30196
|
-
/**
|
|
30197
|
-
* Checks if a URL is supported for file/image uploads.
|
|
30198
|
-
*
|
|
30199
|
-
* @param url - The URL to check
|
|
30200
|
-
* @returns True if the URL protocol is HTTPS or data with valid image format
|
|
30201
|
-
*/
|
|
30202
|
-
supportsUrl(url) {
|
|
30203
|
-
if (url.protocol === "https:") return true;
|
|
30204
|
-
if (url.protocol === "data:") {
|
|
30205
|
-
return /^data:image\//i.test(url.href);
|
|
30206
|
-
}
|
|
30207
|
-
return false;
|
|
30208
|
-
}
|
|
30086
|
+
specificationVersion = "v3";
|
|
30209
30087
|
/**
|
|
30210
|
-
*
|
|
30088
|
+
* Model capabilities.
|
|
30211
30089
|
*
|
|
30212
|
-
*
|
|
30090
|
+
* These defaults assume “modern” model behavior to avoid maintaining a
|
|
30091
|
+
* per-model capability matrix. If a deployment doesn't support a feature,
|
|
30092
|
+
* SAP AI Core will fail the request at runtime.
|
|
30213
30093
|
*/
|
|
30214
|
-
|
|
30215
|
-
|
|
30216
|
-
|
|
30217
|
-
|
|
30218
|
-
|
|
30094
|
+
supportsImageUrls = true;
|
|
30095
|
+
/** Multiple completions via the `n` parameter (provider-specific support). */
|
|
30096
|
+
supportsMultipleCompletions = true;
|
|
30097
|
+
/** Parallel tool calls. */
|
|
30098
|
+
supportsParallelToolCalls = true;
|
|
30099
|
+
/** Streaming responses. */
|
|
30100
|
+
supportsStreaming = true;
|
|
30101
|
+
/** Structured JSON outputs (json_schema response format). */
|
|
30102
|
+
supportsStructuredOutputs = true;
|
|
30103
|
+
/** Tool/function calling. */
|
|
30104
|
+
supportsToolCalls = true;
|
|
30219
30105
|
/**
|
|
30220
30106
|
* Generates text completion using SAP AI Core's Orchestration API.
|
|
30221
30107
|
*
|
|
@@ -30261,206 +30147,31 @@ var SAPAIChatLanguageModel = class {
|
|
|
30261
30147
|
return this.config.provider;
|
|
30262
30148
|
}
|
|
30263
30149
|
/**
|
|
30264
|
-
*
|
|
30265
|
-
*
|
|
30266
|
-
* These defaults assume “modern” model behavior to avoid maintaining a
|
|
30267
|
-
* per-model capability matrix. If a deployment doesn't support a feature,
|
|
30268
|
-
* SAP AI Core will fail the request at runtime.
|
|
30269
|
-
*/
|
|
30270
|
-
supportsImageUrls = true;
|
|
30271
|
-
/** Structured JSON outputs (json_schema response format). */
|
|
30272
|
-
supportsStructuredOutputs = true;
|
|
30273
|
-
/** Tool/function calling. */
|
|
30274
|
-
supportsToolCalls = true;
|
|
30275
|
-
/** Streaming responses. */
|
|
30276
|
-
supportsStreaming = true;
|
|
30277
|
-
/** Multiple completions via the `n` parameter (provider-specific support). */
|
|
30278
|
-
supportsMultipleCompletions = true;
|
|
30279
|
-
/** Parallel tool calls. */
|
|
30280
|
-
supportsParallelToolCalls = true;
|
|
30281
|
-
/**
|
|
30282
|
-
* Builds orchestration module config for SAP AI SDK.
|
|
30150
|
+
* Returns supported URL patterns for different content types.
|
|
30283
30151
|
*
|
|
30284
|
-
* @
|
|
30285
|
-
* @returns Object containing orchestration config, messages, and warnings
|
|
30286
|
-
* @internal
|
|
30152
|
+
* @returns Record of content types to regex patterns
|
|
30287
30153
|
*/
|
|
30288
|
-
|
|
30289
|
-
|
|
30290
|
-
|
|
30291
|
-
const messages = convertToSAPMessages(options.prompt, {
|
|
30292
|
-
includeReasoning: providerOptions.includeReasoning ?? this.settings.includeReasoning ?? false
|
|
30293
|
-
});
|
|
30294
|
-
let tools;
|
|
30295
|
-
const settingsTools = providerOptions.tools ?? this.settings.tools;
|
|
30296
|
-
const optionsTools = options.tools;
|
|
30297
|
-
const shouldUseSettingsTools = settingsTools && settingsTools.length > 0 && (!optionsTools || optionsTools.length === 0);
|
|
30298
|
-
const shouldUseOptionsTools = !!(optionsTools && optionsTools.length > 0);
|
|
30299
|
-
if (settingsTools && settingsTools.length > 0 && optionsTools && optionsTools.length > 0) {
|
|
30300
|
-
warnings.push({
|
|
30301
|
-
type: "other",
|
|
30302
|
-
message: "Both settings.tools and call options.tools were provided; preferring call options.tools."
|
|
30303
|
-
});
|
|
30304
|
-
}
|
|
30305
|
-
if (shouldUseSettingsTools) {
|
|
30306
|
-
tools = settingsTools;
|
|
30307
|
-
} else {
|
|
30308
|
-
const availableTools = shouldUseOptionsTools ? optionsTools : void 0;
|
|
30309
|
-
tools = availableTools?.map((tool) => {
|
|
30310
|
-
if (tool.type === "function") {
|
|
30311
|
-
const inputSchema = tool.inputSchema;
|
|
30312
|
-
const toolWithParams = tool;
|
|
30313
|
-
let parameters;
|
|
30314
|
-
if (toolWithParams.parameters && isZodSchema(toolWithParams.parameters)) {
|
|
30315
|
-
try {
|
|
30316
|
-
const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(
|
|
30317
|
-
toolWithParams.parameters,
|
|
30318
|
-
{
|
|
30319
|
-
$refStrategy: "none"
|
|
30320
|
-
}
|
|
30321
|
-
);
|
|
30322
|
-
const schemaRecord = jsonSchema;
|
|
30323
|
-
delete schemaRecord.$schema;
|
|
30324
|
-
parameters = buildSAPToolParameters(schemaRecord);
|
|
30325
|
-
} catch (error) {
|
|
30326
|
-
warnings.push({
|
|
30327
|
-
type: "unsupported",
|
|
30328
|
-
feature: `tool schema conversion for ${tool.name}`,
|
|
30329
|
-
details: `Failed to convert tool Zod schema: ${error instanceof Error ? error.message : String(error)}. Falling back to empty object schema.`
|
|
30330
|
-
});
|
|
30331
|
-
parameters = buildSAPToolParameters({});
|
|
30332
|
-
}
|
|
30333
|
-
} else if (inputSchema && Object.keys(inputSchema).length > 0) {
|
|
30334
|
-
const hasProperties = inputSchema.properties && typeof inputSchema.properties === "object" && Object.keys(inputSchema.properties).length > 0;
|
|
30335
|
-
if (hasProperties) {
|
|
30336
|
-
parameters = buildSAPToolParameters(inputSchema);
|
|
30337
|
-
} else {
|
|
30338
|
-
parameters = buildSAPToolParameters({});
|
|
30339
|
-
}
|
|
30340
|
-
} else {
|
|
30341
|
-
parameters = buildSAPToolParameters({});
|
|
30342
|
-
}
|
|
30343
|
-
return {
|
|
30344
|
-
type: "function",
|
|
30345
|
-
function: {
|
|
30346
|
-
name: tool.name,
|
|
30347
|
-
description: tool.description,
|
|
30348
|
-
parameters
|
|
30349
|
-
}
|
|
30350
|
-
};
|
|
30351
|
-
} else {
|
|
30352
|
-
warnings.push({
|
|
30353
|
-
type: "unsupported",
|
|
30354
|
-
feature: `tool type for ${tool.name}`,
|
|
30355
|
-
details: "Only 'function' tool type is supported."
|
|
30356
|
-
});
|
|
30357
|
-
return null;
|
|
30358
|
-
}
|
|
30359
|
-
}).filter((t) => t !== null);
|
|
30360
|
-
}
|
|
30361
|
-
const supportsN = !this.modelId.startsWith("amazon--") && !this.modelId.startsWith("anthropic--");
|
|
30362
|
-
const modelParams = {};
|
|
30363
|
-
const maxTokens = options.maxOutputTokens ?? providerOptions.modelParams?.maxTokens ?? this.settings.modelParams?.maxTokens;
|
|
30364
|
-
if (maxTokens !== void 0) modelParams.max_tokens = maxTokens;
|
|
30365
|
-
const temperature = options.temperature ?? providerOptions.modelParams?.temperature ?? this.settings.modelParams?.temperature;
|
|
30366
|
-
if (temperature !== void 0) modelParams.temperature = temperature;
|
|
30367
|
-
const topP = options.topP ?? providerOptions.modelParams?.topP ?? this.settings.modelParams?.topP;
|
|
30368
|
-
if (topP !== void 0) modelParams.top_p = topP;
|
|
30369
|
-
if (options.topK !== void 0) modelParams.top_k = options.topK;
|
|
30370
|
-
const frequencyPenalty = options.frequencyPenalty ?? providerOptions.modelParams?.frequencyPenalty ?? this.settings.modelParams?.frequencyPenalty;
|
|
30371
|
-
if (frequencyPenalty !== void 0) {
|
|
30372
|
-
modelParams.frequency_penalty = frequencyPenalty;
|
|
30373
|
-
}
|
|
30374
|
-
const presencePenalty = options.presencePenalty ?? providerOptions.modelParams?.presencePenalty ?? this.settings.modelParams?.presencePenalty;
|
|
30375
|
-
if (presencePenalty !== void 0) {
|
|
30376
|
-
modelParams.presence_penalty = presencePenalty;
|
|
30377
|
-
}
|
|
30378
|
-
if (supportsN) {
|
|
30379
|
-
const nValue = providerOptions.modelParams?.n ?? this.settings.modelParams?.n;
|
|
30380
|
-
if (nValue !== void 0) {
|
|
30381
|
-
modelParams.n = nValue;
|
|
30382
|
-
}
|
|
30383
|
-
}
|
|
30384
|
-
const parallelToolCalls = providerOptions.modelParams?.parallel_tool_calls ?? this.settings.modelParams?.parallel_tool_calls;
|
|
30385
|
-
if (parallelToolCalls !== void 0) {
|
|
30386
|
-
modelParams.parallel_tool_calls = parallelToolCalls;
|
|
30387
|
-
}
|
|
30388
|
-
if (options.stopSequences && options.stopSequences.length > 0) {
|
|
30389
|
-
modelParams.stop = options.stopSequences;
|
|
30390
|
-
}
|
|
30391
|
-
if (options.seed !== void 0) {
|
|
30392
|
-
modelParams.seed = options.seed;
|
|
30393
|
-
}
|
|
30394
|
-
validateModelParameters(
|
|
30395
|
-
{
|
|
30396
|
-
temperature,
|
|
30397
|
-
topP,
|
|
30398
|
-
frequencyPenalty,
|
|
30399
|
-
presencePenalty,
|
|
30400
|
-
maxTokens,
|
|
30401
|
-
n: modelParams.n
|
|
30402
|
-
},
|
|
30403
|
-
warnings
|
|
30404
|
-
);
|
|
30405
|
-
if (options.toolChoice && options.toolChoice.type !== "auto") {
|
|
30406
|
-
warnings.push({
|
|
30407
|
-
type: "unsupported",
|
|
30408
|
-
feature: "toolChoice",
|
|
30409
|
-
details: `SAP AI SDK does not support toolChoice '${options.toolChoice.type}'. Using default 'auto' behavior.`
|
|
30410
|
-
});
|
|
30411
|
-
}
|
|
30412
|
-
if (options.responseFormat?.type === "json") {
|
|
30413
|
-
warnings.push({
|
|
30414
|
-
type: "other",
|
|
30415
|
-
message: "responseFormat JSON mode is forwarded to the underlying model; support and schema adherence depend on the model/deployment."
|
|
30416
|
-
});
|
|
30417
|
-
}
|
|
30418
|
-
const responseFormat = options.responseFormat?.type === "json" ? options.responseFormat.schema ? {
|
|
30419
|
-
type: "json_schema",
|
|
30420
|
-
json_schema: {
|
|
30421
|
-
name: options.responseFormat.name ?? "response",
|
|
30422
|
-
description: options.responseFormat.description,
|
|
30423
|
-
schema: options.responseFormat.schema,
|
|
30424
|
-
strict: null
|
|
30425
|
-
}
|
|
30426
|
-
} : { type: "json_object" } : void 0;
|
|
30427
|
-
const orchestrationConfig = {
|
|
30428
|
-
promptTemplating: {
|
|
30429
|
-
model: {
|
|
30430
|
-
name: this.modelId,
|
|
30431
|
-
version: providerOptions.modelVersion ?? this.settings.modelVersion ?? "latest",
|
|
30432
|
-
params: modelParams
|
|
30433
|
-
},
|
|
30434
|
-
prompt: {
|
|
30435
|
-
template: [],
|
|
30436
|
-
tools: tools && tools.length > 0 ? tools : void 0,
|
|
30437
|
-
...responseFormat ? { response_format: responseFormat } : {}
|
|
30438
|
-
}
|
|
30439
|
-
},
|
|
30440
|
-
...(() => {
|
|
30441
|
-
const masking = providerOptions.masking ?? this.settings.masking;
|
|
30442
|
-
return masking && Object.keys(masking).length > 0 ? { masking } : {};
|
|
30443
|
-
})(),
|
|
30444
|
-
...(() => {
|
|
30445
|
-
const filtering = providerOptions.filtering ?? this.settings.filtering;
|
|
30446
|
-
return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
|
|
30447
|
-
})()
|
|
30154
|
+
get supportedUrls() {
|
|
30155
|
+
return {
|
|
30156
|
+
"image/*": [/^https:\/\/.+$/i, /^data:image\/.*$/]
|
|
30448
30157
|
};
|
|
30449
|
-
return { orchestrationConfig, messages, warnings };
|
|
30450
30158
|
}
|
|
30159
|
+
config;
|
|
30160
|
+
settings;
|
|
30451
30161
|
/**
|
|
30452
|
-
* Creates
|
|
30162
|
+
* Creates a new SAP AI Chat Language Model instance.
|
|
30453
30163
|
*
|
|
30454
|
-
* @param
|
|
30455
|
-
* @
|
|
30456
|
-
* @
|
|
30164
|
+
* @param modelId - The model identifier
|
|
30165
|
+
* @param settings - Model-specific configuration settings
|
|
30166
|
+
* @param config - Internal configuration (deployment config, destination, etc.)
|
|
30167
|
+
*
|
|
30168
|
+
* @internal This constructor is not meant to be called directly.
|
|
30169
|
+
* Use the provider function instead.
|
|
30457
30170
|
*/
|
|
30458
|
-
|
|
30459
|
-
|
|
30460
|
-
|
|
30461
|
-
|
|
30462
|
-
this.config.destination
|
|
30463
|
-
);
|
|
30171
|
+
constructor(modelId, settings, config) {
|
|
30172
|
+
this.settings = settings;
|
|
30173
|
+
this.config = config;
|
|
30174
|
+
this.modelId = modelId;
|
|
30464
30175
|
}
|
|
30465
30176
|
/**
|
|
30466
30177
|
* Generates a single completion (non-streaming).
|
|
@@ -30481,6 +30192,8 @@ var SAPAIChatLanguageModel = class {
|
|
|
30481
30192
|
* to SAP AI Core - the request continues executing on the server. This is a
|
|
30482
30193
|
* limitation of the SAP AI SDK's chatCompletion API.
|
|
30483
30194
|
*
|
|
30195
|
+
* @see https://github.com/SAP/ai-sdk-js/issues/1429 for tracking true cancellation support
|
|
30196
|
+
*
|
|
30484
30197
|
* @param options - Generation options including prompt, tools, and settings
|
|
30485
30198
|
* @returns Promise resolving to the generation result with content, usage, and metadata
|
|
30486
30199
|
*
|
|
@@ -30498,7 +30211,7 @@ var SAPAIChatLanguageModel = class {
|
|
|
30498
30211
|
*/
|
|
30499
30212
|
async doGenerate(options) {
|
|
30500
30213
|
try {
|
|
30501
|
-
const {
|
|
30214
|
+
const { messages, orchestrationConfig, warnings } = this.buildOrchestrationConfig(options);
|
|
30502
30215
|
const client = this.createClient(orchestrationConfig);
|
|
30503
30216
|
const promptTemplating = orchestrationConfig.promptTemplating;
|
|
30504
30217
|
const requestBody = {
|
|
@@ -30515,6 +30228,14 @@ var SAPAIChatLanguageModel = class {
|
|
|
30515
30228
|
...(() => {
|
|
30516
30229
|
const filtering = orchestrationConfig.filtering;
|
|
30517
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 } : {};
|
|
30518
30239
|
})()
|
|
30519
30240
|
};
|
|
30520
30241
|
const response = await (async () => {
|
|
@@ -30565,18 +30286,18 @@ var SAPAIChatLanguageModel = class {
|
|
|
30565
30286
|
const textContent = response.getContent();
|
|
30566
30287
|
if (textContent) {
|
|
30567
30288
|
content.push({
|
|
30568
|
-
|
|
30569
|
-
|
|
30289
|
+
text: textContent,
|
|
30290
|
+
type: "text"
|
|
30570
30291
|
});
|
|
30571
30292
|
}
|
|
30572
30293
|
const toolCalls = response.getToolCalls();
|
|
30573
30294
|
if (toolCalls) {
|
|
30574
30295
|
for (const toolCall of toolCalls) {
|
|
30575
30296
|
content.push({
|
|
30576
|
-
|
|
30297
|
+
input: toolCall.function.arguments,
|
|
30577
30298
|
toolCallId: toolCall.id,
|
|
30578
30299
|
toolName: toolCall.function.name,
|
|
30579
|
-
|
|
30300
|
+
type: "tool-call"
|
|
30580
30301
|
});
|
|
30581
30302
|
}
|
|
30582
30303
|
}
|
|
@@ -30585,26 +30306,13 @@ var SAPAIChatLanguageModel = class {
|
|
|
30585
30306
|
const finishReason = mapFinishReason(finishReasonRaw);
|
|
30586
30307
|
const rawResponseBody = {
|
|
30587
30308
|
content: textContent,
|
|
30588
|
-
|
|
30309
|
+
finishReason: finishReasonRaw,
|
|
30589
30310
|
tokenUsage,
|
|
30590
|
-
|
|
30311
|
+
toolCalls
|
|
30591
30312
|
};
|
|
30592
30313
|
return {
|
|
30593
30314
|
content,
|
|
30594
30315
|
finishReason,
|
|
30595
|
-
usage: {
|
|
30596
|
-
inputTokens: {
|
|
30597
|
-
total: tokenUsage.prompt_tokens,
|
|
30598
|
-
noCache: tokenUsage.prompt_tokens,
|
|
30599
|
-
cacheRead: void 0,
|
|
30600
|
-
cacheWrite: void 0
|
|
30601
|
-
},
|
|
30602
|
-
outputTokens: {
|
|
30603
|
-
total: tokenUsage.completion_tokens,
|
|
30604
|
-
text: tokenUsage.completion_tokens,
|
|
30605
|
-
reasoning: void 0
|
|
30606
|
-
}
|
|
30607
|
-
},
|
|
30608
30316
|
providerMetadata: {
|
|
30609
30317
|
"sap-ai": {
|
|
30610
30318
|
finishReason: finishReasonRaw ?? "unknown",
|
|
@@ -30616,18 +30324,31 @@ var SAPAIChatLanguageModel = class {
|
|
|
30616
30324
|
body: requestBody
|
|
30617
30325
|
},
|
|
30618
30326
|
response: {
|
|
30619
|
-
|
|
30620
|
-
modelId: this.modelId,
|
|
30327
|
+
body: rawResponseBody,
|
|
30621
30328
|
headers: responseHeaders,
|
|
30622
|
-
|
|
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
|
+
}
|
|
30623
30344
|
},
|
|
30624
30345
|
warnings
|
|
30625
30346
|
};
|
|
30626
30347
|
} catch (error) {
|
|
30627
30348
|
throw convertToAISDKError(error, {
|
|
30628
30349
|
operation: "doGenerate",
|
|
30629
|
-
|
|
30630
|
-
|
|
30350
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
30351
|
+
url: "sap-ai:orchestration"
|
|
30631
30352
|
});
|
|
30632
30353
|
}
|
|
30633
30354
|
}
|
|
@@ -30656,6 +30377,15 @@ var SAPAIChatLanguageModel = class {
|
|
|
30656
30377
|
* - Usage format: `{ inputTokens: { total, ... }, outputTokens: { total, ... } }`
|
|
30657
30378
|
* - Warnings only in `stream-start` event
|
|
30658
30379
|
*
|
|
30380
|
+
* **Note on Abort Signal:**
|
|
30381
|
+
* The abort signal implementation uses Promise.race to reject the promise when
|
|
30382
|
+
* the signal is aborted. However, this does not cancel the underlying HTTP request
|
|
30383
|
+
* to SAP AI Core - the request continues executing on the server. This is a
|
|
30384
|
+
* limitation of the SAP AI SDK's chatCompletion API.
|
|
30385
|
+
*
|
|
30386
|
+
* @see https://github.com/SAP/ai-sdk-js/issues/1429 for tracking true cancellation support
|
|
30387
|
+
* @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/streaming Vercel AI SDK Streaming}
|
|
30388
|
+
*
|
|
30659
30389
|
* @param options - Streaming options including prompt, tools, and settings
|
|
30660
30390
|
* @returns Promise resolving to stream and request metadata
|
|
30661
30391
|
*
|
|
@@ -30681,7 +30411,7 @@ var SAPAIChatLanguageModel = class {
|
|
|
30681
30411
|
*/
|
|
30682
30412
|
async doStream(options) {
|
|
30683
30413
|
try {
|
|
30684
|
-
const {
|
|
30414
|
+
const { messages, orchestrationConfig, warnings } = this.buildOrchestrationConfig(options);
|
|
30685
30415
|
const client = this.createClient(orchestrationConfig);
|
|
30686
30416
|
const promptTemplating = orchestrationConfig.promptTemplating;
|
|
30687
30417
|
const requestBody = {
|
|
@@ -30700,33 +30430,31 @@ var SAPAIChatLanguageModel = class {
|
|
|
30700
30430
|
return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
|
|
30701
30431
|
})()
|
|
30702
30432
|
};
|
|
30703
|
-
const streamResponse = await client.stream(
|
|
30704
|
-
|
|
30705
|
-
|
|
30706
|
-
{ promptTemplating: { include_usage: true } }
|
|
30707
|
-
);
|
|
30433
|
+
const streamResponse = await client.stream(requestBody, options.abortSignal, {
|
|
30434
|
+
promptTemplating: { include_usage: true }
|
|
30435
|
+
});
|
|
30708
30436
|
const idGenerator = new StreamIdGenerator();
|
|
30709
30437
|
let textBlockId = null;
|
|
30710
30438
|
const streamState = {
|
|
30439
|
+
activeText: false,
|
|
30711
30440
|
finishReason: {
|
|
30712
|
-
|
|
30713
|
-
|
|
30441
|
+
raw: void 0,
|
|
30442
|
+
unified: "other"
|
|
30714
30443
|
},
|
|
30444
|
+
isFirstChunk: true,
|
|
30715
30445
|
usage: {
|
|
30716
30446
|
inputTokens: {
|
|
30717
|
-
total: void 0,
|
|
30718
|
-
noCache: void 0,
|
|
30719
30447
|
cacheRead: void 0,
|
|
30720
|
-
cacheWrite: void 0
|
|
30448
|
+
cacheWrite: void 0,
|
|
30449
|
+
noCache: void 0,
|
|
30450
|
+
total: void 0
|
|
30721
30451
|
},
|
|
30722
30452
|
outputTokens: {
|
|
30723
|
-
|
|
30453
|
+
reasoning: void 0,
|
|
30724
30454
|
text: void 0,
|
|
30725
|
-
|
|
30455
|
+
total: void 0
|
|
30726
30456
|
}
|
|
30727
|
-
}
|
|
30728
|
-
isFirstChunk: true,
|
|
30729
|
-
activeText: false
|
|
30457
|
+
}
|
|
30730
30458
|
};
|
|
30731
30459
|
const toolCallsInProgress = /* @__PURE__ */ new Map();
|
|
30732
30460
|
const sdkStream = streamResponse.stream;
|
|
@@ -30734,6 +30462,11 @@ var SAPAIChatLanguageModel = class {
|
|
|
30734
30462
|
const warningsSnapshot = [...warnings];
|
|
30735
30463
|
const warningsOut = [...warningsSnapshot];
|
|
30736
30464
|
const transformedStream = new ReadableStream({
|
|
30465
|
+
cancel(reason) {
|
|
30466
|
+
if (reason) {
|
|
30467
|
+
console.debug("SAP AI stream cancelled:", reason);
|
|
30468
|
+
}
|
|
30469
|
+
},
|
|
30737
30470
|
async start(controller) {
|
|
30738
30471
|
controller.enqueue({
|
|
30739
30472
|
type: "stream-start",
|
|
@@ -30744,30 +30477,30 @@ var SAPAIChatLanguageModel = class {
|
|
|
30744
30477
|
if (streamState.isFirstChunk) {
|
|
30745
30478
|
streamState.isFirstChunk = false;
|
|
30746
30479
|
controller.enqueue({
|
|
30747
|
-
type: "response-metadata",
|
|
30748
30480
|
modelId,
|
|
30749
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
30481
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
30482
|
+
type: "response-metadata"
|
|
30750
30483
|
});
|
|
30751
30484
|
}
|
|
30752
30485
|
const deltaToolCalls = chunk.getDeltaToolCalls();
|
|
30753
30486
|
if (Array.isArray(deltaToolCalls) && deltaToolCalls.length > 0) {
|
|
30754
30487
|
streamState.finishReason = {
|
|
30755
|
-
|
|
30756
|
-
|
|
30488
|
+
raw: void 0,
|
|
30489
|
+
unified: "tool-calls"
|
|
30757
30490
|
};
|
|
30758
30491
|
}
|
|
30759
30492
|
const deltaContent = chunk.getDeltaContent();
|
|
30760
30493
|
if (typeof deltaContent === "string" && deltaContent.length > 0 && streamState.finishReason.unified !== "tool-calls") {
|
|
30761
30494
|
if (!streamState.activeText) {
|
|
30762
30495
|
textBlockId = idGenerator.generateTextBlockId();
|
|
30763
|
-
controller.enqueue({ type: "text-start"
|
|
30496
|
+
controller.enqueue({ id: textBlockId, type: "text-start" });
|
|
30764
30497
|
streamState.activeText = true;
|
|
30765
30498
|
}
|
|
30766
30499
|
if (textBlockId) {
|
|
30767
30500
|
controller.enqueue({
|
|
30768
|
-
|
|
30501
|
+
delta: deltaContent,
|
|
30769
30502
|
id: textBlockId,
|
|
30770
|
-
|
|
30503
|
+
type: "text-delta"
|
|
30771
30504
|
});
|
|
30772
30505
|
}
|
|
30773
30506
|
}
|
|
@@ -30779,11 +30512,11 @@ var SAPAIChatLanguageModel = class {
|
|
|
30779
30512
|
}
|
|
30780
30513
|
if (!toolCallsInProgress.has(index)) {
|
|
30781
30514
|
toolCallsInProgress.set(index, {
|
|
30782
|
-
id: toolCallChunk.id ?? `tool_${String(index)}`,
|
|
30783
|
-
toolName: toolCallChunk.function?.name,
|
|
30784
30515
|
arguments: "",
|
|
30516
|
+
didEmitCall: false,
|
|
30785
30517
|
didEmitInputStart: false,
|
|
30786
|
-
|
|
30518
|
+
id: toolCallChunk.id ?? `tool_${String(index)}`,
|
|
30519
|
+
toolName: toolCallChunk.function?.name
|
|
30787
30520
|
});
|
|
30788
30521
|
}
|
|
30789
30522
|
const tc = toolCallsInProgress.get(index);
|
|
@@ -30798,9 +30531,9 @@ var SAPAIChatLanguageModel = class {
|
|
|
30798
30531
|
if (!tc.didEmitInputStart && tc.toolName) {
|
|
30799
30532
|
tc.didEmitInputStart = true;
|
|
30800
30533
|
controller.enqueue({
|
|
30801
|
-
type: "tool-input-start",
|
|
30802
30534
|
id: tc.id,
|
|
30803
|
-
toolName: tc.toolName
|
|
30535
|
+
toolName: tc.toolName,
|
|
30536
|
+
type: "tool-input-start"
|
|
30804
30537
|
});
|
|
30805
30538
|
}
|
|
30806
30539
|
const argumentsDelta = toolCallChunk.function?.arguments;
|
|
@@ -30808,9 +30541,9 @@ var SAPAIChatLanguageModel = class {
|
|
|
30808
30541
|
tc.arguments += argumentsDelta;
|
|
30809
30542
|
if (tc.didEmitInputStart) {
|
|
30810
30543
|
controller.enqueue({
|
|
30811
|
-
|
|
30544
|
+
delta: argumentsDelta,
|
|
30812
30545
|
id: tc.id,
|
|
30813
|
-
|
|
30546
|
+
type: "tool-input-delta"
|
|
30814
30547
|
});
|
|
30815
30548
|
}
|
|
30816
30549
|
}
|
|
@@ -30828,28 +30561,28 @@ var SAPAIChatLanguageModel = class {
|
|
|
30828
30561
|
if (!tc.didEmitInputStart) {
|
|
30829
30562
|
tc.didEmitInputStart = true;
|
|
30830
30563
|
controller.enqueue({
|
|
30831
|
-
type: "tool-input-start",
|
|
30832
30564
|
id: tc.id,
|
|
30833
|
-
toolName: tc.toolName ?? ""
|
|
30565
|
+
toolName: tc.toolName ?? "",
|
|
30566
|
+
type: "tool-input-start"
|
|
30834
30567
|
});
|
|
30835
30568
|
}
|
|
30836
30569
|
if (!tc.toolName) {
|
|
30837
30570
|
warningsOut.push({
|
|
30838
|
-
|
|
30839
|
-
|
|
30571
|
+
message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name.",
|
|
30572
|
+
type: "other"
|
|
30840
30573
|
});
|
|
30841
30574
|
}
|
|
30842
30575
|
tc.didEmitCall = true;
|
|
30843
|
-
controller.enqueue({ type: "tool-input-end"
|
|
30576
|
+
controller.enqueue({ id: tc.id, type: "tool-input-end" });
|
|
30844
30577
|
controller.enqueue({
|
|
30845
|
-
|
|
30578
|
+
input: tc.arguments,
|
|
30846
30579
|
toolCallId: tc.id,
|
|
30847
30580
|
toolName: tc.toolName ?? "",
|
|
30848
|
-
|
|
30581
|
+
type: "tool-call"
|
|
30849
30582
|
});
|
|
30850
30583
|
}
|
|
30851
30584
|
if (streamState.activeText && textBlockId) {
|
|
30852
|
-
controller.enqueue({ type: "text-end"
|
|
30585
|
+
controller.enqueue({ id: textBlockId, type: "text-end" });
|
|
30853
30586
|
streamState.activeText = false;
|
|
30854
30587
|
}
|
|
30855
30588
|
}
|
|
@@ -30864,109 +30597,390 @@ var SAPAIChatLanguageModel = class {
|
|
|
30864
30597
|
if (!tc.didEmitInputStart) {
|
|
30865
30598
|
tc.didEmitInputStart = true;
|
|
30866
30599
|
controller.enqueue({
|
|
30867
|
-
type: "tool-input-start",
|
|
30868
30600
|
id: tc.id,
|
|
30869
|
-
toolName: tc.toolName ?? ""
|
|
30601
|
+
toolName: tc.toolName ?? "",
|
|
30602
|
+
type: "tool-input-start"
|
|
30870
30603
|
});
|
|
30871
30604
|
}
|
|
30872
30605
|
if (!tc.toolName) {
|
|
30873
30606
|
warningsOut.push({
|
|
30874
|
-
|
|
30875
|
-
|
|
30607
|
+
message: "Received tool-call delta without a tool name. Emitting tool-call with an empty tool name.",
|
|
30608
|
+
type: "other"
|
|
30876
30609
|
});
|
|
30877
30610
|
}
|
|
30878
30611
|
didEmitAnyToolCalls = true;
|
|
30879
30612
|
tc.didEmitCall = true;
|
|
30880
|
-
controller.enqueue({ type: "tool-input-end"
|
|
30613
|
+
controller.enqueue({ id: tc.id, type: "tool-input-end" });
|
|
30881
30614
|
controller.enqueue({
|
|
30882
|
-
|
|
30615
|
+
input: tc.arguments,
|
|
30883
30616
|
toolCallId: tc.id,
|
|
30884
30617
|
toolName: tc.toolName ?? "",
|
|
30885
|
-
|
|
30618
|
+
type: "tool-call"
|
|
30619
|
+
});
|
|
30620
|
+
}
|
|
30621
|
+
if (streamState.activeText && textBlockId) {
|
|
30622
|
+
controller.enqueue({ id: textBlockId, type: "text-end" });
|
|
30623
|
+
}
|
|
30624
|
+
const finalFinishReason = streamResponse.getFinishReason();
|
|
30625
|
+
if (finalFinishReason) {
|
|
30626
|
+
streamState.finishReason = mapFinishReason(finalFinishReason);
|
|
30627
|
+
} else if (didEmitAnyToolCalls) {
|
|
30628
|
+
streamState.finishReason = {
|
|
30629
|
+
raw: void 0,
|
|
30630
|
+
unified: "tool-calls"
|
|
30631
|
+
};
|
|
30632
|
+
}
|
|
30633
|
+
const finalUsage = streamResponse.getTokenUsage();
|
|
30634
|
+
if (finalUsage) {
|
|
30635
|
+
streamState.usage.inputTokens.total = finalUsage.prompt_tokens;
|
|
30636
|
+
streamState.usage.inputTokens.noCache = finalUsage.prompt_tokens;
|
|
30637
|
+
streamState.usage.outputTokens.total = finalUsage.completion_tokens;
|
|
30638
|
+
streamState.usage.outputTokens.text = finalUsage.completion_tokens;
|
|
30639
|
+
}
|
|
30640
|
+
controller.enqueue({
|
|
30641
|
+
finishReason: streamState.finishReason,
|
|
30642
|
+
type: "finish",
|
|
30643
|
+
usage: streamState.usage
|
|
30644
|
+
});
|
|
30645
|
+
controller.close();
|
|
30646
|
+
} catch (error) {
|
|
30647
|
+
const aiError = convertToAISDKError(error, {
|
|
30648
|
+
operation: "doStream",
|
|
30649
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
30650
|
+
url: "sap-ai:orchestration"
|
|
30651
|
+
});
|
|
30652
|
+
controller.enqueue({
|
|
30653
|
+
error: aiError instanceof Error ? aiError : new Error(String(aiError)),
|
|
30654
|
+
type: "error"
|
|
30655
|
+
});
|
|
30656
|
+
controller.close();
|
|
30657
|
+
}
|
|
30658
|
+
}
|
|
30659
|
+
});
|
|
30660
|
+
return {
|
|
30661
|
+
request: {
|
|
30662
|
+
body: requestBody
|
|
30663
|
+
},
|
|
30664
|
+
stream: transformedStream
|
|
30665
|
+
};
|
|
30666
|
+
} catch (error) {
|
|
30667
|
+
throw convertToAISDKError(error, {
|
|
30668
|
+
operation: "doStream",
|
|
30669
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
30670
|
+
url: "sap-ai:orchestration"
|
|
30671
|
+
});
|
|
30672
|
+
}
|
|
30673
|
+
}
|
|
30674
|
+
/**
|
|
30675
|
+
* Checks if a URL is supported for file/image uploads.
|
|
30676
|
+
*
|
|
30677
|
+
* @param url - The URL to check
|
|
30678
|
+
* @returns True if the URL protocol is HTTPS or data with valid image format
|
|
30679
|
+
*/
|
|
30680
|
+
supportsUrl(url) {
|
|
30681
|
+
if (url.protocol === "https:") return true;
|
|
30682
|
+
if (url.protocol === "data:") {
|
|
30683
|
+
return /^data:image\//i.test(url.href);
|
|
30684
|
+
}
|
|
30685
|
+
return false;
|
|
30686
|
+
}
|
|
30687
|
+
/**
|
|
30688
|
+
* Builds orchestration module config for SAP AI SDK.
|
|
30689
|
+
*
|
|
30690
|
+
* @param options - Call options from the AI SDK
|
|
30691
|
+
* @returns Object containing orchestration config, messages, and warnings
|
|
30692
|
+
* @internal
|
|
30693
|
+
*/
|
|
30694
|
+
buildOrchestrationConfig(options) {
|
|
30695
|
+
const providerOptions = options.providerOptions?.sap ?? {};
|
|
30696
|
+
const warnings = [];
|
|
30697
|
+
const messages = convertToSAPMessages(options.prompt, {
|
|
30698
|
+
includeReasoning: providerOptions.includeReasoning ?? this.settings.includeReasoning ?? false
|
|
30699
|
+
});
|
|
30700
|
+
let tools;
|
|
30701
|
+
const settingsTools = providerOptions.tools ?? this.settings.tools;
|
|
30702
|
+
const optionsTools = options.tools;
|
|
30703
|
+
const shouldUseSettingsTools = settingsTools && settingsTools.length > 0 && (!optionsTools || optionsTools.length === 0);
|
|
30704
|
+
const shouldUseOptionsTools = !!(optionsTools && optionsTools.length > 0);
|
|
30705
|
+
if (settingsTools && settingsTools.length > 0 && optionsTools && optionsTools.length > 0) {
|
|
30706
|
+
warnings.push({
|
|
30707
|
+
message: "Both settings.tools and call options.tools were provided; preferring call options.tools.",
|
|
30708
|
+
type: "other"
|
|
30709
|
+
});
|
|
30710
|
+
}
|
|
30711
|
+
if (shouldUseSettingsTools) {
|
|
30712
|
+
tools = settingsTools;
|
|
30713
|
+
} else {
|
|
30714
|
+
const availableTools = shouldUseOptionsTools ? optionsTools : void 0;
|
|
30715
|
+
tools = availableTools?.map((tool) => {
|
|
30716
|
+
if (tool.type === "function") {
|
|
30717
|
+
const inputSchema = tool.inputSchema;
|
|
30718
|
+
const toolWithParams = tool;
|
|
30719
|
+
let parameters;
|
|
30720
|
+
if (toolWithParams.parameters && isZodSchema(toolWithParams.parameters)) {
|
|
30721
|
+
try {
|
|
30722
|
+
const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(toolWithParams.parameters, {
|
|
30723
|
+
$refStrategy: "none"
|
|
30886
30724
|
});
|
|
30725
|
+
const schemaRecord = jsonSchema;
|
|
30726
|
+
delete schemaRecord.$schema;
|
|
30727
|
+
parameters = buildSAPToolParameters(schemaRecord);
|
|
30728
|
+
} catch (error) {
|
|
30729
|
+
warnings.push({
|
|
30730
|
+
details: `Failed to convert tool Zod schema: ${error instanceof Error ? error.message : String(error)}. Falling back to empty object schema.`,
|
|
30731
|
+
feature: `tool schema conversion for ${tool.name}`,
|
|
30732
|
+
type: "unsupported"
|
|
30733
|
+
});
|
|
30734
|
+
parameters = buildSAPToolParameters({});
|
|
30887
30735
|
}
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
30891
|
-
|
|
30892
|
-
|
|
30893
|
-
|
|
30894
|
-
} else if (didEmitAnyToolCalls) {
|
|
30895
|
-
streamState.finishReason = {
|
|
30896
|
-
unified: "tool-calls",
|
|
30897
|
-
raw: void 0
|
|
30898
|
-
};
|
|
30899
|
-
}
|
|
30900
|
-
const finalUsage = streamResponse.getTokenUsage();
|
|
30901
|
-
if (finalUsage) {
|
|
30902
|
-
streamState.usage.inputTokens.total = finalUsage.prompt_tokens;
|
|
30903
|
-
streamState.usage.inputTokens.noCache = finalUsage.prompt_tokens;
|
|
30904
|
-
streamState.usage.outputTokens.total = finalUsage.completion_tokens;
|
|
30905
|
-
streamState.usage.outputTokens.text = finalUsage.completion_tokens;
|
|
30736
|
+
} else if (inputSchema && Object.keys(inputSchema).length > 0) {
|
|
30737
|
+
const hasProperties = inputSchema.properties && typeof inputSchema.properties === "object" && Object.keys(inputSchema.properties).length > 0;
|
|
30738
|
+
if (hasProperties) {
|
|
30739
|
+
parameters = buildSAPToolParameters(inputSchema);
|
|
30740
|
+
} else {
|
|
30741
|
+
parameters = buildSAPToolParameters({});
|
|
30906
30742
|
}
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
finishReason: streamState.finishReason,
|
|
30910
|
-
usage: streamState.usage
|
|
30911
|
-
});
|
|
30912
|
-
controller.close();
|
|
30913
|
-
} catch (error) {
|
|
30914
|
-
const aiError = convertToAISDKError(error, {
|
|
30915
|
-
operation: "doStream",
|
|
30916
|
-
url: "sap-ai:orchestration",
|
|
30917
|
-
requestBody: createAISDKRequestBodySummary(options)
|
|
30918
|
-
});
|
|
30919
|
-
controller.enqueue({
|
|
30920
|
-
type: "error",
|
|
30921
|
-
error: aiError instanceof Error ? aiError : new Error(String(aiError))
|
|
30922
|
-
});
|
|
30923
|
-
controller.close();
|
|
30924
|
-
}
|
|
30925
|
-
},
|
|
30926
|
-
cancel(reason) {
|
|
30927
|
-
if (reason) {
|
|
30928
|
-
console.debug("SAP AI stream cancelled:", reason);
|
|
30743
|
+
} else {
|
|
30744
|
+
parameters = buildSAPToolParameters({});
|
|
30929
30745
|
}
|
|
30746
|
+
return {
|
|
30747
|
+
function: {
|
|
30748
|
+
description: tool.description,
|
|
30749
|
+
name: tool.name,
|
|
30750
|
+
parameters
|
|
30751
|
+
},
|
|
30752
|
+
type: "function"
|
|
30753
|
+
};
|
|
30754
|
+
} else {
|
|
30755
|
+
warnings.push({
|
|
30756
|
+
details: "Only 'function' tool type is supported.",
|
|
30757
|
+
feature: `tool type for ${tool.name}`,
|
|
30758
|
+
type: "unsupported"
|
|
30759
|
+
});
|
|
30760
|
+
return null;
|
|
30930
30761
|
}
|
|
30762
|
+
}).filter((t) => t !== null);
|
|
30763
|
+
}
|
|
30764
|
+
const supportsN = !this.modelId.startsWith("amazon--") && !this.modelId.startsWith("anthropic--");
|
|
30765
|
+
const modelParams = {};
|
|
30766
|
+
const maxTokens = options.maxOutputTokens ?? providerOptions.modelParams?.maxTokens ?? this.settings.modelParams?.maxTokens;
|
|
30767
|
+
if (maxTokens !== void 0) modelParams.max_tokens = maxTokens;
|
|
30768
|
+
const temperature = options.temperature ?? providerOptions.modelParams?.temperature ?? this.settings.modelParams?.temperature;
|
|
30769
|
+
if (temperature !== void 0) modelParams.temperature = temperature;
|
|
30770
|
+
const topP = options.topP ?? providerOptions.modelParams?.topP ?? this.settings.modelParams?.topP;
|
|
30771
|
+
if (topP !== void 0) modelParams.top_p = topP;
|
|
30772
|
+
if (options.topK !== void 0) modelParams.top_k = options.topK;
|
|
30773
|
+
const frequencyPenalty = options.frequencyPenalty ?? providerOptions.modelParams?.frequencyPenalty ?? this.settings.modelParams?.frequencyPenalty;
|
|
30774
|
+
if (frequencyPenalty !== void 0) {
|
|
30775
|
+
modelParams.frequency_penalty = frequencyPenalty;
|
|
30776
|
+
}
|
|
30777
|
+
const presencePenalty = options.presencePenalty ?? providerOptions.modelParams?.presencePenalty ?? this.settings.modelParams?.presencePenalty;
|
|
30778
|
+
if (presencePenalty !== void 0) {
|
|
30779
|
+
modelParams.presence_penalty = presencePenalty;
|
|
30780
|
+
}
|
|
30781
|
+
if (supportsN) {
|
|
30782
|
+
const nValue = providerOptions.modelParams?.n ?? this.settings.modelParams?.n;
|
|
30783
|
+
if (nValue !== void 0) {
|
|
30784
|
+
modelParams.n = nValue;
|
|
30785
|
+
}
|
|
30786
|
+
}
|
|
30787
|
+
const parallelToolCalls = providerOptions.modelParams?.parallel_tool_calls ?? this.settings.modelParams?.parallel_tool_calls;
|
|
30788
|
+
if (parallelToolCalls !== void 0) {
|
|
30789
|
+
modelParams.parallel_tool_calls = parallelToolCalls;
|
|
30790
|
+
}
|
|
30791
|
+
if (options.stopSequences && options.stopSequences.length > 0) {
|
|
30792
|
+
modelParams.stop = options.stopSequences;
|
|
30793
|
+
}
|
|
30794
|
+
if (options.seed !== void 0) {
|
|
30795
|
+
modelParams.seed = options.seed;
|
|
30796
|
+
}
|
|
30797
|
+
validateModelParameters(
|
|
30798
|
+
{
|
|
30799
|
+
frequencyPenalty,
|
|
30800
|
+
maxTokens,
|
|
30801
|
+
n: modelParams.n,
|
|
30802
|
+
presencePenalty,
|
|
30803
|
+
temperature,
|
|
30804
|
+
topP
|
|
30805
|
+
},
|
|
30806
|
+
warnings
|
|
30807
|
+
);
|
|
30808
|
+
if (options.toolChoice && options.toolChoice.type !== "auto") {
|
|
30809
|
+
warnings.push({
|
|
30810
|
+
details: `SAP AI SDK does not support toolChoice '${options.toolChoice.type}'. Using default 'auto' behavior.`,
|
|
30811
|
+
feature: "toolChoice",
|
|
30812
|
+
type: "unsupported"
|
|
30931
30813
|
});
|
|
30932
|
-
|
|
30933
|
-
|
|
30934
|
-
|
|
30935
|
-
|
|
30936
|
-
|
|
30937
|
-
};
|
|
30938
|
-
} catch (error) {
|
|
30939
|
-
throw convertToAISDKError(error, {
|
|
30940
|
-
operation: "doStream",
|
|
30941
|
-
url: "sap-ai:orchestration",
|
|
30942
|
-
requestBody: createAISDKRequestBodySummary(options)
|
|
30814
|
+
}
|
|
30815
|
+
if (options.responseFormat?.type === "json") {
|
|
30816
|
+
warnings.push({
|
|
30817
|
+
message: "responseFormat JSON mode is forwarded to the underlying model; support and schema adherence depend on the model/deployment.",
|
|
30818
|
+
type: "other"
|
|
30943
30819
|
});
|
|
30944
30820
|
}
|
|
30821
|
+
const responseFormat = options.responseFormat?.type === "json" ? options.responseFormat.schema ? {
|
|
30822
|
+
json_schema: {
|
|
30823
|
+
description: options.responseFormat.description,
|
|
30824
|
+
name: options.responseFormat.name ?? "response",
|
|
30825
|
+
schema: options.responseFormat.schema,
|
|
30826
|
+
strict: null
|
|
30827
|
+
},
|
|
30828
|
+
type: "json_schema"
|
|
30829
|
+
} : { type: "json_object" } : void 0;
|
|
30830
|
+
const orchestrationConfig = {
|
|
30831
|
+
promptTemplating: {
|
|
30832
|
+
model: {
|
|
30833
|
+
name: this.modelId,
|
|
30834
|
+
params: modelParams,
|
|
30835
|
+
version: providerOptions.modelVersion ?? this.settings.modelVersion ?? "latest"
|
|
30836
|
+
},
|
|
30837
|
+
prompt: {
|
|
30838
|
+
template: [],
|
|
30839
|
+
tools: tools && tools.length > 0 ? tools : void 0,
|
|
30840
|
+
...responseFormat ? { response_format: responseFormat } : {}
|
|
30841
|
+
}
|
|
30842
|
+
},
|
|
30843
|
+
...(() => {
|
|
30844
|
+
const masking = providerOptions.masking ?? this.settings.masking;
|
|
30845
|
+
return masking && Object.keys(masking).length > 0 ? { masking } : {};
|
|
30846
|
+
})(),
|
|
30847
|
+
...(() => {
|
|
30848
|
+
const filtering = providerOptions.filtering ?? this.settings.filtering;
|
|
30849
|
+
return filtering && Object.keys(filtering).length > 0 ? { filtering } : {};
|
|
30850
|
+
})(),
|
|
30851
|
+
...(() => {
|
|
30852
|
+
const grounding = providerOptions.grounding ?? this.settings.grounding;
|
|
30853
|
+
return grounding && Object.keys(grounding).length > 0 ? { grounding } : {};
|
|
30854
|
+
})(),
|
|
30855
|
+
...(() => {
|
|
30856
|
+
const translation = providerOptions.translation ?? this.settings.translation;
|
|
30857
|
+
return translation && Object.keys(translation).length > 0 ? { translation } : {};
|
|
30858
|
+
})()
|
|
30859
|
+
};
|
|
30860
|
+
return { messages, orchestrationConfig, warnings };
|
|
30861
|
+
}
|
|
30862
|
+
/**
|
|
30863
|
+
* Creates an OrchestrationClient instance.
|
|
30864
|
+
*
|
|
30865
|
+
* @param config - Orchestration module configuration
|
|
30866
|
+
* @returns OrchestrationClient instance
|
|
30867
|
+
* @internal
|
|
30868
|
+
*/
|
|
30869
|
+
createClient(config) {
|
|
30870
|
+
return new import_orchestration.OrchestrationClient(config, this.config.deploymentConfig, this.config.destination);
|
|
30945
30871
|
}
|
|
30946
30872
|
};
|
|
30873
|
+
function buildSAPToolParameters(schema) {
|
|
30874
|
+
const schemaType = schema.type;
|
|
30875
|
+
if (schemaType !== void 0 && schemaType !== "object") {
|
|
30876
|
+
return {
|
|
30877
|
+
properties: {},
|
|
30878
|
+
required: [],
|
|
30879
|
+
type: "object"
|
|
30880
|
+
};
|
|
30881
|
+
}
|
|
30882
|
+
const properties = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
|
|
30883
|
+
const required = Array.isArray(schema.required) && schema.required.every((item) => typeof item === "string") ? schema.required : [];
|
|
30884
|
+
const additionalFields = Object.fromEntries(
|
|
30885
|
+
Object.entries(schema).filter(
|
|
30886
|
+
([key]) => key !== "type" && key !== "properties" && key !== "required"
|
|
30887
|
+
)
|
|
30888
|
+
);
|
|
30889
|
+
return {
|
|
30890
|
+
properties,
|
|
30891
|
+
required,
|
|
30892
|
+
type: "object",
|
|
30893
|
+
...additionalFields
|
|
30894
|
+
};
|
|
30895
|
+
}
|
|
30896
|
+
function createAISDKRequestBodySummary(options) {
|
|
30897
|
+
return {
|
|
30898
|
+
hasImageParts: options.prompt.some(
|
|
30899
|
+
(message) => message.role === "user" && message.content.some((part) => part.type === "file" && part.mediaType.startsWith("image/"))
|
|
30900
|
+
),
|
|
30901
|
+
maxOutputTokens: options.maxOutputTokens,
|
|
30902
|
+
promptMessages: options.prompt.length,
|
|
30903
|
+
responseFormatType: options.responseFormat?.type,
|
|
30904
|
+
seed: options.seed,
|
|
30905
|
+
stopSequences: options.stopSequences?.length,
|
|
30906
|
+
temperature: options.temperature,
|
|
30907
|
+
toolChoiceType: options.toolChoice?.type,
|
|
30908
|
+
tools: options.tools?.length ?? 0,
|
|
30909
|
+
topK: options.topK,
|
|
30910
|
+
topP: options.topP
|
|
30911
|
+
};
|
|
30912
|
+
}
|
|
30913
|
+
function hasCallableParse(obj) {
|
|
30914
|
+
return typeof obj.parse === "function";
|
|
30915
|
+
}
|
|
30916
|
+
function isZodSchema(obj) {
|
|
30917
|
+
if (obj === null || typeof obj !== "object") {
|
|
30918
|
+
return false;
|
|
30919
|
+
}
|
|
30920
|
+
const record = obj;
|
|
30921
|
+
return "_def" in record && "parse" in record && hasCallableParse(record);
|
|
30922
|
+
}
|
|
30947
30923
|
function mapFinishReason(reason) {
|
|
30948
30924
|
const raw = reason;
|
|
30949
|
-
if (!reason) return { unified: "other"
|
|
30925
|
+
if (!reason) return { raw, unified: "other" };
|
|
30950
30926
|
switch (reason.toLowerCase()) {
|
|
30951
|
-
case "
|
|
30927
|
+
case "content_filter":
|
|
30928
|
+
return { raw, unified: "content-filter" };
|
|
30952
30929
|
case "end_turn":
|
|
30953
|
-
case "stop_sequence":
|
|
30954
30930
|
case "eos":
|
|
30955
|
-
|
|
30931
|
+
case "stop":
|
|
30932
|
+
case "stop_sequence":
|
|
30933
|
+
return { raw, unified: "stop" };
|
|
30934
|
+
case "error":
|
|
30935
|
+
return { raw, unified: "error" };
|
|
30936
|
+
case "function_call":
|
|
30937
|
+
case "tool_call":
|
|
30938
|
+
case "tool_calls":
|
|
30939
|
+
return { raw, unified: "tool-calls" };
|
|
30956
30940
|
case "length":
|
|
30957
30941
|
case "max_tokens":
|
|
30958
30942
|
case "max_tokens_reached":
|
|
30959
|
-
return { unified: "length"
|
|
30960
|
-
case "tool_calls":
|
|
30961
|
-
case "tool_call":
|
|
30962
|
-
case "function_call":
|
|
30963
|
-
return { unified: "tool-calls", raw };
|
|
30964
|
-
case "content_filter":
|
|
30965
|
-
return { unified: "content-filter", raw };
|
|
30966
|
-
case "error":
|
|
30967
|
-
return { unified: "error", raw };
|
|
30943
|
+
return { raw, unified: "length" };
|
|
30968
30944
|
default:
|
|
30969
|
-
return { unified: "other"
|
|
30945
|
+
return { raw, unified: "other" };
|
|
30946
|
+
}
|
|
30947
|
+
}
|
|
30948
|
+
function validateModelParameters(params, warnings) {
|
|
30949
|
+
if (params.temperature !== void 0 && (params.temperature < 0 || params.temperature > 2)) {
|
|
30950
|
+
warnings.push({
|
|
30951
|
+
message: `temperature=${String(params.temperature)} is outside typical range [0, 2]. The API may reject this value.`,
|
|
30952
|
+
type: "other"
|
|
30953
|
+
});
|
|
30954
|
+
}
|
|
30955
|
+
if (params.topP !== void 0 && (params.topP < 0 || params.topP > 1)) {
|
|
30956
|
+
warnings.push({
|
|
30957
|
+
message: `topP=${String(params.topP)} is outside valid range [0, 1]. The API may reject this value.`,
|
|
30958
|
+
type: "other"
|
|
30959
|
+
});
|
|
30960
|
+
}
|
|
30961
|
+
if (params.frequencyPenalty !== void 0 && (params.frequencyPenalty < -2 || params.frequencyPenalty > 2)) {
|
|
30962
|
+
warnings.push({
|
|
30963
|
+
message: `frequencyPenalty=${String(params.frequencyPenalty)} is outside typical range [-2, 2]. The API may reject this value.`,
|
|
30964
|
+
type: "other"
|
|
30965
|
+
});
|
|
30966
|
+
}
|
|
30967
|
+
if (params.presencePenalty !== void 0 && (params.presencePenalty < -2 || params.presencePenalty > 2)) {
|
|
30968
|
+
warnings.push({
|
|
30969
|
+
message: `presencePenalty=${String(params.presencePenalty)} is outside typical range [-2, 2]. The API may reject this value.`,
|
|
30970
|
+
type: "other"
|
|
30971
|
+
});
|
|
30972
|
+
}
|
|
30973
|
+
if (params.maxTokens !== void 0 && params.maxTokens <= 0) {
|
|
30974
|
+
warnings.push({
|
|
30975
|
+
message: `maxTokens=${String(params.maxTokens)} must be positive. The API will likely reject this value.`,
|
|
30976
|
+
type: "other"
|
|
30977
|
+
});
|
|
30978
|
+
}
|
|
30979
|
+
if (params.n !== void 0 && params.n <= 0) {
|
|
30980
|
+
warnings.push({
|
|
30981
|
+
message: `n=${String(params.n)} must be positive. The API will likely reject this value.`,
|
|
30982
|
+
type: "other"
|
|
30983
|
+
});
|
|
30970
30984
|
}
|
|
30971
30985
|
}
|
|
30972
30986
|
|
|
@@ -30984,26 +30998,24 @@ function createSAPAIProvider(options = {}) {
|
|
|
30984
30998
|
const mergedSettings = {
|
|
30985
30999
|
...options.defaultSettings,
|
|
30986
31000
|
...settings,
|
|
31001
|
+
filtering: settings.filtering ?? options.defaultSettings?.filtering,
|
|
31002
|
+
// Complex objects: override, do not merge
|
|
31003
|
+
masking: settings.masking ?? options.defaultSettings?.masking,
|
|
30987
31004
|
modelParams: {
|
|
30988
31005
|
...options.defaultSettings?.modelParams ?? {},
|
|
30989
31006
|
...settings.modelParams ?? {}
|
|
30990
31007
|
},
|
|
30991
|
-
// Complex objects: override, do not merge
|
|
30992
|
-
masking: settings.masking ?? options.defaultSettings?.masking,
|
|
30993
|
-
filtering: settings.filtering ?? options.defaultSettings?.filtering,
|
|
30994
31008
|
tools: settings.tools ?? options.defaultSettings?.tools
|
|
30995
31009
|
};
|
|
30996
|
-
return new
|
|
30997
|
-
provider: "sap-ai",
|
|
31010
|
+
return new SAPAILanguageModel(modelId, mergedSettings, {
|
|
30998
31011
|
deploymentConfig,
|
|
30999
|
-
destination: options.destination
|
|
31012
|
+
destination: options.destination,
|
|
31013
|
+
provider: "sap-ai"
|
|
31000
31014
|
});
|
|
31001
31015
|
};
|
|
31002
31016
|
const provider = function(modelId, settings) {
|
|
31003
31017
|
if (new.target) {
|
|
31004
|
-
throw new Error(
|
|
31005
|
-
"The SAP AI provider function cannot be called with the new keyword."
|
|
31006
|
-
);
|
|
31018
|
+
throw new Error("The SAP AI provider function cannot be called with the new keyword.");
|
|
31007
31019
|
}
|
|
31008
31020
|
return createModel(modelId, settings);
|
|
31009
31021
|
};
|
|
@@ -31012,17 +31024,12 @@ function createSAPAIProvider(options = {}) {
|
|
|
31012
31024
|
}
|
|
31013
31025
|
var sapai = createSAPAIProvider();
|
|
31014
31026
|
|
|
31015
|
-
// src/sap-ai-
|
|
31027
|
+
// src/sap-ai-settings.ts
|
|
31016
31028
|
var import_orchestration2 = require("@sap-ai-sdk/orchestration");
|
|
31017
|
-
|
|
31018
|
-
// src/types/completion-request.ts
|
|
31019
31029
|
var import_orchestration3 = require("@sap-ai-sdk/orchestration");
|
|
31020
31030
|
|
|
31021
|
-
// src/types/completion-response.ts
|
|
31022
|
-
var import_orchestration4 = require("@sap-ai-sdk/orchestration");
|
|
31023
|
-
|
|
31024
31031
|
// src/index.ts
|
|
31025
|
-
var
|
|
31032
|
+
var import_orchestration4 = require("@sap-ai-sdk/orchestration");
|
|
31026
31033
|
// Annotate the CommonJS export names for ESM import in node:
|
|
31027
31034
|
0 && (module.exports = {
|
|
31028
31035
|
OrchestrationClient,
|