@jerome-benoit/sap-ai-provider-v2 5.0.3 → 5.1.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 +44 -24
- package/dist/chunk-4ILJD6PI.js +333 -0
- package/dist/chunk-4ILJD6PI.js.map +1 -0
- package/dist/chunk-BHA5MIN6.js +224 -0
- package/dist/chunk-BHA5MIN6.js.map +1 -0
- package/dist/{chunk-4JLNWASF.js → chunk-DLGBK3C3.js} +91 -7
- package/dist/chunk-DLGBK3C3.js.map +1 -0
- package/dist/{chunk-E76ZDPIW.js → chunk-EUBI5ENK.js} +54 -27
- package/dist/chunk-EUBI5ENK.js.map +1 -0
- package/dist/{chunk-YP3AADWD.js → chunk-FKHOJ3ZC.js} +24 -3
- package/dist/chunk-FKHOJ3ZC.js.map +1 -0
- package/dist/{chunk-UIBQ5AFS.js → chunk-QFMHNGLB.js} +56 -218
- package/dist/chunk-QFMHNGLB.js.map +1 -0
- package/dist/{chunk-3H5C5U22.js → chunk-QQQYMQPU.js} +19 -10
- package/dist/chunk-QQQYMQPU.js.map +1 -0
- package/dist/{chunk-NF355OFT.js → chunk-ZOBD7PXJ.js} +116 -21
- package/dist/chunk-ZOBD7PXJ.js.map +1 -0
- package/dist/{foundation-models-embedding-model-strategy-SAVQFBF4.js → foundation-models-embedding-model-strategy-3WAKJXBY.js} +5 -4
- package/dist/{foundation-models-embedding-model-strategy-SAVQFBF4.js.map → foundation-models-embedding-model-strategy-3WAKJXBY.js.map} +1 -1
- package/dist/{foundation-models-language-model-strategy-ZDOWVYTA.js → foundation-models-language-model-strategy-PJ26VXEA.js} +21 -8
- package/dist/foundation-models-language-model-strategy-PJ26VXEA.js.map +1 -0
- package/dist/index.cjs +2008 -497
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +798 -185
- package/dist/index.d.ts +798 -185
- package/dist/index.js +148 -24
- package/dist/index.js.map +1 -1
- package/dist/{orchestration-embedding-model-strategy-GT27AFII.js → orchestration-embedding-model-strategy-AZ76XLMD.js} +6 -5
- package/dist/{orchestration-embedding-model-strategy-GT27AFII.js.map → orchestration-embedding-model-strategy-AZ76XLMD.js.map} +1 -1
- package/dist/{orchestration-language-model-strategy-7QTPQHCC.js → orchestration-language-model-strategy-CT6RHCYO.js} +48 -17
- package/dist/orchestration-language-model-strategy-CT6RHCYO.js.map +1 -0
- package/dist/responses-language-model-strategy-UYTV6TPM.js +738 -0
- package/dist/responses-language-model-strategy-UYTV6TPM.js.map +1 -0
- package/dist/sap-ai-error-UPKYWPSS.js +16 -0
- package/dist/sap-ai-error-UPKYWPSS.js.map +1 -0
- package/package.json +79 -39
- package/dist/chunk-3H5C5U22.js.map +0 -1
- package/dist/chunk-4JLNWASF.js.map +0 -1
- package/dist/chunk-E76ZDPIW.js.map +0 -1
- package/dist/chunk-NF355OFT.js.map +0 -1
- package/dist/chunk-UIBQ5AFS.js.map +0 -1
- package/dist/chunk-YP3AADWD.js.map +0 -1
- package/dist/foundation-models-language-model-strategy-ZDOWVYTA.js.map +0 -1
- package/dist/orchestration-language-model-strategy-7QTPQHCC.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -5,8 +5,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __esm = (fn, res) => function __init() {
|
|
9
|
-
|
|
8
|
+
var __esm = (fn, res, err) => function __init() {
|
|
9
|
+
if (err) throw err[0];
|
|
10
|
+
try {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw err = [e], e;
|
|
14
|
+
}
|
|
10
15
|
};
|
|
11
16
|
var __export = (target, all) => {
|
|
12
17
|
for (var name in all)
|
|
@@ -30,6 +35,181 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
35
|
));
|
|
31
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
37
|
|
|
38
|
+
// src/sap-ai-provider-options.ts
|
|
39
|
+
function getProviderName(providerIdentifier) {
|
|
40
|
+
const dotIndex = providerIdentifier.indexOf(".");
|
|
41
|
+
return dotIndex === -1 ? providerIdentifier : providerIdentifier.slice(0, dotIndex);
|
|
42
|
+
}
|
|
43
|
+
function validateEmbeddingModelParamsSettings(modelParams) {
|
|
44
|
+
return embeddingModelParamsSchema.parse(modelParams);
|
|
45
|
+
}
|
|
46
|
+
function validateModelParamsSettings(modelParams) {
|
|
47
|
+
return modelParamsSchema.parse(modelParams);
|
|
48
|
+
}
|
|
49
|
+
function validateModelParamsWithWarnings(params, warnings) {
|
|
50
|
+
const result = modelParamsSchema.safeParse(params);
|
|
51
|
+
if (!result.success) {
|
|
52
|
+
for (const issue of result.error.issues) {
|
|
53
|
+
const path = issue.path.join(".");
|
|
54
|
+
const value = path ? params[path] : void 0;
|
|
55
|
+
warnings.push({
|
|
56
|
+
message: `${path}=${String(value)} is invalid: ${issue.message}. The API may reject this value.`,
|
|
57
|
+
type: "other"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function parseSAPPartProviderOptions(providerOptions, warnings) {
|
|
63
|
+
if (!providerOptions || typeof providerOptions !== "object") {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
const block = providerOptions[SAP_AI_PROVIDER_NAME];
|
|
67
|
+
if (block === void 0) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
const parsed = sapAIPartProviderOptionsSchema.safeParse(block);
|
|
71
|
+
if (parsed.success) {
|
|
72
|
+
return parsed.data;
|
|
73
|
+
}
|
|
74
|
+
if (warnings) {
|
|
75
|
+
for (const issue of parsed.error.issues) {
|
|
76
|
+
const path = issue.path.join(".");
|
|
77
|
+
const message = `providerOptions['sap-ai']${path ? `.${path}` : ""} is invalid: ${issue.message}. The directive was dropped.`;
|
|
78
|
+
if (!warnings.some((w) => w.message === message)) {
|
|
79
|
+
warnings.push({ message, type: "other" });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
var import_provider_utils, import_zod, SAP_AI_PROVIDER_NAME, modelParamsSchema, embeddingModelParamsSchema, sapAIApiTypeSchema, cacheControlSchema, sapAIPartProviderOptionsSchema, orchestrationReasoningBlockSchema, promptTemplateScopeSchema, promptTemplateRefByIdSchema, promptTemplateRefByScenarioNameVersionSchema, promptTemplateRefSchema, orchestrationConfigRefOverrideSchema, orchestrationConfigRefByIdSchema, orchestrationConfigRefByScenarioNameVersionSchema, orchestrationConfigRefSchema, responsesModelOptionsSchema, dropUnsupportedParamsSchema, sapAILanguageModelProviderOptions, sapAIEmbeddingProviderOptions;
|
|
86
|
+
var init_sap_ai_provider_options = __esm({
|
|
87
|
+
"src/sap-ai-provider-options.ts"() {
|
|
88
|
+
"use strict";
|
|
89
|
+
import_provider_utils = require("@ai-sdk/provider-utils");
|
|
90
|
+
import_zod = require("zod");
|
|
91
|
+
SAP_AI_PROVIDER_NAME = "sap-ai";
|
|
92
|
+
modelParamsSchema = import_zod.z.object({
|
|
93
|
+
frequencyPenalty: import_zod.z.number().min(-2).max(2).optional(),
|
|
94
|
+
maxTokens: import_zod.z.number().int().positive().optional(),
|
|
95
|
+
n: import_zod.z.number().int().positive().optional(),
|
|
96
|
+
parallel_tool_calls: import_zod.z.boolean().optional(),
|
|
97
|
+
presencePenalty: import_zod.z.number().min(-2).max(2).optional(),
|
|
98
|
+
temperature: import_zod.z.number().min(0).max(2).optional(),
|
|
99
|
+
topP: import_zod.z.number().min(0).max(1).optional()
|
|
100
|
+
}).catchall(import_zod.z.unknown());
|
|
101
|
+
embeddingModelParamsSchema = import_zod.z.object({
|
|
102
|
+
dimensions: import_zod.z.number().int().positive().optional(),
|
|
103
|
+
encoding_format: import_zod.z.enum(["base64", "binary", "float"]).optional(),
|
|
104
|
+
normalize: import_zod.z.boolean().optional()
|
|
105
|
+
}).catchall(import_zod.z.unknown());
|
|
106
|
+
sapAIApiTypeSchema = import_zod.z.enum(["orchestration", "foundation-models", "responses"]);
|
|
107
|
+
cacheControlSchema = import_zod.z.object({
|
|
108
|
+
ttl: import_zod.z.enum(["5m", "1h"]).optional(),
|
|
109
|
+
type: import_zod.z.literal("ephemeral")
|
|
110
|
+
});
|
|
111
|
+
sapAIPartProviderOptionsSchema = import_zod.z.object({
|
|
112
|
+
cacheControl: cacheControlSchema.optional()
|
|
113
|
+
});
|
|
114
|
+
orchestrationReasoningBlockSchema = import_zod.z.object({
|
|
115
|
+
content: import_zod.z.string().optional(),
|
|
116
|
+
signature: import_zod.z.string().optional()
|
|
117
|
+
}).strict();
|
|
118
|
+
promptTemplateScopeSchema = import_zod.z.enum(["tenant", "resource_group"]);
|
|
119
|
+
promptTemplateRefByIdSchema = import_zod.z.object({
|
|
120
|
+
id: import_zod.z.string().min(1, "Template ID cannot be empty"),
|
|
121
|
+
scope: promptTemplateScopeSchema.optional()
|
|
122
|
+
});
|
|
123
|
+
promptTemplateRefByScenarioNameVersionSchema = import_zod.z.object({
|
|
124
|
+
name: import_zod.z.string().min(1, "Template name cannot be empty"),
|
|
125
|
+
scenario: import_zod.z.string().min(1, "Scenario cannot be empty"),
|
|
126
|
+
scope: promptTemplateScopeSchema.optional(),
|
|
127
|
+
version: import_zod.z.string().min(1, "Version cannot be empty")
|
|
128
|
+
});
|
|
129
|
+
promptTemplateRefSchema = import_zod.z.union([
|
|
130
|
+
promptTemplateRefByIdSchema,
|
|
131
|
+
promptTemplateRefByScenarioNameVersionSchema
|
|
132
|
+
]);
|
|
133
|
+
orchestrationConfigRefOverrideSchema = import_zod.z.custom(
|
|
134
|
+
(value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
135
|
+
{ message: "overrideConfig must be an object" }
|
|
136
|
+
).refine(
|
|
137
|
+
(value) => {
|
|
138
|
+
let stream;
|
|
139
|
+
try {
|
|
140
|
+
stream = value.stream;
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return stream === void 0 || Boolean(stream) && typeof stream === "object" && !Array.isArray(stream);
|
|
145
|
+
},
|
|
146
|
+
{ message: "overrideConfig.stream must be an object" }
|
|
147
|
+
).refine(
|
|
148
|
+
(value) => {
|
|
149
|
+
let stream;
|
|
150
|
+
try {
|
|
151
|
+
stream = value.stream;
|
|
152
|
+
} catch {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
if (stream === void 0 || stream === null || typeof stream !== "object") {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
return !("enabled" in stream);
|
|
160
|
+
} catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
message: "stream.enabled is not allowed in overrideConfig: it is controlled by the call site (stream() or chatCompletion())"
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
orchestrationConfigRefByIdSchema = import_zod.z.object({
|
|
169
|
+
id: import_zod.z.string().min(1, "Config ID cannot be empty"),
|
|
170
|
+
overrideConfig: orchestrationConfigRefOverrideSchema.optional()
|
|
171
|
+
});
|
|
172
|
+
orchestrationConfigRefByScenarioNameVersionSchema = import_zod.z.object({
|
|
173
|
+
name: import_zod.z.string().min(1, "Config name cannot be empty"),
|
|
174
|
+
overrideConfig: orchestrationConfigRefOverrideSchema.optional(),
|
|
175
|
+
scenario: import_zod.z.string().min(1, "Scenario cannot be empty"),
|
|
176
|
+
version: import_zod.z.string().min(1, "Version cannot be empty")
|
|
177
|
+
});
|
|
178
|
+
orchestrationConfigRefSchema = import_zod.z.union([
|
|
179
|
+
orchestrationConfigRefByIdSchema,
|
|
180
|
+
orchestrationConfigRefByScenarioNameVersionSchema
|
|
181
|
+
]);
|
|
182
|
+
responsesModelOptionsSchema = import_zod.z.object({
|
|
183
|
+
metadata: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).nullable().optional()
|
|
184
|
+
}).catchall(import_zod.z.json());
|
|
185
|
+
dropUnsupportedParamsSchema = import_zod.z.boolean();
|
|
186
|
+
sapAILanguageModelProviderOptions = (0, import_provider_utils.lazySchema)(
|
|
187
|
+
() => (0, import_provider_utils.zodSchema)(
|
|
188
|
+
import_zod.z.object({
|
|
189
|
+
api: sapAIApiTypeSchema.optional(),
|
|
190
|
+
dropUnsupportedParams: dropUnsupportedParamsSchema.optional(),
|
|
191
|
+
escapeTemplatePlaceholders: import_zod.z.boolean().optional(),
|
|
192
|
+
includeReasoning: import_zod.z.boolean().optional(),
|
|
193
|
+
modelParams: modelParamsSchema.optional(),
|
|
194
|
+
orchestrationConfigRef: orchestrationConfigRefSchema.optional(),
|
|
195
|
+
placeholderValues: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
196
|
+
promptTemplateRef: promptTemplateRefSchema.optional(),
|
|
197
|
+
responses: responsesModelOptionsSchema.optional()
|
|
198
|
+
})
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
sapAIEmbeddingProviderOptions = (0, import_provider_utils.lazySchema)(
|
|
202
|
+
() => (0, import_provider_utils.zodSchema)(
|
|
203
|
+
import_zod.z.object({
|
|
204
|
+
api: sapAIApiTypeSchema.optional(),
|
|
205
|
+
modelParams: embeddingModelParamsSchema.optional(),
|
|
206
|
+
type: import_zod.z.enum(["document", "query", "text"]).optional()
|
|
207
|
+
})
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
33
213
|
// src/convert-to-sap-messages.ts
|
|
34
214
|
function getURLHref(value) {
|
|
35
215
|
if (typeof value !== "object" || value === null || URL_HREF_DESCRIPTOR?.get === void 0) {
|
|
@@ -171,6 +351,7 @@ function convertToSAPMessages(prompt, options = {}) {
|
|
|
171
351
|
let text = "";
|
|
172
352
|
const textParts = parser ? [] : void 0;
|
|
173
353
|
let anyCacheControl = false;
|
|
354
|
+
let reasoningContent;
|
|
174
355
|
const toolCalls = [];
|
|
175
356
|
for (const part of message.content) {
|
|
176
357
|
switch (part.type) {
|
|
@@ -182,6 +363,21 @@ function convertToSAPMessages(prompt, options = {}) {
|
|
|
182
363
|
break;
|
|
183
364
|
}
|
|
184
365
|
case "reasoning": {
|
|
366
|
+
const nativeNamespace = options.nativeReasoningProviderName;
|
|
367
|
+
const nativeOptions = nativeNamespace === void 0 ? void 0 : part.providerOptions?.[nativeNamespace];
|
|
368
|
+
if (nativeOptions !== null && typeof nativeOptions === "object" && !Array.isArray(nativeOptions) && Object.hasOwn(nativeOptions, "reasoningContent")) {
|
|
369
|
+
const parsed = orchestrationReasoningBlockSchema.safeParse(
|
|
370
|
+
nativeOptions.reasoningContent
|
|
371
|
+
);
|
|
372
|
+
if (!parsed.success) {
|
|
373
|
+
throw new import_provider.InvalidPromptError({
|
|
374
|
+
message: "Invalid native Orchestration reasoning metadata.",
|
|
375
|
+
prompt
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
(reasoningContent ??= []).push(parsed.data);
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
185
381
|
if (includeReasoning && part.text) {
|
|
186
382
|
const reasoning = `<think>${part.text}</think>`;
|
|
187
383
|
text += reasoning;
|
|
@@ -228,11 +424,12 @@ function convertToSAPMessages(prompt, options = {}) {
|
|
|
228
424
|
}
|
|
229
425
|
}
|
|
230
426
|
}
|
|
231
|
-
if (text || toolCalls.length > 0) {
|
|
427
|
+
if (text || toolCalls.length > 0 || reasoningContent?.length) {
|
|
232
428
|
const assistantMessage = {
|
|
233
429
|
content: anyCacheControl && textParts ? textParts.map((p) => wrapAsTextContent(maybeEscape(p.text), p.cacheControl)) : maybeEscape(text),
|
|
234
430
|
role: "assistant",
|
|
235
|
-
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
431
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
432
|
+
...reasoningContent && { reasoning_content: reasoningContent }
|
|
236
433
|
};
|
|
237
434
|
messages.push(assistantMessage);
|
|
238
435
|
}
|
|
@@ -388,6 +585,7 @@ var init_convert_to_sap_messages = __esm({
|
|
|
388
585
|
"src/convert-to-sap-messages.ts"() {
|
|
389
586
|
"use strict";
|
|
390
587
|
import_provider = require("@ai-sdk/provider");
|
|
588
|
+
init_sap_ai_provider_options();
|
|
391
589
|
ZERO_WIDTH_SPACE = "\u200B";
|
|
392
590
|
ARRAY_BUFFER_BYTE_LENGTH_DESCRIPTOR = Object.getOwnPropertyDescriptor(
|
|
393
591
|
ArrayBuffer.prototype,
|
|
@@ -408,260 +606,64 @@ var init_convert_to_sap_messages = __esm({
|
|
|
408
606
|
}
|
|
409
607
|
});
|
|
410
608
|
|
|
411
|
-
// src/sap-ai-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
message: `${path}=${String(value)} is invalid: ${issue.message}. The API may reject this value.`,
|
|
430
|
-
type: "other"
|
|
431
|
-
});
|
|
609
|
+
// src/sap-ai-error.ts
|
|
610
|
+
var sap_ai_error_exports = {};
|
|
611
|
+
__export(sap_ai_error_exports, {
|
|
612
|
+
ApiSwitchError: () => ApiSwitchError,
|
|
613
|
+
UnsupportedFeatureError: () => UnsupportedFeatureError,
|
|
614
|
+
convertSAPErrorToAPICallError: () => convertSAPErrorToAPICallError,
|
|
615
|
+
convertToAISDKError: () => convertToAISDKError,
|
|
616
|
+
normalizeHeaders: () => normalizeHeaders
|
|
617
|
+
});
|
|
618
|
+
function convertSAPErrorToAPICallError(errorResponse, context) {
|
|
619
|
+
const { code, location, message, requestId } = extractErrorFields(errorResponse);
|
|
620
|
+
const statusCode = getStatusCodeFromSAPError(code, context?.httpStatusCode);
|
|
621
|
+
const responseBody = JSON.stringify({
|
|
622
|
+
error: {
|
|
623
|
+
code,
|
|
624
|
+
location,
|
|
625
|
+
message,
|
|
626
|
+
request_id: requestId
|
|
432
627
|
}
|
|
628
|
+
});
|
|
629
|
+
let enhancedMessage = message;
|
|
630
|
+
if (statusCode === HTTP_STATUS.UNAUTHORIZED || statusCode === HTTP_STATUS.FORBIDDEN) {
|
|
631
|
+
enhancedMessage += "\n\nAuthentication failed. Verify your AICORE_SERVICE_KEY environment variable is set correctly.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-service-key";
|
|
632
|
+
if (requestId) {
|
|
633
|
+
enhancedMessage += `
|
|
634
|
+
Request ID: ${requestId}`;
|
|
635
|
+
}
|
|
636
|
+
return new import_provider3.LoadAPIKeyError({
|
|
637
|
+
message: enhancedMessage
|
|
638
|
+
});
|
|
433
639
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
return
|
|
640
|
+
if (statusCode === HTTP_STATUS.NOT_FOUND) {
|
|
641
|
+
enhancedMessage += "\n\nResource not found. The model or deployment may not exist in your SAP AI Core instance.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-deployment-for-orchestration";
|
|
642
|
+
if (requestId) {
|
|
643
|
+
enhancedMessage += `
|
|
644
|
+
Request ID: ${requestId}`;
|
|
645
|
+
}
|
|
646
|
+
const modelId = context?.modelId ?? extractModelIdentifier(message, location);
|
|
647
|
+
return new import_provider3.NoSuchModelError({
|
|
648
|
+
message: enhancedMessage,
|
|
649
|
+
modelId: modelId ?? "unknown",
|
|
650
|
+
modelType: context?.modelType ?? "languageModel"
|
|
651
|
+
});
|
|
442
652
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
653
|
+
if (statusCode === HTTP_STATUS.RATE_LIMIT) {
|
|
654
|
+
enhancedMessage += "\n\nRate limit exceeded. Please try again later or contact your SAP administrator.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/rate-limits";
|
|
655
|
+
} else if (statusCode >= HTTP_STATUS.INTERNAL_ERROR) {
|
|
656
|
+
enhancedMessage += "\n\nSAP AI Core service error. This is typically a temporary issue. Retries depend on the caller's retry configuration.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/troubleshooting";
|
|
657
|
+
} else if (location) {
|
|
658
|
+
enhancedMessage += `
|
|
659
|
+
|
|
660
|
+
Error location: ${location}`;
|
|
446
661
|
}
|
|
447
|
-
if (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const message = `providerOptions['sap-ai']${path ? `.${path}` : ""} is invalid: ${issue.message}. The directive was dropped.`;
|
|
451
|
-
if (!warnings.some((w) => w.message === message)) {
|
|
452
|
-
warnings.push({ message, type: "other" });
|
|
453
|
-
}
|
|
454
|
-
}
|
|
662
|
+
if (requestId) {
|
|
663
|
+
enhancedMessage += `
|
|
664
|
+
Request ID: ${requestId}`;
|
|
455
665
|
}
|
|
456
|
-
return
|
|
457
|
-
}
|
|
458
|
-
var import_provider_utils, import_zod, SAP_AI_PROVIDER_NAME, modelParamsSchema, embeddingModelParamsSchema, sapAIApiTypeSchema, cacheControlSchema, sapAIPartProviderOptionsSchema, promptTemplateScopeSchema, promptTemplateRefByIdSchema, promptTemplateRefByScenarioNameVersionSchema, promptTemplateRefSchema, orchestrationConfigRefOverrideSchema, orchestrationConfigRefByIdSchema, orchestrationConfigRefByScenarioNameVersionSchema, orchestrationConfigRefSchema, sapAILanguageModelProviderOptions, sapAIEmbeddingProviderOptions;
|
|
459
|
-
var init_sap_ai_provider_options = __esm({
|
|
460
|
-
"src/sap-ai-provider-options.ts"() {
|
|
461
|
-
"use strict";
|
|
462
|
-
import_provider_utils = require("@ai-sdk/provider-utils");
|
|
463
|
-
import_zod = require("zod");
|
|
464
|
-
SAP_AI_PROVIDER_NAME = "sap-ai";
|
|
465
|
-
modelParamsSchema = import_zod.z.object({
|
|
466
|
-
frequencyPenalty: import_zod.z.number().min(-2).max(2).optional(),
|
|
467
|
-
maxTokens: import_zod.z.number().int().positive().optional(),
|
|
468
|
-
n: import_zod.z.number().int().positive().optional(),
|
|
469
|
-
parallel_tool_calls: import_zod.z.boolean().optional(),
|
|
470
|
-
presencePenalty: import_zod.z.number().min(-2).max(2).optional(),
|
|
471
|
-
temperature: import_zod.z.number().min(0).max(2).optional(),
|
|
472
|
-
topP: import_zod.z.number().min(0).max(1).optional()
|
|
473
|
-
}).catchall(import_zod.z.unknown());
|
|
474
|
-
embeddingModelParamsSchema = import_zod.z.object({
|
|
475
|
-
dimensions: import_zod.z.number().int().positive().optional(),
|
|
476
|
-
encoding_format: import_zod.z.enum(["base64", "binary", "float"]).optional(),
|
|
477
|
-
normalize: import_zod.z.boolean().optional()
|
|
478
|
-
}).catchall(import_zod.z.unknown());
|
|
479
|
-
sapAIApiTypeSchema = import_zod.z.enum(["orchestration", "foundation-models"]);
|
|
480
|
-
cacheControlSchema = import_zod.z.object({
|
|
481
|
-
ttl: import_zod.z.enum(["5m", "1h"]).optional(),
|
|
482
|
-
type: import_zod.z.literal("ephemeral")
|
|
483
|
-
});
|
|
484
|
-
sapAIPartProviderOptionsSchema = import_zod.z.object({
|
|
485
|
-
cacheControl: cacheControlSchema.optional()
|
|
486
|
-
});
|
|
487
|
-
promptTemplateScopeSchema = import_zod.z.enum(["tenant", "resource_group"]);
|
|
488
|
-
promptTemplateRefByIdSchema = import_zod.z.object({
|
|
489
|
-
id: import_zod.z.string().min(1, "Template ID cannot be empty"),
|
|
490
|
-
scope: promptTemplateScopeSchema.optional()
|
|
491
|
-
});
|
|
492
|
-
promptTemplateRefByScenarioNameVersionSchema = import_zod.z.object({
|
|
493
|
-
name: import_zod.z.string().min(1, "Template name cannot be empty"),
|
|
494
|
-
scenario: import_zod.z.string().min(1, "Scenario cannot be empty"),
|
|
495
|
-
scope: promptTemplateScopeSchema.optional(),
|
|
496
|
-
version: import_zod.z.string().min(1, "Version cannot be empty")
|
|
497
|
-
});
|
|
498
|
-
promptTemplateRefSchema = import_zod.z.union([
|
|
499
|
-
promptTemplateRefByIdSchema,
|
|
500
|
-
promptTemplateRefByScenarioNameVersionSchema
|
|
501
|
-
]);
|
|
502
|
-
orchestrationConfigRefOverrideSchema = import_zod.z.custom(
|
|
503
|
-
(value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
504
|
-
{ message: "overrideConfig must be an object" }
|
|
505
|
-
).refine(
|
|
506
|
-
(value) => {
|
|
507
|
-
let stream;
|
|
508
|
-
try {
|
|
509
|
-
stream = value.stream;
|
|
510
|
-
} catch {
|
|
511
|
-
return false;
|
|
512
|
-
}
|
|
513
|
-
return stream === void 0 || Boolean(stream) && typeof stream === "object" && !Array.isArray(stream);
|
|
514
|
-
},
|
|
515
|
-
{ message: "overrideConfig.stream must be an object" }
|
|
516
|
-
).refine(
|
|
517
|
-
(value) => {
|
|
518
|
-
let stream;
|
|
519
|
-
try {
|
|
520
|
-
stream = value.stream;
|
|
521
|
-
} catch {
|
|
522
|
-
return true;
|
|
523
|
-
}
|
|
524
|
-
if (stream === void 0 || stream === null || typeof stream !== "object") {
|
|
525
|
-
return true;
|
|
526
|
-
}
|
|
527
|
-
try {
|
|
528
|
-
return !("enabled" in stream);
|
|
529
|
-
} catch {
|
|
530
|
-
return false;
|
|
531
|
-
}
|
|
532
|
-
},
|
|
533
|
-
{
|
|
534
|
-
message: "stream.enabled is not allowed in overrideConfig: it is controlled by the call site (stream() or chatCompletion())"
|
|
535
|
-
}
|
|
536
|
-
);
|
|
537
|
-
orchestrationConfigRefByIdSchema = import_zod.z.object({
|
|
538
|
-
id: import_zod.z.string().min(1, "Config ID cannot be empty"),
|
|
539
|
-
overrideConfig: orchestrationConfigRefOverrideSchema.optional()
|
|
540
|
-
});
|
|
541
|
-
orchestrationConfigRefByScenarioNameVersionSchema = import_zod.z.object({
|
|
542
|
-
name: import_zod.z.string().min(1, "Config name cannot be empty"),
|
|
543
|
-
overrideConfig: orchestrationConfigRefOverrideSchema.optional(),
|
|
544
|
-
scenario: import_zod.z.string().min(1, "Scenario cannot be empty"),
|
|
545
|
-
version: import_zod.z.string().min(1, "Version cannot be empty")
|
|
546
|
-
});
|
|
547
|
-
orchestrationConfigRefSchema = import_zod.z.union([
|
|
548
|
-
orchestrationConfigRefByIdSchema,
|
|
549
|
-
orchestrationConfigRefByScenarioNameVersionSchema
|
|
550
|
-
]);
|
|
551
|
-
sapAILanguageModelProviderOptions = (0, import_provider_utils.lazySchema)(
|
|
552
|
-
() => (0, import_provider_utils.zodSchema)(
|
|
553
|
-
import_zod.z.object({
|
|
554
|
-
api: sapAIApiTypeSchema.optional(),
|
|
555
|
-
escapeTemplatePlaceholders: import_zod.z.boolean().optional(),
|
|
556
|
-
includeReasoning: import_zod.z.boolean().optional(),
|
|
557
|
-
modelParams: modelParamsSchema.optional(),
|
|
558
|
-
orchestrationConfigRef: orchestrationConfigRefSchema.optional(),
|
|
559
|
-
placeholderValues: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
560
|
-
promptTemplateRef: promptTemplateRefSchema.optional()
|
|
561
|
-
})
|
|
562
|
-
)
|
|
563
|
-
);
|
|
564
|
-
sapAIEmbeddingProviderOptions = (0, import_provider_utils.lazySchema)(
|
|
565
|
-
() => (0, import_provider_utils.zodSchema)(
|
|
566
|
-
import_zod.z.object({
|
|
567
|
-
api: sapAIApiTypeSchema.optional(),
|
|
568
|
-
modelParams: embeddingModelParamsSchema.optional(),
|
|
569
|
-
type: import_zod.z.enum(["document", "query", "text"]).optional()
|
|
570
|
-
})
|
|
571
|
-
)
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
// src/deep-merge.ts
|
|
577
|
-
function deepMerge(...sources) {
|
|
578
|
-
const result = {};
|
|
579
|
-
for (const source of sources) {
|
|
580
|
-
if (source != null) mergeInto(result, source, /* @__PURE__ */ new Set(), 0);
|
|
581
|
-
}
|
|
582
|
-
return result;
|
|
583
|
-
}
|
|
584
|
-
function isPlainObject(value) {
|
|
585
|
-
if (value === null || typeof value !== "object") return false;
|
|
586
|
-
const proto = Object.getPrototypeOf(value);
|
|
587
|
-
return proto === Object.prototype || proto === null;
|
|
588
|
-
}
|
|
589
|
-
function mergeInto(target, source, ancestors, depth) {
|
|
590
|
-
if (depth > MAX_DEPTH) throw new Error("Maximum merge depth exceeded");
|
|
591
|
-
if (ancestors.has(source)) throw new Error("Circular reference detected during deep merge");
|
|
592
|
-
ancestors.add(source);
|
|
593
|
-
for (const key of Object.keys(source)) {
|
|
594
|
-
const sourceValue = source[key];
|
|
595
|
-
const targetValue = Object.hasOwn(target, key) ? target[key] : void 0;
|
|
596
|
-
const value = isPlainObject(sourceValue) ? mergeInto(isPlainObject(targetValue) ? targetValue : {}, sourceValue, ancestors, depth + 1) : sourceValue;
|
|
597
|
-
Object.defineProperty(target, key, {
|
|
598
|
-
configurable: true,
|
|
599
|
-
enumerable: true,
|
|
600
|
-
value,
|
|
601
|
-
writable: true
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
ancestors.delete(source);
|
|
605
|
-
return target;
|
|
606
|
-
}
|
|
607
|
-
var MAX_DEPTH;
|
|
608
|
-
var init_deep_merge = __esm({
|
|
609
|
-
"src/deep-merge.ts"() {
|
|
610
|
-
"use strict";
|
|
611
|
-
MAX_DEPTH = 100;
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
// src/sap-ai-error.ts
|
|
616
|
-
function convertSAPErrorToAPICallError(errorResponse, context) {
|
|
617
|
-
const { code, location, message, requestId } = extractErrorFields(errorResponse);
|
|
618
|
-
const statusCode = getStatusCodeFromSAPError(code, context?.httpStatusCode);
|
|
619
|
-
const responseBody = JSON.stringify({
|
|
620
|
-
error: {
|
|
621
|
-
code,
|
|
622
|
-
location,
|
|
623
|
-
message,
|
|
624
|
-
request_id: requestId
|
|
625
|
-
}
|
|
626
|
-
});
|
|
627
|
-
let enhancedMessage = message;
|
|
628
|
-
if (statusCode === HTTP_STATUS.UNAUTHORIZED || statusCode === HTTP_STATUS.FORBIDDEN) {
|
|
629
|
-
enhancedMessage += "\n\nAuthentication failed. Verify your AICORE_SERVICE_KEY environment variable is set correctly.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-service-key";
|
|
630
|
-
if (requestId) {
|
|
631
|
-
enhancedMessage += `
|
|
632
|
-
Request ID: ${requestId}`;
|
|
633
|
-
}
|
|
634
|
-
return new import_provider2.LoadAPIKeyError({
|
|
635
|
-
message: enhancedMessage
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
if (statusCode === HTTP_STATUS.NOT_FOUND) {
|
|
639
|
-
enhancedMessage += "\n\nResource not found. The model or deployment may not exist in your SAP AI Core instance.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-deployment-for-orchestration";
|
|
640
|
-
if (requestId) {
|
|
641
|
-
enhancedMessage += `
|
|
642
|
-
Request ID: ${requestId}`;
|
|
643
|
-
}
|
|
644
|
-
const modelId = context?.modelId ?? extractModelIdentifier(message, location);
|
|
645
|
-
return new import_provider2.NoSuchModelError({
|
|
646
|
-
message: enhancedMessage,
|
|
647
|
-
modelId: modelId ?? "unknown",
|
|
648
|
-
modelType: context?.modelType ?? "languageModel"
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
if (statusCode === HTTP_STATUS.RATE_LIMIT) {
|
|
652
|
-
enhancedMessage += "\n\nRate limit exceeded. Please try again later or contact your SAP administrator.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/rate-limits";
|
|
653
|
-
} else if (statusCode >= HTTP_STATUS.INTERNAL_ERROR) {
|
|
654
|
-
enhancedMessage += "\n\nSAP AI Core service error. This is typically a temporary issue. Retries depend on the caller's retry configuration.\nSee: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/troubleshooting";
|
|
655
|
-
} else if (location) {
|
|
656
|
-
enhancedMessage += `
|
|
657
|
-
|
|
658
|
-
Error location: ${location}`;
|
|
659
|
-
}
|
|
660
|
-
if (requestId) {
|
|
661
|
-
enhancedMessage += `
|
|
662
|
-
Request ID: ${requestId}`;
|
|
663
|
-
}
|
|
664
|
-
return new import_provider2.APICallError({
|
|
666
|
+
return new import_provider3.APICallError({
|
|
665
667
|
isRetryable: isRetryable(statusCode),
|
|
666
668
|
message: enhancedMessage,
|
|
667
669
|
requestBodyValues: context?.requestBody,
|
|
@@ -672,14 +674,21 @@ Request ID: ${requestId}`;
|
|
|
672
674
|
});
|
|
673
675
|
}
|
|
674
676
|
function convertToAISDKError(error, context) {
|
|
675
|
-
if (
|
|
677
|
+
if (import_provider3.APICallError.isInstance(error) || import_provider3.LoadAPIKeyError.isInstance(error) || import_provider3.NoSuchModelError.isInstance(error) || import_provider3.InvalidPromptError.isInstance(error) || import_provider3.UnsupportedFunctionalityError.isInstance(error)) {
|
|
676
678
|
return error;
|
|
677
679
|
}
|
|
678
|
-
const { aborted, response, rootError } = inspectError(error);
|
|
680
|
+
const { aborted, networkCode, noMatchingDeployment, response, rootError, syntaxError } = inspectError(error);
|
|
681
|
+
if (noMatchingDeployment && !aborted) {
|
|
682
|
+
return new import_provider3.NoSuchModelError({
|
|
683
|
+
message: "SAP AI Core has no running deployment matching the requested model. Check the model ID, model version, resource group, and deployment status in your SAP AI Core instance.",
|
|
684
|
+
modelId: context?.modelId ?? "unknown",
|
|
685
|
+
modelType: context?.modelType ?? "languageModel"
|
|
686
|
+
});
|
|
687
|
+
}
|
|
679
688
|
const responseHeaders = context?.responseHeaders ?? normalizeHeaders(response?.headers);
|
|
680
689
|
if (!aborted) {
|
|
681
690
|
const errorResponse = findStructuredErrorResponse(
|
|
682
|
-
|
|
691
|
+
syntaxError ? void 0 : rootError,
|
|
683
692
|
response?.data
|
|
684
693
|
);
|
|
685
694
|
if (errorResponse) {
|
|
@@ -697,7 +706,8 @@ function convertToAISDKError(error, context) {
|
|
|
697
706
|
};
|
|
698
707
|
if (aborted) {
|
|
699
708
|
return createAPICallError(
|
|
700
|
-
|
|
709
|
+
// Preserve cancellation priority without retaining credential-bearing criteria.
|
|
710
|
+
noMatchingDeployment ? void 0 : error,
|
|
701
711
|
{
|
|
702
712
|
isRetryable: false,
|
|
703
713
|
message: "Request was aborted by the client",
|
|
@@ -706,33 +716,44 @@ function convertToAISDKError(error, context) {
|
|
|
706
716
|
resolvedContext
|
|
707
717
|
);
|
|
708
718
|
}
|
|
709
|
-
if (isHttpStatus(response?.status)) {
|
|
719
|
+
if (isHttpStatus(response?.status) && (networkCode === void 0 || syntaxError !== void 0 || response.status < 200 || response.status >= 300)) {
|
|
710
720
|
return createAPICallError(
|
|
711
721
|
error,
|
|
712
722
|
{
|
|
713
723
|
isRetryable: isRetryable(response.status),
|
|
714
|
-
message:
|
|
724
|
+
message: syntaxError && error instanceof Error ? error.message : rootError instanceof Error ? rootError.message : "SAP AI Core request failed",
|
|
715
725
|
statusCode: response.status
|
|
716
726
|
},
|
|
717
727
|
resolvedContext
|
|
718
728
|
);
|
|
719
729
|
}
|
|
720
|
-
if (
|
|
730
|
+
if (syntaxError) {
|
|
721
731
|
return createAPICallError(
|
|
722
732
|
error,
|
|
723
733
|
{
|
|
724
734
|
isRetryable: false,
|
|
725
|
-
message: error instanceof Error && error !==
|
|
735
|
+
message: error instanceof Error && error !== syntaxError ? error.message : "Failed to parse SAP AI Core data.",
|
|
726
736
|
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
727
737
|
},
|
|
728
738
|
resolvedContext
|
|
729
739
|
);
|
|
730
740
|
}
|
|
741
|
+
if (networkCode) {
|
|
742
|
+
return createAPICallError(
|
|
743
|
+
error,
|
|
744
|
+
{
|
|
745
|
+
isRetryable: true,
|
|
746
|
+
message: `SAP AI Core network error (${networkCode})`,
|
|
747
|
+
statusCode: HTTP_STATUS.SERVICE_UNAVAILABLE
|
|
748
|
+
},
|
|
749
|
+
resolvedContext
|
|
750
|
+
);
|
|
751
|
+
}
|
|
731
752
|
if (rootError instanceof Error) {
|
|
732
753
|
const errorMsg = rootError.message.toLowerCase();
|
|
733
754
|
const originalErrorMsg = rootError.message;
|
|
734
755
|
if (AUTHENTICATION_ERROR_KEYWORDS.some((keyword) => errorMsg.includes(keyword))) {
|
|
735
|
-
return new
|
|
756
|
+
return new import_provider3.LoadAPIKeyError({
|
|
736
757
|
message: `SAP AI Core authentication failed: ${originalErrorMsg}
|
|
737
758
|
|
|
738
759
|
Make sure your AICORE_SERVICE_KEY environment variable is set correctly.
|
|
@@ -741,7 +762,7 @@ See: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-serv
|
|
|
741
762
|
}
|
|
742
763
|
if (DEPLOYMENT_ERROR_KEYWORDS.some((keyword) => errorMsg.includes(keyword))) {
|
|
743
764
|
const modelId = context?.modelId ?? extractModelIdentifier(originalErrorMsg);
|
|
744
|
-
return new
|
|
765
|
+
return new import_provider3.NoSuchModelError({
|
|
745
766
|
message: `SAP AI Core deployment error: ${originalErrorMsg}
|
|
746
767
|
|
|
747
768
|
Make sure you have a running orchestration deployment in your SAP AI Core instance.
|
|
@@ -813,7 +834,7 @@ function normalizeHeaders(headers) {
|
|
|
813
834
|
return Object.fromEntries(entries);
|
|
814
835
|
}
|
|
815
836
|
function createAPICallError(error, options, context) {
|
|
816
|
-
return new
|
|
837
|
+
return new import_provider3.APICallError({
|
|
817
838
|
cause: error,
|
|
818
839
|
isRetryable: options.isRetryable,
|
|
819
840
|
message: options.message,
|
|
@@ -887,10 +908,18 @@ function inspectError(error) {
|
|
|
887
908
|
let current = error;
|
|
888
909
|
let response;
|
|
889
910
|
let aborted = false;
|
|
911
|
+
let networkCode;
|
|
912
|
+
let noMatchingDeployment = false;
|
|
913
|
+
let syntaxError;
|
|
890
914
|
while (typeof current === "object" && current !== null && !seen.has(current)) {
|
|
891
915
|
seen.add(current);
|
|
892
916
|
rootError = current;
|
|
917
|
+
noMatchingDeployment ||= current instanceof Error && current.message.startsWith("No deployment matched the given criteria:");
|
|
893
918
|
aborted ||= isAbortError(current);
|
|
919
|
+
if (current instanceof SyntaxError) syntaxError ??= current;
|
|
920
|
+
if (current instanceof Error && "code" in current && typeof current.code === "string") {
|
|
921
|
+
if (RETRYABLE_NETWORK_CODES.has(current.code)) networkCode ??= current.code;
|
|
922
|
+
}
|
|
894
923
|
const entry = current;
|
|
895
924
|
if (response === void 0 && entry.isAxiosError === true) response = entry.response;
|
|
896
925
|
const cause = "cause" in entry ? entry.cause : current instanceof Error && (0, import_util.isErrorWithCause)(current) ? current.rootCause : void 0;
|
|
@@ -900,7 +929,7 @@ function inspectError(error) {
|
|
|
900
929
|
rootError = cause;
|
|
901
930
|
current = cause;
|
|
902
931
|
}
|
|
903
|
-
return { aborted, response, rootError };
|
|
932
|
+
return { aborted, networkCode, noMatchingDeployment, response, rootError, syntaxError };
|
|
904
933
|
}
|
|
905
934
|
function isAbortError(error) {
|
|
906
935
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
@@ -1009,11 +1038,11 @@ function tryExtractSAPErrorFromMessage(message) {
|
|
|
1009
1038
|
return null;
|
|
1010
1039
|
}
|
|
1011
1040
|
}
|
|
1012
|
-
var
|
|
1041
|
+
var import_provider3, import_util, HTTP_STATUS, RETRYABLE_NETWORK_CODES, ERROR_MATCHERS, AUTHENTICATION_ERROR_KEYWORDS, DEPLOYMENT_ERROR_KEYWORDS, ApiSwitchError, UnsupportedFeatureError;
|
|
1013
1042
|
var init_sap_ai_error = __esm({
|
|
1014
1043
|
"src/sap-ai-error.ts"() {
|
|
1015
1044
|
"use strict";
|
|
1016
|
-
|
|
1045
|
+
import_provider3 = require("@ai-sdk/provider");
|
|
1017
1046
|
import_util = require("@sap-cloud-sdk/util");
|
|
1018
1047
|
HTTP_STATUS = {
|
|
1019
1048
|
BAD_REQUEST: 400,
|
|
@@ -1027,6 +1056,17 @@ var init_sap_ai_error = __esm({
|
|
|
1027
1056
|
SERVICE_UNAVAILABLE: 503,
|
|
1028
1057
|
UNAUTHORIZED: 401
|
|
1029
1058
|
};
|
|
1059
|
+
RETRYABLE_NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
1060
|
+
"EAI_AGAIN",
|
|
1061
|
+
"ECONNABORTED",
|
|
1062
|
+
"ECONNREFUSED",
|
|
1063
|
+
"ECONNRESET",
|
|
1064
|
+
"EHOSTUNREACH",
|
|
1065
|
+
"ENETUNREACH",
|
|
1066
|
+
"ENOTFOUND",
|
|
1067
|
+
"EPIPE",
|
|
1068
|
+
"ETIMEDOUT"
|
|
1069
|
+
]);
|
|
1030
1070
|
ERROR_MATCHERS = [
|
|
1031
1071
|
{
|
|
1032
1072
|
category: "network",
|
|
@@ -1160,8 +1200,13 @@ The model's response was blocked by content safety filters. Try a different prom
|
|
|
1160
1200
|
* @param suggestedApi - The API that supports this feature.
|
|
1161
1201
|
*/
|
|
1162
1202
|
constructor(feature, api, suggestedApi) {
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1203
|
+
const names = {
|
|
1204
|
+
"foundation-models": "Foundation Models",
|
|
1205
|
+
orchestration: "Orchestration",
|
|
1206
|
+
responses: "Responses"
|
|
1207
|
+
};
|
|
1208
|
+
const apiName = names[api];
|
|
1209
|
+
const suggestedApiName = names[suggestedApi];
|
|
1165
1210
|
super(`${feature} is not supported by ${apiName} API. Use ${suggestedApiName} API instead.`);
|
|
1166
1211
|
this.feature = feature;
|
|
1167
1212
|
this.api = api;
|
|
@@ -1175,43 +1220,135 @@ The model's response was blocked by content safety filters. Try a different prom
|
|
|
1175
1220
|
}
|
|
1176
1221
|
});
|
|
1177
1222
|
|
|
1178
|
-
// src/
|
|
1179
|
-
function
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
modelParams[mapping.outputKey] = value;
|
|
1184
|
-
}
|
|
1185
|
-
if (mapping.camelCaseKey && mapping.camelCaseKey !== mapping.outputKey) {
|
|
1186
|
-
delete modelParams[mapping.camelCaseKey];
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1223
|
+
// src/abort-utils.ts
|
|
1224
|
+
function createAbortError(reason) {
|
|
1225
|
+
const error = new Error("The operation was aborted.", { cause: reason });
|
|
1226
|
+
error.name = "AbortError";
|
|
1227
|
+
return error;
|
|
1189
1228
|
}
|
|
1190
|
-
function
|
|
1191
|
-
|
|
1192
|
-
if (!details || (details.ephemeral_5m_input_tokens ?? 0) === 0 && (details.ephemeral_1h_input_tokens ?? 0) === 0) {
|
|
1193
|
-
return {};
|
|
1194
|
-
}
|
|
1195
|
-
return { cacheUsage: details };
|
|
1229
|
+
function throwIfAborted(signal) {
|
|
1230
|
+
if (signal?.aborted) throw createAbortError(signal.reason);
|
|
1196
1231
|
}
|
|
1197
|
-
function
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1232
|
+
function waitWithAbort(pending, signal, onAbortedValue) {
|
|
1233
|
+
if (!signal) return pending;
|
|
1234
|
+
return new Promise((resolve, reject) => {
|
|
1235
|
+
let listening = true;
|
|
1236
|
+
const cleanup = () => {
|
|
1237
|
+
if (!listening) return;
|
|
1238
|
+
listening = false;
|
|
1239
|
+
signal.removeEventListener("abort", onAbort);
|
|
1240
|
+
};
|
|
1241
|
+
const onAbort = () => {
|
|
1242
|
+
cleanup();
|
|
1243
|
+
reject(createAbortError(signal.reason));
|
|
1244
|
+
};
|
|
1245
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1246
|
+
void pending.then(
|
|
1247
|
+
(value) => {
|
|
1248
|
+
cleanup();
|
|
1249
|
+
if (signal.aborted) {
|
|
1250
|
+
try {
|
|
1251
|
+
onAbortedValue?.(value);
|
|
1252
|
+
} finally {
|
|
1253
|
+
reject(createAbortError(signal.reason));
|
|
1254
|
+
}
|
|
1255
|
+
} else {
|
|
1256
|
+
resolve(value);
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
(error) => {
|
|
1260
|
+
cleanup();
|
|
1261
|
+
reject(error);
|
|
1262
|
+
}
|
|
1263
|
+
).catch((error) => {
|
|
1264
|
+
cleanup();
|
|
1265
|
+
reject(error);
|
|
1266
|
+
});
|
|
1267
|
+
if (signal.aborted) onAbort();
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
var init_abort_utils = __esm({
|
|
1271
|
+
"src/abort-utils.ts"() {
|
|
1272
|
+
"use strict";
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
// src/deep-merge.ts
|
|
1277
|
+
function deepMerge(...sources) {
|
|
1278
|
+
const result = {};
|
|
1279
|
+
for (const source of sources) {
|
|
1280
|
+
if (source != null) mergeInto(result, source, /* @__PURE__ */ new Set(), 0);
|
|
1281
|
+
}
|
|
1282
|
+
return result;
|
|
1283
|
+
}
|
|
1284
|
+
function isPlainObject(value) {
|
|
1285
|
+
if (value === null || typeof value !== "object") return false;
|
|
1286
|
+
const proto = Object.getPrototypeOf(value);
|
|
1287
|
+
return proto === Object.prototype || proto === null;
|
|
1288
|
+
}
|
|
1289
|
+
function mergeInto(target, source, ancestors, depth) {
|
|
1290
|
+
if (depth > MAX_DEPTH) throw new Error("Maximum merge depth exceeded");
|
|
1291
|
+
if (ancestors.has(source)) throw new Error("Circular reference detected during deep merge");
|
|
1292
|
+
ancestors.add(source);
|
|
1293
|
+
for (const key of Object.keys(source)) {
|
|
1294
|
+
const sourceValue = source[key];
|
|
1295
|
+
const targetValue = Object.hasOwn(target, key) ? target[key] : void 0;
|
|
1296
|
+
const value = isPlainObject(sourceValue) ? mergeInto(isPlainObject(targetValue) ? targetValue : {}, sourceValue, ancestors, depth + 1) : sourceValue;
|
|
1297
|
+
Object.defineProperty(target, key, {
|
|
1298
|
+
configurable: true,
|
|
1299
|
+
enumerable: true,
|
|
1300
|
+
value,
|
|
1301
|
+
writable: true
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
ancestors.delete(source);
|
|
1305
|
+
return target;
|
|
1306
|
+
}
|
|
1307
|
+
var MAX_DEPTH;
|
|
1308
|
+
var init_deep_merge = __esm({
|
|
1309
|
+
"src/deep-merge.ts"() {
|
|
1310
|
+
"use strict";
|
|
1311
|
+
MAX_DEPTH = 100;
|
|
1312
|
+
}
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
// src/strategy-utils.ts
|
|
1316
|
+
function applyParameterOverrides(modelParams, options, sapModelParams, settingsModelParams, mappings) {
|
|
1317
|
+
for (const mapping of mappings) {
|
|
1318
|
+
const value = (mapping.optionKey ? options[mapping.optionKey] : void 0) ?? (mapping.camelCaseKey ? sapModelParams?.[mapping.camelCaseKey] : void 0) ?? (mapping.camelCaseKey ? settingsModelParams?.[mapping.camelCaseKey] : void 0);
|
|
1319
|
+
if (value !== void 0) {
|
|
1320
|
+
modelParams[mapping.outputKey] = value;
|
|
1321
|
+
}
|
|
1322
|
+
if (mapping.camelCaseKey && mapping.camelCaseKey !== mapping.outputKey) {
|
|
1323
|
+
delete modelParams[mapping.camelCaseKey];
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
function buildAnthropicCacheMetadata(tokenUsage) {
|
|
1328
|
+
const details = tokenUsage?.prompt_tokens_details?.cache_creation_token_details;
|
|
1329
|
+
if (!details || (details.ephemeral_5m_input_tokens ?? 0) === 0 && (details.ephemeral_1h_input_tokens ?? 0) === 0) {
|
|
1330
|
+
return {};
|
|
1331
|
+
}
|
|
1332
|
+
return { cacheUsage: details };
|
|
1333
|
+
}
|
|
1334
|
+
function buildEmbeddingResult(config) {
|
|
1335
|
+
const {
|
|
1336
|
+
embeddings,
|
|
1337
|
+
modelId,
|
|
1338
|
+
providerName,
|
|
1339
|
+
requestId,
|
|
1340
|
+
responseHeaders,
|
|
1341
|
+
totalTokens,
|
|
1342
|
+
version,
|
|
1343
|
+
warnings
|
|
1344
|
+
} = config;
|
|
1345
|
+
const providerMetadata = {
|
|
1346
|
+
[providerName]: {
|
|
1347
|
+
model: modelId,
|
|
1348
|
+
...requestId ? { requestId } : {},
|
|
1349
|
+
version
|
|
1350
|
+
}
|
|
1351
|
+
};
|
|
1215
1352
|
return {
|
|
1216
1353
|
embeddings,
|
|
1217
1354
|
providerMetadata,
|
|
@@ -1225,9 +1362,23 @@ function buildGenerateResult(config) {
|
|
|
1225
1362
|
const content = [];
|
|
1226
1363
|
const tokenUsage = response.getTokenUsage();
|
|
1227
1364
|
const finishReasonRaw = response.getFinishReason();
|
|
1228
|
-
const
|
|
1365
|
+
const providerSpecificFields = parseProviderSpecificFields(
|
|
1366
|
+
response.getProviderSpecificFields?.()
|
|
1367
|
+
);
|
|
1368
|
+
const finishReason = mapFinishReason(
|
|
1369
|
+
finishReasonRaw,
|
|
1370
|
+
getProviderFinishReason(providerSpecificFields)
|
|
1371
|
+
);
|
|
1229
1372
|
const textContent = response.getContent();
|
|
1230
1373
|
const toolCalls = response.getToolCalls();
|
|
1374
|
+
for (const block of response.getReasoningBlocks?.() ?? []) {
|
|
1375
|
+
const validatedBlock = orchestrationReasoningBlockSchema.parse(block);
|
|
1376
|
+
content.push({
|
|
1377
|
+
providerMetadata: buildOrchestrationReasoningMetadata(validatedBlock, providerName),
|
|
1378
|
+
text: validatedBlock.content ?? "",
|
|
1379
|
+
type: "reasoning"
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1231
1382
|
if (textContent) content.push({ text: textContent, type: "text" });
|
|
1232
1383
|
for (const toolCall of toolCalls ?? []) {
|
|
1233
1384
|
content.push({
|
|
@@ -1262,9 +1413,10 @@ function buildGenerateResult(config) {
|
|
|
1262
1413
|
providerMetadata: {
|
|
1263
1414
|
[providerName]: {
|
|
1264
1415
|
...buildAnthropicCacheMetadata(tokenUsage),
|
|
1265
|
-
finishReason:
|
|
1416
|
+
finishReason: finishReason.raw ?? "unknown",
|
|
1266
1417
|
finishReasonMapped: finishReason,
|
|
1267
1418
|
...intermediateFailures?.length ? { intermediateFailures: sanitizeAsJSONArray(intermediateFailures) } : {},
|
|
1419
|
+
...providerSpecificFields && { providerSpecificFields },
|
|
1268
1420
|
...requestId ? { requestId } : {},
|
|
1269
1421
|
version
|
|
1270
1422
|
}
|
|
@@ -1535,8 +1687,8 @@ function isZodSchema(obj) {
|
|
|
1535
1687
|
const record = obj;
|
|
1536
1688
|
return "_def" in record && "parse" in record && hasCallableParse(record);
|
|
1537
1689
|
}
|
|
1538
|
-
function mapFinishReason(reason) {
|
|
1539
|
-
const raw = reason ?? void 0;
|
|
1690
|
+
function mapFinishReason(reason, originalReason) {
|
|
1691
|
+
const raw = originalReason ?? reason ?? void 0;
|
|
1540
1692
|
if (!reason) {
|
|
1541
1693
|
return { raw, unified: "other" };
|
|
1542
1694
|
}
|
|
@@ -1631,6 +1783,18 @@ function normalizeEmbedding(embedding) {
|
|
|
1631
1783
|
);
|
|
1632
1784
|
return Array.from(float32Array);
|
|
1633
1785
|
}
|
|
1786
|
+
function buildOrchestrationReasoningMetadata(block, providerName) {
|
|
1787
|
+
return { [providerName]: { reasoningContent: block } };
|
|
1788
|
+
}
|
|
1789
|
+
function getProviderFinishReason(fields) {
|
|
1790
|
+
const reason = fields?.finish_reason;
|
|
1791
|
+
return typeof reason === "string" && reason.length > 0 ? reason : void 0;
|
|
1792
|
+
}
|
|
1793
|
+
function parseProviderSpecificFields(value) {
|
|
1794
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1795
|
+
const fields = sanitizeAsJSONObject(value);
|
|
1796
|
+
return fields !== null && typeof fields === "object" && !Array.isArray(fields) ? fields : void 0;
|
|
1797
|
+
}
|
|
1634
1798
|
function sanitizeAsJSONArray(value) {
|
|
1635
1799
|
try {
|
|
1636
1800
|
return JSON.parse(JSON.stringify(value, jsonReplacer));
|
|
@@ -1662,16 +1826,17 @@ var VERSION;
|
|
|
1662
1826
|
var init_version = __esm({
|
|
1663
1827
|
"src/version.ts"() {
|
|
1664
1828
|
"use strict";
|
|
1665
|
-
VERSION = true ? "5.0
|
|
1829
|
+
VERSION = true ? "5.1.0" : "0.0.0-test";
|
|
1666
1830
|
}
|
|
1667
1831
|
});
|
|
1668
1832
|
|
|
1669
1833
|
// src/base-embedding-model-strategy.ts
|
|
1670
|
-
var
|
|
1834
|
+
var import_provider4, BaseEmbeddingModelStrategy;
|
|
1671
1835
|
var init_base_embedding_model_strategy = __esm({
|
|
1672
1836
|
"src/base-embedding-model-strategy.ts"() {
|
|
1673
1837
|
"use strict";
|
|
1674
|
-
|
|
1838
|
+
import_provider4 = require("@ai-sdk/provider");
|
|
1839
|
+
init_abort_utils();
|
|
1675
1840
|
init_deep_merge();
|
|
1676
1841
|
init_sap_ai_error();
|
|
1677
1842
|
init_sap_ai_provider_options();
|
|
@@ -1691,25 +1856,30 @@ var init_base_embedding_model_strategy = __esm({
|
|
|
1691
1856
|
const { abortSignal, values } = options;
|
|
1692
1857
|
try {
|
|
1693
1858
|
if (values.length > maxEmbeddingsPerCall) {
|
|
1694
|
-
throw new
|
|
1859
|
+
throw new import_provider4.TooManyEmbeddingValuesForCallError({
|
|
1695
1860
|
maxEmbeddingsPerCall,
|
|
1696
1861
|
modelId: config.modelId,
|
|
1697
1862
|
provider: config.provider,
|
|
1698
1863
|
values
|
|
1699
1864
|
});
|
|
1700
1865
|
}
|
|
1866
|
+
throwIfAborted(abortSignal);
|
|
1701
1867
|
const embeddingOptions = config.parsedProviderOptions;
|
|
1702
1868
|
const providerName = getProviderName(config.provider);
|
|
1703
1869
|
const embeddingType = embeddingOptions?.type ?? settings.type ?? "text";
|
|
1704
1870
|
const warnings = [];
|
|
1705
1871
|
this.resolveWarnings(settings, warnings);
|
|
1706
1872
|
const client = this.createClient(config, settings, embeddingOptions);
|
|
1707
|
-
const response = await
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1873
|
+
const response = await waitWithAbort(
|
|
1874
|
+
this.executeCall(
|
|
1875
|
+
client,
|
|
1876
|
+
values,
|
|
1877
|
+
embeddingType,
|
|
1878
|
+
mergeRequestConfig(config.requestConfig, abortSignal, options.headers)
|
|
1879
|
+
),
|
|
1880
|
+
abortSignal
|
|
1712
1881
|
);
|
|
1882
|
+
throwIfAborted(abortSignal);
|
|
1713
1883
|
const embeddings = this.extractEmbeddings(response);
|
|
1714
1884
|
const totalTokens = this.extractTokenCount(response);
|
|
1715
1885
|
const { headers: responseHeaders, requestId } = this.extractResponseMetadata(response);
|
|
@@ -1724,7 +1894,7 @@ var init_base_embedding_model_strategy = __esm({
|
|
|
1724
1894
|
warnings
|
|
1725
1895
|
});
|
|
1726
1896
|
} catch (error) {
|
|
1727
|
-
if (error instanceof
|
|
1897
|
+
if (error instanceof import_provider4.TooManyEmbeddingValuesForCallError) {
|
|
1728
1898
|
throw error;
|
|
1729
1899
|
}
|
|
1730
1900
|
throw convertToAISDKError(error, {
|
|
@@ -1825,22 +1995,22 @@ var init_foundation_models_embedding_model_strategy = __esm({
|
|
|
1825
1995
|
|
|
1826
1996
|
// src/sap-ai-validation.ts
|
|
1827
1997
|
function validateEscapeTemplatePlaceholders(api, escapeTemplatePlaceholders) {
|
|
1828
|
-
if (api
|
|
1998
|
+
if (api !== "orchestration" && escapeTemplatePlaceholders === true) {
|
|
1829
1999
|
throw new UnsupportedFeatureError(
|
|
1830
2000
|
ESCAPE_TEMPLATE_PLACEHOLDERS_DESCRIPTION,
|
|
1831
|
-
|
|
2001
|
+
api,
|
|
1832
2002
|
"orchestration"
|
|
1833
2003
|
);
|
|
1834
2004
|
}
|
|
1835
2005
|
}
|
|
1836
|
-
function validateFoundationModelsOnlyOptions(settings) {
|
|
2006
|
+
function validateFoundationModelsOnlyOptions(api, settings) {
|
|
1837
2007
|
if (!settings) return;
|
|
1838
2008
|
const fmSettings = settings;
|
|
1839
2009
|
for (const feature of FOUNDATION_MODELS_ONLY_FEATURE_KEYS) {
|
|
1840
2010
|
if (fmSettings[feature] !== void 0) {
|
|
1841
2011
|
throw new UnsupportedFeatureError(
|
|
1842
2012
|
FOUNDATION_MODELS_ONLY_FEATURES[feature],
|
|
1843
|
-
|
|
2013
|
+
api,
|
|
1844
2014
|
"foundation-models"
|
|
1845
2015
|
);
|
|
1846
2016
|
}
|
|
@@ -1858,23 +2028,19 @@ function validateOrchestrationOnlyEmbeddingOptions(settings) {
|
|
|
1858
2028
|
}
|
|
1859
2029
|
}
|
|
1860
2030
|
}
|
|
1861
|
-
function validateOrchestrationOnlyOptions(settings) {
|
|
2031
|
+
function validateOrchestrationOnlyOptions(api, settings) {
|
|
1862
2032
|
if (!settings) return;
|
|
1863
2033
|
const orchSettings = settings;
|
|
1864
2034
|
for (const feature of ORCHESTRATION_ONLY_FEATURE_KEYS) {
|
|
1865
2035
|
if (orchSettings[feature] !== void 0) {
|
|
1866
|
-
throw new UnsupportedFeatureError(
|
|
1867
|
-
ORCHESTRATION_ONLY_FEATURES[feature],
|
|
1868
|
-
"foundation-models",
|
|
1869
|
-
"orchestration"
|
|
1870
|
-
);
|
|
2036
|
+
throw new UnsupportedFeatureError(ORCHESTRATION_ONLY_FEATURES[feature], api, "orchestration");
|
|
1871
2037
|
}
|
|
1872
2038
|
}
|
|
1873
2039
|
}
|
|
1874
2040
|
function validateApiSwitch(fromApi, toApi, modelSettings, embeddingSettings) {
|
|
1875
2041
|
if (fromApi === toApi) return;
|
|
1876
2042
|
if (!modelSettings && !embeddingSettings) return;
|
|
1877
|
-
if (
|
|
2043
|
+
if (toApi !== "orchestration") {
|
|
1878
2044
|
const orchSettings = modelSettings;
|
|
1879
2045
|
for (const feature of ORCHESTRATION_ONLY_FEATURE_KEYS) {
|
|
1880
2046
|
if (orchSettings?.[feature] !== void 0) {
|
|
@@ -1887,7 +2053,7 @@ function validateApiSwitch(fromApi, toApi, modelSettings, embeddingSettings) {
|
|
|
1887
2053
|
}
|
|
1888
2054
|
}
|
|
1889
2055
|
}
|
|
1890
|
-
if (
|
|
2056
|
+
if (toApi !== "foundation-models") {
|
|
1891
2057
|
const fmSettings = modelSettings;
|
|
1892
2058
|
for (const feature of FOUNDATION_MODELS_ONLY_FEATURE_KEYS) {
|
|
1893
2059
|
if (fmSettings?.[feature] !== void 0) {
|
|
@@ -1895,6 +2061,9 @@ function validateApiSwitch(fromApi, toApi, modelSettings, embeddingSettings) {
|
|
|
1895
2061
|
}
|
|
1896
2062
|
}
|
|
1897
2063
|
}
|
|
2064
|
+
if (toApi !== "responses" && modelSettings && "responses" in modelSettings && modelSettings.responses !== void 0) {
|
|
2065
|
+
throw new ApiSwitchError(fromApi, toApi, "responses");
|
|
2066
|
+
}
|
|
1898
2067
|
}
|
|
1899
2068
|
function mergeSettingsWithApi(defaultSettings, callSettings, fallbackApi) {
|
|
1900
2069
|
return {
|
|
@@ -1945,142 +2114,1234 @@ function validateSettings(options) {
|
|
|
1945
2114
|
);
|
|
1946
2115
|
}
|
|
1947
2116
|
}
|
|
1948
|
-
if (api === "
|
|
1949
|
-
|
|
1950
|
-
|
|
2117
|
+
if (api === "responses" && embeddingSettings !== void 0) {
|
|
2118
|
+
throw new UnsupportedFeatureError("Embeddings", "responses", "foundation-models");
|
|
2119
|
+
}
|
|
2120
|
+
if (api !== "orchestration") {
|
|
2121
|
+
validateOrchestrationOnlyOptions(api, modelSettings);
|
|
2122
|
+
validateOrchestrationOnlyInvocationOptions(api, invocationSettings);
|
|
1951
2123
|
validateOrchestrationOnlyEmbeddingOptions(embeddingSettings);
|
|
2124
|
+
}
|
|
2125
|
+
if (api !== "foundation-models") {
|
|
2126
|
+
validateFoundationModelsOnlyOptions(api, modelSettings);
|
|
2127
|
+
}
|
|
2128
|
+
const modelResponses = modelSettings && "responses" in modelSettings ? modelSettings.responses : void 0;
|
|
2129
|
+
const invocationResponses = invocationSettings?.responses;
|
|
2130
|
+
if (api !== "responses") {
|
|
2131
|
+
if (modelResponses !== void 0 || invocationResponses !== void 0) {
|
|
2132
|
+
throw new UnsupportedFeatureError("Responses options (responses)", api, "responses");
|
|
2133
|
+
}
|
|
1952
2134
|
} else {
|
|
1953
|
-
|
|
2135
|
+
if (modelResponses !== void 0) responsesModelOptionsSchema.parse(modelResponses);
|
|
2136
|
+
if (invocationResponses !== void 0) responsesModelOptionsSchema.parse(invocationResponses);
|
|
2137
|
+
}
|
|
2138
|
+
const modelDropUnsupportedParams = modelSettings?.dropUnsupportedParams;
|
|
2139
|
+
if (modelDropUnsupportedParams !== void 0) {
|
|
2140
|
+
dropUnsupportedParamsSchema.parse(modelDropUnsupportedParams);
|
|
2141
|
+
}
|
|
2142
|
+
if (invocationSettings?.dropUnsupportedParams !== void 0) {
|
|
2143
|
+
dropUnsupportedParamsSchema.parse(invocationSettings.dropUnsupportedParams);
|
|
1954
2144
|
}
|
|
1955
2145
|
const modelEscape = modelSettings?.escapeTemplatePlaceholders;
|
|
1956
2146
|
const invocationEscape = invocationSettings?.escapeTemplatePlaceholders;
|
|
1957
2147
|
const effectiveEscape = invocationEscape ?? modelEscape;
|
|
1958
2148
|
validateEscapeTemplatePlaceholders(api, effectiveEscape);
|
|
1959
2149
|
}
|
|
1960
|
-
function validateOrchestrationOnlyInvocationOptions(invocationSettings) {
|
|
2150
|
+
function validateOrchestrationOnlyInvocationOptions(api, invocationSettings) {
|
|
1961
2151
|
if (!invocationSettings) return;
|
|
1962
2152
|
for (const feature of ORCHESTRATION_ONLY_INVOCATION_FEATURE_KEYS) {
|
|
1963
2153
|
if (invocationSettings[feature] !== void 0) {
|
|
1964
|
-
throw new UnsupportedFeatureError(
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2154
|
+
throw new UnsupportedFeatureError(ORCHESTRATION_ONLY_FEATURES[feature], api, "orchestration");
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
var ORCHESTRATION_ONLY_FEATURE_KEYS, ORCHESTRATION_ONLY_FEATURES, FOUNDATION_MODELS_ONLY_FEATURE_KEYS, FOUNDATION_MODELS_ONLY_FEATURES, ORCHESTRATION_ONLY_INVOCATION_FEATURE_KEYS, ORCHESTRATION_ONLY_EMBEDDING_FEATURE_KEYS, ORCHESTRATION_ONLY_EMBEDDING_FEATURES, ESCAPE_TEMPLATE_PLACEHOLDERS_DESCRIPTION, VALID_API_TYPES;
|
|
2159
|
+
var init_sap_ai_validation = __esm({
|
|
2160
|
+
"src/sap-ai-validation.ts"() {
|
|
2161
|
+
"use strict";
|
|
2162
|
+
init_deep_merge();
|
|
2163
|
+
init_sap_ai_error();
|
|
2164
|
+
init_sap_ai_provider_options();
|
|
2165
|
+
ORCHESTRATION_ONLY_FEATURE_KEYS = [
|
|
2166
|
+
"dropUnsupportedParams",
|
|
2167
|
+
"fallbackModuleConfigs",
|
|
2168
|
+
"filtering",
|
|
2169
|
+
"grounding",
|
|
2170
|
+
"masking",
|
|
2171
|
+
"orchestrationConfigRef",
|
|
2172
|
+
"placeholderValues",
|
|
2173
|
+
"promptTemplateRef",
|
|
2174
|
+
"streamOptions",
|
|
2175
|
+
"tools",
|
|
2176
|
+
"translation"
|
|
2177
|
+
];
|
|
2178
|
+
ORCHESTRATION_ONLY_FEATURES = {
|
|
2179
|
+
dropUnsupportedParams: "Unsupported parameter handling (dropUnsupportedParams)",
|
|
2180
|
+
fallbackModuleConfigs: "Fallback module configurations (fallbackModuleConfigs)",
|
|
2181
|
+
filtering: "Content filtering",
|
|
2182
|
+
grounding: "Document grounding",
|
|
2183
|
+
masking: "Data masking",
|
|
2184
|
+
orchestrationConfigRef: "Orchestration config reference (orchestrationConfigRef)",
|
|
2185
|
+
placeholderValues: "Placeholder values (placeholderValues)",
|
|
2186
|
+
promptTemplateRef: "Prompt template reference (promptTemplateRef)",
|
|
2187
|
+
streamOptions: "Stream options for post-LLM modules",
|
|
2188
|
+
tools: "SAP-format tool definitions (use AI SDK tools instead)",
|
|
2189
|
+
translation: "Translation"
|
|
2190
|
+
};
|
|
2191
|
+
FOUNDATION_MODELS_ONLY_FEATURE_KEYS = ["dataSources"];
|
|
2192
|
+
FOUNDATION_MODELS_ONLY_FEATURES = {
|
|
2193
|
+
dataSources: "Azure On Your Data (dataSources)"
|
|
2194
|
+
};
|
|
2195
|
+
ORCHESTRATION_ONLY_INVOCATION_FEATURE_KEYS = [
|
|
2196
|
+
"dropUnsupportedParams",
|
|
2197
|
+
"orchestrationConfigRef",
|
|
2198
|
+
"placeholderValues",
|
|
2199
|
+
"promptTemplateRef"
|
|
2200
|
+
];
|
|
2201
|
+
ORCHESTRATION_ONLY_EMBEDDING_FEATURE_KEYS = ["masking"];
|
|
2202
|
+
ORCHESTRATION_ONLY_EMBEDDING_FEATURES = {
|
|
2203
|
+
masking: ORCHESTRATION_ONLY_FEATURES.masking
|
|
2204
|
+
};
|
|
2205
|
+
ESCAPE_TEMPLATE_PLACEHOLDERS_DESCRIPTION = "escapeTemplatePlaceholders (Jinja2 template escaping)";
|
|
2206
|
+
VALID_API_TYPES = [
|
|
2207
|
+
"orchestration",
|
|
2208
|
+
"foundation-models",
|
|
2209
|
+
"responses"
|
|
2210
|
+
];
|
|
2211
|
+
}
|
|
2212
|
+
});
|
|
2213
|
+
|
|
2214
|
+
// src/orchestration-embedding-model-strategy.ts
|
|
2215
|
+
var orchestration_embedding_model_strategy_exports = {};
|
|
2216
|
+
__export(orchestration_embedding_model_strategy_exports, {
|
|
2217
|
+
OrchestrationEmbeddingModelStrategy: () => OrchestrationEmbeddingModelStrategy
|
|
2218
|
+
});
|
|
2219
|
+
var OrchestrationEmbeddingModelStrategy;
|
|
2220
|
+
var init_orchestration_embedding_model_strategy = __esm({
|
|
2221
|
+
"src/orchestration-embedding-model-strategy.ts"() {
|
|
2222
|
+
"use strict";
|
|
2223
|
+
init_base_embedding_model_strategy();
|
|
2224
|
+
init_sap_ai_validation();
|
|
2225
|
+
init_strategy_utils();
|
|
2226
|
+
OrchestrationEmbeddingModelStrategy = class extends BaseEmbeddingModelStrategy {
|
|
2227
|
+
ClientClass;
|
|
2228
|
+
constructor(ClientClass) {
|
|
2229
|
+
super();
|
|
2230
|
+
this.ClientClass = ClientClass;
|
|
2231
|
+
}
|
|
2232
|
+
createClient(config, settings, embeddingOptions) {
|
|
2233
|
+
const mergedParams = this.mergeModelParams(settings, embeddingOptions);
|
|
2234
|
+
const embeddingConfig = {
|
|
2235
|
+
model: {
|
|
2236
|
+
name: config.modelId,
|
|
2237
|
+
...hasKeys(mergedParams) ? { params: mergedParams } : {},
|
|
2238
|
+
...settings.modelVersion ? { version: settings.modelVersion } : {}
|
|
2239
|
+
}
|
|
2240
|
+
};
|
|
2241
|
+
const moduleConfig = {
|
|
2242
|
+
embeddings: embeddingConfig,
|
|
2243
|
+
...settings.masking && hasKeys(settings.masking) ? { masking: settings.masking } : {}
|
|
2244
|
+
};
|
|
2245
|
+
return new this.ClientClass(moduleConfig, config.deploymentConfig, config.destination);
|
|
2246
|
+
}
|
|
2247
|
+
async executeCall(client, values, embeddingType, requestConfig) {
|
|
2248
|
+
return client.embed({ input: values, type: embeddingType }, requestConfig);
|
|
2249
|
+
}
|
|
2250
|
+
extractEmbeddings(response) {
|
|
2251
|
+
const embeddingData = response.getEmbeddings();
|
|
2252
|
+
const sortedEmbeddings = [...embeddingData].sort((a, b) => a.index - b.index);
|
|
2253
|
+
return sortedEmbeddings.map((data) => normalizeEmbedding(data.embedding));
|
|
2254
|
+
}
|
|
2255
|
+
extractResponseMetadata(response) {
|
|
2256
|
+
return extractResponseMetadata(response, "response");
|
|
2257
|
+
}
|
|
2258
|
+
extractTokenCount(response) {
|
|
2259
|
+
const tokenUsage = response.getTokenUsage();
|
|
2260
|
+
return tokenUsage.total_tokens;
|
|
2261
|
+
}
|
|
2262
|
+
getUrl() {
|
|
2263
|
+
return "sap-ai:orchestration/embeddings";
|
|
2264
|
+
}
|
|
2265
|
+
resolveWarnings(settings, warnings) {
|
|
2266
|
+
validateMaskingProvidersDeprecation(settings, warnings);
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
});
|
|
2271
|
+
|
|
2272
|
+
// src/responses-adapters-v3-to-v4.ts
|
|
2273
|
+
function convertResponsesCallToV4(options) {
|
|
2274
|
+
return {
|
|
2275
|
+
...options,
|
|
2276
|
+
prompt: options.prompt.map((message) => {
|
|
2277
|
+
switch (message.role) {
|
|
2278
|
+
case "assistant":
|
|
2279
|
+
return { ...message, content: message.content.map(convertPromptPart) };
|
|
2280
|
+
case "system":
|
|
2281
|
+
return message;
|
|
2282
|
+
case "tool":
|
|
2283
|
+
return {
|
|
2284
|
+
...message,
|
|
2285
|
+
content: message.content.map(
|
|
2286
|
+
(part) => part.type === "tool-result" ? convertToolResult(part) : part
|
|
2287
|
+
)
|
|
2288
|
+
};
|
|
2289
|
+
case "user":
|
|
2290
|
+
return {
|
|
2291
|
+
...message,
|
|
2292
|
+
content: message.content.map(
|
|
2293
|
+
(part) => part.type === "file" ? convertFile(part) : part
|
|
2294
|
+
)
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
})
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
function convertFile(part) {
|
|
2301
|
+
const data = part.data;
|
|
2302
|
+
const href = getURLHref(data);
|
|
2303
|
+
if (href !== void 0) {
|
|
2304
|
+
const url = data instanceof URL && data.toString === URL.prototype.toString ? data : new URL(href);
|
|
2305
|
+
return { ...part, data: { type: "url", url } };
|
|
2306
|
+
}
|
|
2307
|
+
return { ...part, data: { data, type: "data" } };
|
|
2308
|
+
}
|
|
2309
|
+
function convertPromptPart(part) {
|
|
2310
|
+
if (part.type === "file") {
|
|
2311
|
+
throw new import_provider5.UnsupportedFunctionalityError({
|
|
2312
|
+
functionality: "Responses assistant file history is not supported."
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
if (part.type === "tool-result") return convertToolResult(part);
|
|
2316
|
+
return part;
|
|
2317
|
+
}
|
|
2318
|
+
function convertToolItem(item) {
|
|
2319
|
+
switch (item.type) {
|
|
2320
|
+
case "custom":
|
|
2321
|
+
case "text":
|
|
2322
|
+
return item;
|
|
2323
|
+
case "file-data":
|
|
2324
|
+
case "image-data": {
|
|
2325
|
+
const delegateIsImage = (0, import_provider_utils2.getTopLevelMediaType)(item.mediaType) === "image";
|
|
2326
|
+
if (delegateIsImage !== (item.type === "image-data")) {
|
|
2327
|
+
throw new import_provider5.UnsupportedFunctionalityError({
|
|
2328
|
+
functionality: "Responses tool-result media whose legacy category disagrees with its media type."
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
return { ...item, data: { data: item.data, type: "data" }, type: "file" };
|
|
2332
|
+
}
|
|
2333
|
+
case "file-id":
|
|
2334
|
+
case "image-file-id":
|
|
2335
|
+
return {
|
|
2336
|
+
data: {
|
|
2337
|
+
reference: typeof item.fileId === "string" ? { openai: item.fileId } : item.fileId,
|
|
2338
|
+
type: "reference"
|
|
2339
|
+
},
|
|
2340
|
+
mediaType: item.type === "image-file-id" ? "image" : "application/octet-stream",
|
|
2341
|
+
providerOptions: item.providerOptions,
|
|
2342
|
+
type: "file"
|
|
2343
|
+
};
|
|
2344
|
+
case "file-url":
|
|
2345
|
+
case "image-url":
|
|
2346
|
+
return {
|
|
2347
|
+
data: { type: "url", url: new URL(item.url) },
|
|
2348
|
+
mediaType: item.type === "image-url" ? "image" : "application/octet-stream",
|
|
2349
|
+
providerOptions: item.providerOptions,
|
|
2350
|
+
type: "file"
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
function convertToolResult(part) {
|
|
2355
|
+
return part.output.type === "content" ? { ...part, output: { ...part.output, value: part.output.value.map(convertToolItem) } } : { ...part, output: part.output };
|
|
2356
|
+
}
|
|
2357
|
+
var import_provider5, import_provider_utils2;
|
|
2358
|
+
var init_responses_adapters_v3_to_v4 = __esm({
|
|
2359
|
+
"src/responses-adapters-v3-to-v4.ts"() {
|
|
2360
|
+
"use strict";
|
|
2361
|
+
import_provider5 = require("@ai-sdk/provider");
|
|
2362
|
+
import_provider_utils2 = require("@ai-sdk/provider-utils");
|
|
2363
|
+
init_convert_to_sap_messages();
|
|
2364
|
+
}
|
|
2365
|
+
});
|
|
2366
|
+
|
|
2367
|
+
// src/adapter-metadata.ts
|
|
2368
|
+
var ORIGINAL_V4_FINISH_REASON;
|
|
2369
|
+
var init_adapter_metadata = __esm({
|
|
2370
|
+
"src/adapter-metadata.ts"() {
|
|
2371
|
+
"use strict";
|
|
2372
|
+
ORIGINAL_V4_FINISH_REASON = /* @__PURE__ */ Symbol.for(
|
|
2373
|
+
"@jerome-benoit/sap-ai-provider/adapter-metadata.originalV4FinishReason"
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
});
|
|
2377
|
+
|
|
2378
|
+
// src/responses-adapters-v4-to-v3.ts
|
|
2379
|
+
function convertResponsesResultToV3(result) {
|
|
2380
|
+
return {
|
|
2381
|
+
...result,
|
|
2382
|
+
content: result.content.map(convertContent),
|
|
2383
|
+
finishReason: convertFinishReason(result.finishReason),
|
|
2384
|
+
warnings: result.warnings.map(convertWarning)
|
|
2385
|
+
};
|
|
2386
|
+
}
|
|
2387
|
+
function convertResponsesStreamPartToV3(part) {
|
|
2388
|
+
switch (part.type) {
|
|
2389
|
+
case "custom":
|
|
2390
|
+
case "reasoning-file":
|
|
2391
|
+
throw new import_provider6.UnsupportedFunctionalityError({
|
|
2392
|
+
functionality: `Responses '${part.type}' output has no V3 equivalent.`
|
|
2393
|
+
});
|
|
2394
|
+
case "file":
|
|
2395
|
+
return convertGeneratedFile(part);
|
|
2396
|
+
case "finish":
|
|
2397
|
+
return { ...part, finishReason: convertFinishReason(part.finishReason) };
|
|
2398
|
+
case "stream-start":
|
|
2399
|
+
return { ...part, warnings: part.warnings.map(convertWarning) };
|
|
2400
|
+
default:
|
|
2401
|
+
return part;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
function convertContent(part) {
|
|
2405
|
+
if (part.type === "custom" || part.type === "reasoning-file") {
|
|
2406
|
+
throw new import_provider6.UnsupportedFunctionalityError({
|
|
2407
|
+
functionality: `Responses '${part.type}' output has no V3 equivalent.`
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
return part.type === "file" ? convertGeneratedFile(part) : part;
|
|
2411
|
+
}
|
|
2412
|
+
function convertFinishReason(reason) {
|
|
2413
|
+
if (reason.unified !== "interrupted") return reason;
|
|
2414
|
+
const converted = { ...reason, unified: "other" };
|
|
2415
|
+
return Object.defineProperty(converted, ORIGINAL_V4_FINISH_REASON, { value: reason });
|
|
2416
|
+
}
|
|
2417
|
+
function convertGeneratedFile(part) {
|
|
2418
|
+
if (part.data.type !== "data") {
|
|
2419
|
+
throw new import_provider6.UnsupportedFunctionalityError({
|
|
2420
|
+
functionality: "Responses generated file URLs have no V3 equivalent and are not fetched."
|
|
2421
|
+
});
|
|
2422
|
+
}
|
|
2423
|
+
return { ...part, data: part.data.data };
|
|
2424
|
+
}
|
|
2425
|
+
function convertWarning(warning) {
|
|
2426
|
+
return warning.type === "deprecated" ? { message: `${warning.setting}: ${warning.message}`, type: "other" } : warning;
|
|
2427
|
+
}
|
|
2428
|
+
var import_provider6;
|
|
2429
|
+
var init_responses_adapters_v4_to_v3 = __esm({
|
|
2430
|
+
"src/responses-adapters-v4-to-v3.ts"() {
|
|
2431
|
+
"use strict";
|
|
2432
|
+
import_provider6 = require("@ai-sdk/provider");
|
|
2433
|
+
init_adapter_metadata();
|
|
2434
|
+
}
|
|
2435
|
+
});
|
|
2436
|
+
|
|
2437
|
+
// src/sap-http-stream.ts
|
|
2438
|
+
function destroyHttpResponse(response, retainedRequest) {
|
|
2439
|
+
const body = response.data;
|
|
2440
|
+
const request = response.request;
|
|
2441
|
+
try {
|
|
2442
|
+
if (isDestroyableRequest(body)) body.destroy();
|
|
2443
|
+
} finally {
|
|
2444
|
+
if (request !== retainedRequest && isDestroyableRequest(request)) request.destroy();
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
function disposeSapStream(response) {
|
|
2448
|
+
if (disposedStreams.has(response)) return;
|
|
2449
|
+
disposedStreams.add(response);
|
|
2450
|
+
try {
|
|
2451
|
+
response.stream.controller.abort();
|
|
2452
|
+
} finally {
|
|
2453
|
+
if (leasedStreams.has(response)) releaseSapStream(response);
|
|
2454
|
+
else destroyHttpResponse(response.rawResponse);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
async function executeSapStream(execute, signal, requestConfig) {
|
|
2458
|
+
const responses = [];
|
|
2459
|
+
const cleanups = /* @__PURE__ */ new Set();
|
|
2460
|
+
let closed = false;
|
|
2461
|
+
let transferred = false;
|
|
2462
|
+
let failedRequest;
|
|
2463
|
+
let failedError;
|
|
2464
|
+
const release = () => {
|
|
2465
|
+
closed = true;
|
|
2466
|
+
signal?.removeEventListener("abort", release);
|
|
2467
|
+
for (const response of responses) {
|
|
2468
|
+
if (response.fromTransport && isConsumedHttpBody(response.data)) continue;
|
|
2469
|
+
const consumedRequest = responses.some(
|
|
2470
|
+
(other) => other.fromTransport && other.request === response.request && isConsumedHttpBody(other.data)
|
|
1968
2471
|
);
|
|
2472
|
+
try {
|
|
2473
|
+
const dispose = response.disposeTimeout;
|
|
2474
|
+
const retainedRequest = consumedRequest ? response.request : void 0;
|
|
2475
|
+
if (dispose && cleanups.has(dispose)) dispose(retainedRequest);
|
|
2476
|
+
else destroyHttpResponse(response, retainedRequest);
|
|
2477
|
+
} catch {
|
|
2478
|
+
}
|
|
1969
2479
|
}
|
|
2480
|
+
responses.length = 0;
|
|
2481
|
+
cleanups.clear();
|
|
2482
|
+
};
|
|
2483
|
+
const ownResponse = (response, request, fromTransport, failed) => {
|
|
2484
|
+
const data = response.data;
|
|
2485
|
+
const nativeRequest = response.request;
|
|
2486
|
+
const owned = responses.find((other) => other.data === data && other.request === nativeRequest);
|
|
2487
|
+
if (owned) {
|
|
2488
|
+
if (failed && !owned.disposeTimeout) {
|
|
2489
|
+
owned.disposeTimeout = preserveResponseBodyTimeout(response, request, cleanups);
|
|
2490
|
+
}
|
|
2491
|
+
} else {
|
|
2492
|
+
responses.push({
|
|
2493
|
+
data,
|
|
2494
|
+
disposeTimeout: failed ? preserveResponseBodyTimeout(response, request, cleanups) : void 0,
|
|
2495
|
+
fromTransport,
|
|
2496
|
+
request: nativeRequest
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
if (closed || signal?.aborted) release();
|
|
2500
|
+
};
|
|
2501
|
+
const observeResponse = ({ fn }) => async (request) => {
|
|
2502
|
+
try {
|
|
2503
|
+
const response = await fn(request);
|
|
2504
|
+
ownResponse(response, request, true, false);
|
|
2505
|
+
return response;
|
|
2506
|
+
} catch (error) {
|
|
2507
|
+
const failed = findFailedHttpRequest(error);
|
|
2508
|
+
if (failed) ownResponse(failed.response, request, true, true);
|
|
2509
|
+
throw error;
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
const captureFinalFailure = ({ fn }) => async (request) => {
|
|
2513
|
+
try {
|
|
2514
|
+
const response = await fn(request);
|
|
2515
|
+
ownResponse(response, request, false, false);
|
|
2516
|
+
return response;
|
|
2517
|
+
} catch (error) {
|
|
2518
|
+
const failed = findFailedHttpRequest(error);
|
|
2519
|
+
if (!failed) throw error;
|
|
2520
|
+
failedRequest = failed;
|
|
2521
|
+
failedError = error;
|
|
2522
|
+
ownResponse(failed.response, request, false, true);
|
|
2523
|
+
return failed.response;
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
try {
|
|
2527
|
+
const response = await waitWithAbort(
|
|
2528
|
+
execute({
|
|
2529
|
+
...requestConfig,
|
|
2530
|
+
middleware: [captureFinalFailure, ...requestConfig?.middleware ?? [], observeResponse]
|
|
2531
|
+
}),
|
|
2532
|
+
signal,
|
|
2533
|
+
disposeSapStream
|
|
2534
|
+
);
|
|
2535
|
+
if (signal?.aborted) {
|
|
2536
|
+
try {
|
|
2537
|
+
disposeSapStream(response);
|
|
2538
|
+
} finally {
|
|
2539
|
+
throwIfAborted(signal);
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
if (failedRequest) {
|
|
2543
|
+
try {
|
|
2544
|
+
await readHttpErrorBody(
|
|
2545
|
+
failedRequest.response,
|
|
2546
|
+
createErrorByteStream(failedRequest.response),
|
|
2547
|
+
signal
|
|
2548
|
+
);
|
|
2549
|
+
} catch {
|
|
2550
|
+
throwIfAborted(signal);
|
|
2551
|
+
}
|
|
2552
|
+
throw failedError;
|
|
2553
|
+
}
|
|
2554
|
+
if (responses.length > 0) {
|
|
2555
|
+
streamLeases.set(response, release);
|
|
2556
|
+
leasedStreams.add(response);
|
|
2557
|
+
signal?.addEventListener("abort", release, { once: true });
|
|
2558
|
+
if (signal?.aborted) {
|
|
2559
|
+
releaseSapStream(response);
|
|
2560
|
+
throwIfAborted(signal);
|
|
2561
|
+
}
|
|
2562
|
+
transferred = true;
|
|
2563
|
+
}
|
|
2564
|
+
return response;
|
|
2565
|
+
} finally {
|
|
2566
|
+
if (!transferred) release();
|
|
1970
2567
|
}
|
|
1971
2568
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2569
|
+
function findFailedHttpRequest(error) {
|
|
2570
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2571
|
+
let current = error;
|
|
2572
|
+
for (let depth = 0; depth < 32; depth++) {
|
|
2573
|
+
if (typeof current !== "object" || current === null || seen.has(current)) return void 0;
|
|
2574
|
+
if (import_provider7.AISDKError.isInstance(current)) return void 0;
|
|
2575
|
+
seen.add(current);
|
|
2576
|
+
if (isFailedHttpRequest(current)) return current;
|
|
2577
|
+
current = "cause" in current ? current.cause : current instanceof Error && (0, import_util2.isErrorWithCause)(current) ? current.rootCause : void 0;
|
|
2578
|
+
}
|
|
2579
|
+
return void 0;
|
|
2580
|
+
}
|
|
2581
|
+
function isDestroyableRequest(request) {
|
|
2582
|
+
return typeof request === "object" && request !== null && "destroy" in request && typeof request.destroy === "function";
|
|
2583
|
+
}
|
|
2584
|
+
function preserveResponseBodyTimeout(response, requestConfig, cleanups) {
|
|
2585
|
+
const body = response.data;
|
|
2586
|
+
const request = response.request;
|
|
2587
|
+
if (!isHttpResponseEvents(body) || !isHttpResponseEvents(request)) return;
|
|
2588
|
+
const responseConfig = "config" in response ? response.config : void 0;
|
|
2589
|
+
const timeoutConfig = typeof responseConfig === "object" && responseConfig !== null && !Array.isArray(responseConfig) ? responseConfig : requestConfig;
|
|
2590
|
+
let ownsRequest = true;
|
|
2591
|
+
const release = () => {
|
|
2592
|
+
request.removeListener("timeout", onTimeout);
|
|
2593
|
+
body.removeListener("end", release);
|
|
2594
|
+
body.removeListener("error", onFailure);
|
|
2595
|
+
body.removeListener("close", onFailure);
|
|
2596
|
+
cleanups.delete(dispose);
|
|
2597
|
+
};
|
|
2598
|
+
const onFailure = () => {
|
|
2599
|
+
try {
|
|
2600
|
+
if (ownsRequest) request.destroy();
|
|
2601
|
+
} finally {
|
|
2602
|
+
release();
|
|
2603
|
+
}
|
|
2604
|
+
};
|
|
2605
|
+
const dispose = (retainedRequest) => {
|
|
2606
|
+
ownsRequest = request !== retainedRequest;
|
|
2607
|
+
request.removeListener("timeout", onTimeout);
|
|
2608
|
+
try {
|
|
2609
|
+
body.destroy();
|
|
2610
|
+
} finally {
|
|
2611
|
+
if (ownsRequest) request.destroy();
|
|
2612
|
+
}
|
|
2613
|
+
};
|
|
2614
|
+
const onTimeout = () => {
|
|
2615
|
+
const nativeResponse = "res" in request ? request.res : void 0;
|
|
2616
|
+
if (typeof nativeResponse === "object" && nativeResponse !== null && "complete" in nativeResponse && nativeResponse.complete === true) {
|
|
2617
|
+
release();
|
|
2618
|
+
return;
|
|
2619
|
+
}
|
|
2620
|
+
const timeout = timeoutConfig.timeout;
|
|
2621
|
+
const timeoutErrorMessage = timeoutConfig.timeoutErrorMessage;
|
|
2622
|
+
const transitional = timeoutConfig.transitional;
|
|
2623
|
+
const clarifyTimeoutError = typeof transitional === "object" && transitional !== null && "clarifyTimeoutError" in transitional && transitional.clarifyTimeoutError === true;
|
|
2624
|
+
const message = typeof timeoutErrorMessage === "string" && timeoutErrorMessage ? timeoutErrorMessage : (typeof timeout === "number" || typeof timeout === "string") && timeout ? `timeout of ${String(timeout)}ms exceeded` : "timeout exceeded";
|
|
2625
|
+
body.destroy(
|
|
2626
|
+
Object.assign(new Error(message), {
|
|
2627
|
+
code: clarifyTimeoutError ? "ETIMEDOUT" : "ECONNABORTED"
|
|
2628
|
+
})
|
|
2629
|
+
);
|
|
2630
|
+
request.destroy();
|
|
2631
|
+
};
|
|
2632
|
+
request.once("timeout", onTimeout);
|
|
2633
|
+
body.once("end", release);
|
|
2634
|
+
body.once("error", onFailure);
|
|
2635
|
+
body.once("close", onFailure);
|
|
2636
|
+
cleanups.add(dispose);
|
|
2637
|
+
return dispose;
|
|
2638
|
+
}
|
|
2639
|
+
async function readHttpErrorBody(response, stream, signal) {
|
|
2640
|
+
const decoder = new TextDecoder();
|
|
2641
|
+
const reader = stream.getReader();
|
|
2642
|
+
let retainedBytes = 0;
|
|
2643
|
+
let text = "";
|
|
2644
|
+
let truncated = false;
|
|
2645
|
+
let readFailure;
|
|
2646
|
+
try {
|
|
2647
|
+
for (; ; ) {
|
|
2648
|
+
const chunk = await waitWithAbort(reader.read(), signal);
|
|
2649
|
+
if (chunk.done) {
|
|
2650
|
+
text += decoder.decode();
|
|
2651
|
+
break;
|
|
2652
|
+
}
|
|
2653
|
+
const remaining = MAX_ERROR_BODY_BYTES - retainedBytes;
|
|
2654
|
+
text += decoder.decode(chunk.value.subarray(0, remaining), { stream: true });
|
|
2655
|
+
retainedBytes += Math.min(chunk.value.byteLength, remaining);
|
|
2656
|
+
if (chunk.value.byteLength > remaining) {
|
|
2657
|
+
truncated = true;
|
|
2658
|
+
await reader.cancel("HTTP error diagnostic limit exceeded");
|
|
2659
|
+
break;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
} catch (error) {
|
|
2663
|
+
readFailure = error;
|
|
2664
|
+
if (!truncated) text += decoder.decode();
|
|
2665
|
+
void reader.cancel(error).catch(() => {
|
|
2666
|
+
});
|
|
2667
|
+
} finally {
|
|
2668
|
+
if (signal?.aborted) {
|
|
2669
|
+
destroyHttpResponse(response);
|
|
2670
|
+
void reader.cancel(signal.reason).catch(() => {
|
|
2671
|
+
});
|
|
2672
|
+
}
|
|
2673
|
+
reader.releaseLock();
|
|
2674
|
+
}
|
|
2675
|
+
response.data = truncated ? text + ERROR_BODY_TRUNCATION : text;
|
|
2676
|
+
if (!truncated && readFailure === void 0) {
|
|
2677
|
+
try {
|
|
2678
|
+
response.data = JSON.parse(text);
|
|
2679
|
+
} catch {
|
|
2680
|
+
response.data = text;
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
throwIfAborted(signal);
|
|
2684
|
+
return readFailure;
|
|
2685
|
+
}
|
|
2686
|
+
function withSapStreamCleanup(response, stream) {
|
|
2687
|
+
if (!streamLeases.has(response)) return stream;
|
|
2688
|
+
return iterate();
|
|
2689
|
+
async function* iterate() {
|
|
2690
|
+
try {
|
|
2691
|
+
yield* stream;
|
|
2692
|
+
} finally {
|
|
2693
|
+
releaseSapStream(response);
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
function createErrorByteStream(response) {
|
|
2698
|
+
const body = response.data;
|
|
2699
|
+
if (typeof body !== "object" || body === null || !(Symbol.asyncIterator in body) || typeof body[Symbol.asyncIterator] !== "function") {
|
|
2700
|
+
throw new TypeError("SAP did not return a readable HTTP error body.");
|
|
2701
|
+
}
|
|
2702
|
+
const iterator = body[Symbol.asyncIterator]();
|
|
2703
|
+
const encoder = new TextEncoder();
|
|
2704
|
+
return new ReadableStream(
|
|
2705
|
+
{
|
|
2706
|
+
cancel() {
|
|
2707
|
+
destroyHttpResponse(response);
|
|
2708
|
+
},
|
|
2709
|
+
async pull(controller) {
|
|
2710
|
+
try {
|
|
2711
|
+
const chunk = await iterator.next();
|
|
2712
|
+
if (chunk.done) controller.close();
|
|
2713
|
+
else if (typeof chunk.value === "string") controller.enqueue(encoder.encode(chunk.value));
|
|
2714
|
+
else if (chunk.value instanceof Uint8Array) controller.enqueue(chunk.value);
|
|
2715
|
+
else throw new TypeError("SAP returned a non-byte HTTP error chunk.");
|
|
2716
|
+
} catch (error) {
|
|
2717
|
+
try {
|
|
2718
|
+
destroyHttpResponse(response);
|
|
2719
|
+
} catch {
|
|
2720
|
+
} finally {
|
|
2721
|
+
controller.error(error);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
},
|
|
2726
|
+
{ highWaterMark: 0 }
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
function isConsumedHttpBody(body) {
|
|
2730
|
+
return typeof body === "object" && body !== null && "readableEnded" in body && body.readableEnded === true;
|
|
2731
|
+
}
|
|
2732
|
+
function isFailedHttpRequest(error) {
|
|
2733
|
+
return error instanceof Error && "isAxiosError" in error && error.isAxiosError === true && "response" in error && typeof error.response === "object" && error.response !== null;
|
|
2734
|
+
}
|
|
2735
|
+
function isHttpResponseEvents(value) {
|
|
2736
|
+
return isDestroyableRequest(value) && "once" in value && typeof value.once === "function" && "removeListener" in value && typeof value.removeListener === "function";
|
|
2737
|
+
}
|
|
2738
|
+
function releaseSapStream(response) {
|
|
2739
|
+
const release = streamLeases.get(response);
|
|
2740
|
+
streamLeases.delete(response);
|
|
2741
|
+
release?.();
|
|
2742
|
+
}
|
|
2743
|
+
var import_provider7, import_util2, ERROR_BODY_TRUNCATION, MAX_ERROR_BODY_BYTES, ERROR_BODY_READ_FAILURE, disposedStreams, leasedStreams, streamLeases;
|
|
2744
|
+
var init_sap_http_stream = __esm({
|
|
2745
|
+
"src/sap-http-stream.ts"() {
|
|
2746
|
+
"use strict";
|
|
2747
|
+
import_provider7 = require("@ai-sdk/provider");
|
|
2748
|
+
import_util2 = require("@sap-cloud-sdk/util");
|
|
2749
|
+
init_abort_utils();
|
|
2750
|
+
ERROR_BODY_TRUNCATION = "...[truncated]";
|
|
2751
|
+
MAX_ERROR_BODY_BYTES = 2e3 - ERROR_BODY_TRUNCATION.length;
|
|
2752
|
+
ERROR_BODY_READ_FAILURE = /* @__PURE__ */ Symbol("sap-ai.httpErrorBodyReadFailure");
|
|
2753
|
+
disposedStreams = /* @__PURE__ */ new WeakSet();
|
|
2754
|
+
leasedStreams = /* @__PURE__ */ new WeakSet();
|
|
2755
|
+
streamLeases = /* @__PURE__ */ new WeakMap();
|
|
2756
|
+
}
|
|
2757
|
+
});
|
|
2758
|
+
|
|
2759
|
+
// src/responses-http-transport.ts
|
|
2760
|
+
async function createResponsesTransport(config, settings, options) {
|
|
2761
|
+
throwIfAborted(options.abortSignal);
|
|
2762
|
+
const deployment = buildModelDeployment(config, settings.modelVersion);
|
|
2763
|
+
const [deploymentId, destination] = await waitWithAbort(
|
|
2764
|
+
Promise.all([
|
|
2765
|
+
(0, import_internal.getFoundationModelDeploymentId)(deployment, "azure-openai", config.destination),
|
|
2766
|
+
(0, import_core.getAiCoreDestination)(config.destination)
|
|
2767
|
+
]),
|
|
2768
|
+
options.abortSignal
|
|
2769
|
+
);
|
|
2770
|
+
throwIfAborted(options.abortSignal);
|
|
2771
|
+
const deploymentPath = `/inference/deployments/${encodeURIComponent(deploymentId)}`;
|
|
2772
|
+
const baseURL = (0, import_internal2.getTargetUrl)(destination.url, deploymentPath);
|
|
2773
|
+
const endpoint = new URL(`${baseURL}/responses`);
|
|
2774
|
+
const requestConfig = mergeRequestConfig(
|
|
2775
|
+
config.requestConfig,
|
|
2776
|
+
options.abortSignal,
|
|
2777
|
+
options.headers
|
|
2778
|
+
);
|
|
2779
|
+
const activeRequests = /* @__PURE__ */ new Set();
|
|
2780
|
+
let disposed = false;
|
|
2781
|
+
let disposalReason;
|
|
2782
|
+
const dispose = (reason) => {
|
|
2783
|
+
if (disposed) return;
|
|
2784
|
+
disposed = true;
|
|
2785
|
+
disposalReason = reason;
|
|
2786
|
+
for (const release of activeRequests) {
|
|
2787
|
+
try {
|
|
2788
|
+
release(reason);
|
|
2789
|
+
} catch {
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
activeRequests.clear();
|
|
2793
|
+
};
|
|
2794
|
+
const fetch = async (input, init) => {
|
|
2795
|
+
if (disposed) throw createAbortError(disposalReason);
|
|
2796
|
+
const url = new URL(typeof input === "string" || input instanceof URL ? input : input.url);
|
|
2797
|
+
if (url.origin !== endpoint.origin || url.pathname !== endpoint.pathname) {
|
|
2798
|
+
throw new TypeError("SAP Responses requests must target the configured deployment.");
|
|
2799
|
+
}
|
|
2800
|
+
if (init?.method !== "POST" || typeof init.body !== "string") {
|
|
2801
|
+
throw new TypeError("SAP Responses requires a POST request with a JSON body.");
|
|
2802
|
+
}
|
|
2803
|
+
const body = JSON.parse(init.body);
|
|
2804
|
+
const operation = typeof body === "object" && body !== null && "stream" in body && body.stream === true ? "doStream" : "doGenerate";
|
|
2805
|
+
const controller = new AbortController();
|
|
2806
|
+
const signal = options.abortSignal ?? init.signal;
|
|
2807
|
+
const bodyTimeoutCleanups = /* @__PURE__ */ new Set();
|
|
2808
|
+
let abortFailedRequest;
|
|
2809
|
+
let activeResponse;
|
|
2810
|
+
const onAbort = () => {
|
|
2811
|
+
controller.abort(signal?.reason);
|
|
2812
|
+
};
|
|
2813
|
+
const cleanup = () => {
|
|
2814
|
+
activeRequests.delete(disposeRequest);
|
|
2815
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2816
|
+
if (abortFailedRequest) controller.signal.removeEventListener("abort", abortFailedRequest);
|
|
2817
|
+
for (const dispose2 of bodyTimeoutCleanups) dispose2();
|
|
2818
|
+
activeResponse = void 0;
|
|
2819
|
+
};
|
|
2820
|
+
const disposeRequest = (reason) => {
|
|
2821
|
+
try {
|
|
2822
|
+
controller.abort(reason);
|
|
2823
|
+
} finally {
|
|
2824
|
+
try {
|
|
2825
|
+
if (activeResponse) destroyHttpResponse(activeResponse);
|
|
2826
|
+
} finally {
|
|
2827
|
+
cleanup();
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
};
|
|
2831
|
+
throwIfAborted(signal ?? void 0);
|
|
2832
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2833
|
+
activeRequests.add(disposeRequest);
|
|
2834
|
+
const headers = new Headers(init.headers);
|
|
2835
|
+
headers.delete("authorization");
|
|
2836
|
+
const configuredHeaders = Object.fromEntries(
|
|
2837
|
+
Object.entries(requestConfig?.headers ?? {}).map(([key, value]) => [
|
|
2838
|
+
key.toLowerCase(),
|
|
2839
|
+
value
|
|
2840
|
+
])
|
|
2841
|
+
);
|
|
2842
|
+
let failedRequest;
|
|
2843
|
+
let failedError;
|
|
2844
|
+
const watchResponse = (response, request) => {
|
|
2845
|
+
activeResponse = response;
|
|
2846
|
+
if (controller.signal.aborted) destroyHttpResponse(response);
|
|
2847
|
+
else preserveResponseBodyTimeout(response, request, bodyTimeoutCleanups);
|
|
2848
|
+
return response;
|
|
2849
|
+
};
|
|
2850
|
+
const preserveBodyTimeout = ({ fn }) => async (request) => {
|
|
2851
|
+
try {
|
|
2852
|
+
return watchResponse(await fn(request), request);
|
|
2853
|
+
} catch (error) {
|
|
2854
|
+
const failed = findFailedHttpRequest(error);
|
|
2855
|
+
if (failed) watchResponse(failed.response, request);
|
|
2856
|
+
throw error;
|
|
2857
|
+
}
|
|
2858
|
+
};
|
|
2859
|
+
const preserveErrorResponse = ({ fn }) => async (request) => {
|
|
2860
|
+
try {
|
|
2861
|
+
return await fn(request);
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
const failed = findFailedHttpRequest(error);
|
|
2864
|
+
if (!failed) throw error;
|
|
2865
|
+
failedRequest = failed;
|
|
2866
|
+
failedError = error;
|
|
2867
|
+
const request2 = failed.response.request;
|
|
2868
|
+
if (isDestroyableRequest(request2)) {
|
|
2869
|
+
abortFailedRequest = () => {
|
|
2870
|
+
request2.destroy();
|
|
2871
|
+
};
|
|
2872
|
+
if (controller.signal.aborted) abortFailedRequest();
|
|
2873
|
+
else controller.signal.addEventListener("abort", abortFailedRequest, { once: true });
|
|
2874
|
+
}
|
|
2875
|
+
return failed.response;
|
|
2876
|
+
}
|
|
2877
|
+
};
|
|
2878
|
+
try {
|
|
2879
|
+
const pendingResponse = (0, import_core.executeRequest)(
|
|
2880
|
+
{
|
|
2881
|
+
apiVersion: "2024-10-21",
|
|
2882
|
+
resourceGroup: (0, import_internal.getResourceGroup)(deployment),
|
|
2883
|
+
url: `${deploymentPath}/responses`
|
|
2884
|
+
},
|
|
2885
|
+
body,
|
|
2886
|
+
{
|
|
2887
|
+
...requestConfig,
|
|
2888
|
+
headers: { ...Object.fromEntries(headers), ...configuredHeaders },
|
|
2889
|
+
middleware: [
|
|
2890
|
+
preserveErrorResponse,
|
|
2891
|
+
...requestConfig?.middleware ?? [],
|
|
2892
|
+
preserveBodyTimeout
|
|
2893
|
+
],
|
|
2894
|
+
responseType: "stream",
|
|
2895
|
+
signal: controller.signal
|
|
2896
|
+
},
|
|
2897
|
+
config.destination
|
|
2898
|
+
);
|
|
2899
|
+
const response = await waitWithAbort(pendingResponse, controller.signal, destroyHttpResponse);
|
|
2900
|
+
activeResponse = response;
|
|
2901
|
+
if (controller.signal.aborted) {
|
|
2902
|
+
destroyHttpResponse(response);
|
|
2903
|
+
throw createAbortError(controller.signal.reason);
|
|
2904
|
+
}
|
|
2905
|
+
const responseBody = response.data;
|
|
2906
|
+
const responseStream = createByteStream(
|
|
2907
|
+
responseBody,
|
|
2908
|
+
controller,
|
|
2909
|
+
cleanup,
|
|
2910
|
+
config,
|
|
2911
|
+
options,
|
|
2912
|
+
operation
|
|
2913
|
+
);
|
|
2914
|
+
if (failedRequest) {
|
|
2915
|
+
const readFailure = await readHttpErrorBody(
|
|
2916
|
+
failedRequest.response,
|
|
2917
|
+
responseStream,
|
|
2918
|
+
signal ?? void 0
|
|
2919
|
+
);
|
|
2920
|
+
const failure = convertToAISDKError(failedError, {
|
|
2921
|
+
modelId: config.modelId,
|
|
2922
|
+
modelType: "languageModel",
|
|
2923
|
+
operation,
|
|
2924
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
2925
|
+
url: "sap-ai:responses"
|
|
2926
|
+
});
|
|
2927
|
+
if (readFailure !== void 0 && import_provider8.APICallError.isInstance(failure)) {
|
|
2928
|
+
Object.defineProperty(failure, ERROR_BODY_READ_FAILURE, { value: readFailure });
|
|
2929
|
+
}
|
|
2930
|
+
throw failure;
|
|
2931
|
+
}
|
|
2932
|
+
return new Response(responseStream, {
|
|
2933
|
+
headers: normalizeHeaders(response.headers),
|
|
2934
|
+
status: response.status
|
|
2935
|
+
});
|
|
2936
|
+
} catch (error) {
|
|
2937
|
+
dispose(error);
|
|
2938
|
+
throw error;
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
return { baseURL, dispose, fetch };
|
|
2942
|
+
}
|
|
2943
|
+
function createByteStream(body, requestController, cleanup, config, options, operation) {
|
|
2944
|
+
if (typeof body !== "object" || body === null || !(Symbol.asyncIterator in body) || typeof body[Symbol.asyncIterator] !== "function") {
|
|
2945
|
+
requestController.abort();
|
|
2946
|
+
cleanup();
|
|
2947
|
+
throw new TypeError("SAP Responses did not return a readable response body.");
|
|
2948
|
+
}
|
|
2949
|
+
const source = body;
|
|
2950
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
2951
|
+
const encoder = new TextEncoder();
|
|
2952
|
+
const onAbort = () => source.destroy?.();
|
|
2953
|
+
const cleanupStream = () => {
|
|
2954
|
+
requestController.signal.removeEventListener("abort", onAbort);
|
|
2955
|
+
cleanup();
|
|
2956
|
+
};
|
|
2957
|
+
requestController.signal.addEventListener("abort", onAbort, { once: true });
|
|
2958
|
+
if (requestController.signal.aborted) onAbort();
|
|
2959
|
+
return new ReadableStream(
|
|
2960
|
+
{
|
|
2961
|
+
async cancel(reason) {
|
|
2962
|
+
requestController.abort(reason);
|
|
2963
|
+
cleanupStream();
|
|
2964
|
+
if (source.destroy) {
|
|
2965
|
+
source.destroy();
|
|
2966
|
+
} else {
|
|
2967
|
+
await iterator.return?.();
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
async pull(controller) {
|
|
2971
|
+
try {
|
|
2972
|
+
throwIfAborted(requestController.signal);
|
|
2973
|
+
const chunk = await iterator.next();
|
|
2974
|
+
throwIfAborted(requestController.signal);
|
|
2975
|
+
if (chunk.done) {
|
|
2976
|
+
cleanupStream();
|
|
2977
|
+
controller.close();
|
|
2978
|
+
} else if (typeof chunk.value === "string") {
|
|
2979
|
+
controller.enqueue(encoder.encode(chunk.value));
|
|
2980
|
+
} else if (chunk.value instanceof Uint8Array) {
|
|
2981
|
+
controller.enqueue(chunk.value);
|
|
2982
|
+
} else {
|
|
2983
|
+
throw new TypeError("SAP Responses returned a non-byte response chunk.");
|
|
2984
|
+
}
|
|
2985
|
+
} catch (error) {
|
|
2986
|
+
const failure = requestController.signal.aborted ? createAbortError(requestController.signal.reason) : error;
|
|
2987
|
+
requestController.abort(error);
|
|
2988
|
+
cleanupStream();
|
|
2989
|
+
source.destroy?.();
|
|
2990
|
+
controller.error(
|
|
2991
|
+
convertToAISDKError(failure, {
|
|
2992
|
+
modelId: config.modelId,
|
|
2993
|
+
modelType: "languageModel",
|
|
2994
|
+
operation,
|
|
2995
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
2996
|
+
url: "sap-ai:responses"
|
|
2997
|
+
})
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
},
|
|
3002
|
+
{ highWaterMark: 0 }
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
var import_provider8, import_internal, import_core, import_internal2;
|
|
3006
|
+
var init_responses_http_transport = __esm({
|
|
3007
|
+
"src/responses-http-transport.ts"() {
|
|
1975
3008
|
"use strict";
|
|
1976
|
-
|
|
3009
|
+
import_provider8 = require("@ai-sdk/provider");
|
|
3010
|
+
import_internal = require("@sap-ai-sdk/ai-api/internal.js");
|
|
3011
|
+
import_core = require("@sap-ai-sdk/core");
|
|
3012
|
+
import_internal2 = require("@sap-ai-sdk/core/internal.js");
|
|
3013
|
+
init_abort_utils();
|
|
1977
3014
|
init_sap_ai_error();
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
"filtering",
|
|
1981
|
-
"grounding",
|
|
1982
|
-
"masking",
|
|
1983
|
-
"orchestrationConfigRef",
|
|
1984
|
-
"placeholderValues",
|
|
1985
|
-
"promptTemplateRef",
|
|
1986
|
-
"streamOptions",
|
|
1987
|
-
"tools",
|
|
1988
|
-
"translation"
|
|
1989
|
-
];
|
|
1990
|
-
ORCHESTRATION_ONLY_FEATURES = {
|
|
1991
|
-
fallbackModuleConfigs: "Fallback module configurations (fallbackModuleConfigs)",
|
|
1992
|
-
filtering: "Content filtering",
|
|
1993
|
-
grounding: "Document grounding",
|
|
1994
|
-
masking: "Data masking",
|
|
1995
|
-
orchestrationConfigRef: "Orchestration config reference (orchestrationConfigRef)",
|
|
1996
|
-
placeholderValues: "Placeholder values (placeholderValues)",
|
|
1997
|
-
promptTemplateRef: "Prompt template reference (promptTemplateRef)",
|
|
1998
|
-
streamOptions: "Stream options for post-LLM modules",
|
|
1999
|
-
tools: "SAP-format tool definitions (use AI SDK tools instead)",
|
|
2000
|
-
translation: "Translation"
|
|
2001
|
-
};
|
|
2002
|
-
FOUNDATION_MODELS_ONLY_FEATURE_KEYS = ["dataSources"];
|
|
2003
|
-
FOUNDATION_MODELS_ONLY_FEATURES = {
|
|
2004
|
-
dataSources: "Azure On Your Data (dataSources)"
|
|
2005
|
-
};
|
|
2006
|
-
ORCHESTRATION_ONLY_INVOCATION_FEATURE_KEYS = [
|
|
2007
|
-
"orchestrationConfigRef",
|
|
2008
|
-
"placeholderValues",
|
|
2009
|
-
"promptTemplateRef"
|
|
2010
|
-
];
|
|
2011
|
-
ORCHESTRATION_ONLY_EMBEDDING_FEATURE_KEYS = ["masking"];
|
|
2012
|
-
ORCHESTRATION_ONLY_EMBEDDING_FEATURES = {
|
|
2013
|
-
masking: ORCHESTRATION_ONLY_FEATURES.masking
|
|
2014
|
-
};
|
|
2015
|
-
ESCAPE_TEMPLATE_PLACEHOLDERS_DESCRIPTION = "escapeTemplatePlaceholders (Jinja2 template escaping)";
|
|
2016
|
-
VALID_API_TYPES = ["orchestration", "foundation-models"];
|
|
3015
|
+
init_sap_http_stream();
|
|
3016
|
+
init_strategy_utils();
|
|
2017
3017
|
}
|
|
2018
3018
|
});
|
|
2019
3019
|
|
|
2020
|
-
// src/
|
|
2021
|
-
var
|
|
2022
|
-
__export(
|
|
2023
|
-
|
|
3020
|
+
// src/responses-language-model-strategy.ts
|
|
3021
|
+
var responses_language_model_strategy_exports = {};
|
|
3022
|
+
__export(responses_language_model_strategy_exports, {
|
|
3023
|
+
ResponsesLanguageModelStrategy: () => ResponsesLanguageModelStrategy
|
|
2024
3024
|
});
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
3025
|
+
function convertError(error, config, options, operation) {
|
|
3026
|
+
if (import_provider9.APICallError.isInstance(error) && error.message === "Failed to process successful response" && error.statusCode !== void 0 && error.statusCode >= 200 && error.statusCode < 300 && import_provider9.APICallError.isInstance(error.cause)) {
|
|
3027
|
+
return error.cause;
|
|
3028
|
+
}
|
|
3029
|
+
if (operation === "doStream" && !import_provider9.APICallError.isInstance(error)) {
|
|
3030
|
+
const parsed = OPENAI_STREAM_ERROR_SCHEMA.safeParse(error);
|
|
3031
|
+
if (parsed.success) {
|
|
3032
|
+
return new import_provider9.APICallError({
|
|
3033
|
+
cause: error,
|
|
3034
|
+
data: parsed.data.data,
|
|
3035
|
+
isRetryable: parsed.data.isRetryable,
|
|
3036
|
+
message: parsed.data.message,
|
|
3037
|
+
requestBodyValues: createAISDKRequestBodySummary(options),
|
|
3038
|
+
statusCode: parsed.data.statusCode,
|
|
3039
|
+
url: "sap-ai:responses"
|
|
3040
|
+
});
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
return convertToAISDKError(error, {
|
|
3044
|
+
modelId: config.modelId,
|
|
3045
|
+
modelType: "languageModel",
|
|
3046
|
+
operation,
|
|
3047
|
+
requestBody: createAISDKRequestBodySummary(options),
|
|
3048
|
+
url: "sap-ai:responses"
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
function fromOpenAI(metadata, providerName) {
|
|
3052
|
+
if (providerName === "openai" || !metadata?.openai) return metadata;
|
|
3053
|
+
const { openai, ...rest } = metadata;
|
|
3054
|
+
return { ...rest, [providerName]: { ...rest[providerName], ...openai } };
|
|
3055
|
+
}
|
|
3056
|
+
function fromOpenAICitations(citations, providerName) {
|
|
3057
|
+
if (providerName === "openai" || !citations) return citations;
|
|
3058
|
+
let mapped;
|
|
3059
|
+
let index = 0;
|
|
3060
|
+
for (const citation of citations) {
|
|
3061
|
+
const providerMetadata = fromOpenAI(citation.source.providerMetadata, providerName);
|
|
3062
|
+
if (providerMetadata !== citation.source.providerMetadata) {
|
|
3063
|
+
mapped ??= citations.slice();
|
|
3064
|
+
mapped[index] = {
|
|
3065
|
+
...citation,
|
|
3066
|
+
source: { ...citation.source, providerMetadata }
|
|
3067
|
+
};
|
|
3068
|
+
}
|
|
3069
|
+
index++;
|
|
3070
|
+
}
|
|
3071
|
+
return mapped ?? citations;
|
|
3072
|
+
}
|
|
3073
|
+
function fromOpenAIContent(part, providerName) {
|
|
3074
|
+
const providerMetadata = fromOpenAI(part.providerMetadata, providerName);
|
|
3075
|
+
const citations = fromOpenAICitations(part.citations, providerName);
|
|
3076
|
+
if (providerMetadata === part.providerMetadata && citations === part.citations) return part;
|
|
3077
|
+
if (providerMetadata === part.providerMetadata) return { ...part, citations };
|
|
3078
|
+
return citations === part.citations ? { ...part, providerMetadata } : { ...part, citations, providerMetadata };
|
|
3079
|
+
}
|
|
3080
|
+
function modelResponseFormat(settings) {
|
|
3081
|
+
const format = settings.responseFormat;
|
|
3082
|
+
if (!format || format.type === "text") return format;
|
|
3083
|
+
if (format.type === "json_object") return { type: "json" };
|
|
3084
|
+
const schema = format.json_schema;
|
|
3085
|
+
return {
|
|
3086
|
+
description: schema.description,
|
|
3087
|
+
name: schema.name,
|
|
3088
|
+
schema: schema.schema === void 0 ? void 0 : import_zod3.z.record(import_zod3.z.string(), import_zod3.z.json()).parse(schema.schema),
|
|
3089
|
+
type: "json"
|
|
3090
|
+
};
|
|
3091
|
+
}
|
|
3092
|
+
async function prepareModel(config, settings, options) {
|
|
3093
|
+
if (options.abortSignal?.aborted) {
|
|
3094
|
+
throw createAbortError(options.abortSignal.reason);
|
|
3095
|
+
}
|
|
3096
|
+
const providerName = getProviderName(config.provider);
|
|
3097
|
+
const sapOptions = config.parsedProviderOptions;
|
|
3098
|
+
const parameters = { ...settings.modelParams, ...sapOptions?.modelParams };
|
|
3099
|
+
const warnings = Object.keys(parameters).filter((key) => !MODEL_PARAMETERS.has(key)).map((key) => ({
|
|
3100
|
+
details: "Use the responses option for Responses-specific parameters.",
|
|
3101
|
+
feature: `modelParams.${key}`,
|
|
3102
|
+
type: "unsupported"
|
|
3103
|
+
}));
|
|
3104
|
+
if (sapOptions?.includeReasoning ?? settings.includeReasoning) {
|
|
3105
|
+
warnings.push({
|
|
3106
|
+
details: "Responses preserves native reasoning history instead of converting it to text.",
|
|
3107
|
+
feature: "includeReasoning",
|
|
3108
|
+
type: "unsupported"
|
|
3109
|
+
});
|
|
3110
|
+
}
|
|
3111
|
+
const responseOptions = {
|
|
3112
|
+
...parameters.parallel_tool_calls !== void 0 ? { parallelToolCalls: parameters.parallel_tool_calls } : {},
|
|
3113
|
+
...settings.responseFormat?.type === "json_schema" ? { strictJsonSchema: settings.responseFormat.json_schema.strict } : {},
|
|
3114
|
+
store: false,
|
|
3115
|
+
...settings.responses,
|
|
3116
|
+
...sapOptions?.responses
|
|
3117
|
+
};
|
|
3118
|
+
const reasoning = "reasoning" in options ? options.reasoning : void 0;
|
|
3119
|
+
if (typeof reasoning === "string" && reasoning !== "provider-default") {
|
|
3120
|
+
responseOptions.reasoningEffort = reasoning;
|
|
3121
|
+
}
|
|
3122
|
+
const input = {
|
|
3123
|
+
...options,
|
|
3124
|
+
frequencyPenalty: options.frequencyPenalty ?? parameters.frequencyPenalty,
|
|
3125
|
+
maxOutputTokens: options.maxOutputTokens ?? parameters.maxTokens,
|
|
3126
|
+
presencePenalty: options.presencePenalty ?? parameters.presencePenalty,
|
|
3127
|
+
prompt: toOpenAIPrompt(options.prompt, providerName),
|
|
3128
|
+
providerOptions: {
|
|
3129
|
+
...options.providerOptions,
|
|
3130
|
+
openai: responseOptions
|
|
3131
|
+
},
|
|
3132
|
+
responseFormat: options.responseFormat ?? modelResponseFormat(settings),
|
|
3133
|
+
temperature: options.temperature ?? parameters.temperature,
|
|
3134
|
+
tools: options.tools?.map(
|
|
3135
|
+
(tool) => tool.type === "function" ? {
|
|
3136
|
+
...tool,
|
|
3137
|
+
providerOptions: toOpenAI(tool.providerOptions, providerName),
|
|
3138
|
+
strict: tool.strict ?? false
|
|
3139
|
+
} : tool
|
|
3140
|
+
),
|
|
3141
|
+
topP: options.topP ?? parameters.topP
|
|
3142
|
+
};
|
|
3143
|
+
const convertedInput = convertResponsesCallToV4(input);
|
|
3144
|
+
const transport = await createResponsesTransport(config, settings, options);
|
|
3145
|
+
const model = (0, import_openai.createOpenAI)({
|
|
3146
|
+
// Authentication is supplied by SAP's transport, not an OpenAI API key.
|
|
3147
|
+
apiKey: "sap-ai-core",
|
|
3148
|
+
baseURL: transport.baseURL,
|
|
3149
|
+
fetch: transport.fetch
|
|
3150
|
+
}).responses(config.modelId);
|
|
3151
|
+
return { dispose: transport.dispose, input: convertedInput, model, providerName, warnings };
|
|
3152
|
+
}
|
|
3153
|
+
function responseMetadata(metadata, providerName) {
|
|
3154
|
+
const mapped = fromOpenAI(metadata, providerName);
|
|
3155
|
+
return {
|
|
3156
|
+
...mapped,
|
|
3157
|
+
[providerName]: { ...mapped?.[providerName], api: "responses", version: VERSION }
|
|
3158
|
+
};
|
|
3159
|
+
}
|
|
3160
|
+
function toOpenAI(options, providerName) {
|
|
3161
|
+
if (providerName === "openai" || !options?.[providerName]) return options;
|
|
3162
|
+
return { ...options, openai: { ...options.openai, ...options[providerName] } };
|
|
3163
|
+
}
|
|
3164
|
+
function toOpenAIOutput(output, providerName) {
|
|
3165
|
+
const mappedOutput = {
|
|
3166
|
+
...output,
|
|
3167
|
+
providerOptions: toOpenAI(output.providerOptions, providerName)
|
|
3168
|
+
};
|
|
3169
|
+
if (mappedOutput.type !== "content") return mappedOutput;
|
|
3170
|
+
return {
|
|
3171
|
+
...mappedOutput,
|
|
3172
|
+
value: mappedOutput.value.map((part) => ({
|
|
3173
|
+
...part,
|
|
3174
|
+
...(part.type === "file-id" || part.type === "image-file-id") && typeof part.fileId !== "string" && part.fileId[providerName] ? { fileId: { ...part.fileId, openai: part.fileId[providerName] } } : {},
|
|
3175
|
+
..."providerOptions" in part ? { providerOptions: toOpenAI(part.providerOptions, providerName) } : {}
|
|
3176
|
+
}))
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
function toOpenAIPart(part, providerName) {
|
|
3180
|
+
return {
|
|
3181
|
+
...part,
|
|
3182
|
+
...part.type === "tool-result" ? { output: toOpenAIOutput(part.output, providerName) } : {},
|
|
3183
|
+
providerOptions: toOpenAI(part.providerOptions, providerName)
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
function toOpenAIPrompt(prompt, providerName) {
|
|
3187
|
+
return prompt.map((message) => {
|
|
3188
|
+
const providerOptions = toOpenAI(message.providerOptions, providerName);
|
|
3189
|
+
switch (message.role) {
|
|
3190
|
+
case "assistant":
|
|
3191
|
+
return {
|
|
3192
|
+
...message,
|
|
3193
|
+
content: message.content.map((part) => toOpenAIPart(part, providerName)),
|
|
3194
|
+
providerOptions
|
|
2046
3195
|
};
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
3196
|
+
case "system":
|
|
3197
|
+
return { ...message, providerOptions };
|
|
3198
|
+
case "tool":
|
|
3199
|
+
return {
|
|
3200
|
+
...message,
|
|
3201
|
+
content: message.content.map((part) => toOpenAIPart(part, providerName)),
|
|
3202
|
+
providerOptions
|
|
2050
3203
|
};
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
3204
|
+
case "user":
|
|
3205
|
+
return {
|
|
3206
|
+
...message,
|
|
3207
|
+
content: message.content.map((part) => toOpenAIPart(part, providerName)),
|
|
3208
|
+
providerOptions
|
|
3209
|
+
};
|
|
3210
|
+
}
|
|
3211
|
+
});
|
|
3212
|
+
}
|
|
3213
|
+
var import_openai, import_provider9, import_zod3, MODEL_PARAMETERS, OPENAI_STREAM_ERROR_SCHEMA, ResponsesLanguageModelStrategy;
|
|
3214
|
+
var init_responses_language_model_strategy = __esm({
|
|
3215
|
+
"src/responses-language-model-strategy.ts"() {
|
|
3216
|
+
"use strict";
|
|
3217
|
+
import_openai = require("@ai-sdk/openai");
|
|
3218
|
+
import_provider9 = require("@ai-sdk/provider");
|
|
3219
|
+
import_zod3 = require("zod");
|
|
3220
|
+
init_abort_utils();
|
|
3221
|
+
init_responses_adapters_v3_to_v4();
|
|
3222
|
+
init_responses_adapters_v4_to_v3();
|
|
3223
|
+
init_responses_http_transport();
|
|
3224
|
+
init_sap_ai_error();
|
|
3225
|
+
init_sap_ai_provider_options();
|
|
3226
|
+
init_strategy_utils();
|
|
3227
|
+
init_version();
|
|
3228
|
+
MODEL_PARAMETERS = /* @__PURE__ */ new Set([
|
|
3229
|
+
"frequencyPenalty",
|
|
3230
|
+
"maxTokens",
|
|
3231
|
+
"parallel_tool_calls",
|
|
3232
|
+
"presencePenalty",
|
|
3233
|
+
"temperature",
|
|
3234
|
+
"topP"
|
|
3235
|
+
]);
|
|
3236
|
+
OPENAI_STREAM_ERROR_SCHEMA = import_zod3.z.object({
|
|
3237
|
+
data: import_zod3.z.object({ type: import_zod3.z.enum(["error", "response.failed"]) }).loose(),
|
|
3238
|
+
isRetryable: import_zod3.z.boolean(),
|
|
3239
|
+
message: import_zod3.z.string(),
|
|
3240
|
+
statusCode: import_zod3.z.number().int().min(400).max(599)
|
|
3241
|
+
});
|
|
3242
|
+
ResponsesLanguageModelStrategy = class {
|
|
3243
|
+
async doGenerate(config, settings, options) {
|
|
3244
|
+
let dispose;
|
|
3245
|
+
try {
|
|
3246
|
+
const prepared = await prepareModel(config, settings, options);
|
|
3247
|
+
dispose = prepared.dispose;
|
|
3248
|
+
const { input, model, providerName, warnings } = prepared;
|
|
3249
|
+
const result = convertResponsesResultToV3(await model.doGenerate(input));
|
|
3250
|
+
return {
|
|
3251
|
+
...result,
|
|
3252
|
+
content: result.content.map((part) => fromOpenAIContent(part, providerName)),
|
|
3253
|
+
providerMetadata: responseMetadata(result.providerMetadata, providerName),
|
|
3254
|
+
warnings: [...warnings, ...result.warnings]
|
|
3255
|
+
};
|
|
3256
|
+
} catch (error) {
|
|
3257
|
+
const failure = convertError(error, config, options, "doGenerate");
|
|
3258
|
+
dispose?.(failure);
|
|
3259
|
+
throw failure;
|
|
3260
|
+
}
|
|
2070
3261
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
3262
|
+
async doStream(config, settings, options) {
|
|
3263
|
+
let dispose;
|
|
3264
|
+
try {
|
|
3265
|
+
const prepared = await prepareModel(config, settings, options);
|
|
3266
|
+
dispose = prepared.dispose;
|
|
3267
|
+
const { input, model, providerName, warnings } = prepared;
|
|
3268
|
+
const result = await model.doStream(input);
|
|
3269
|
+
const reader = result.stream.getReader();
|
|
3270
|
+
let cancelled = false;
|
|
3271
|
+
const isCancelled = () => cancelled;
|
|
3272
|
+
return {
|
|
3273
|
+
...result,
|
|
3274
|
+
stream: new ReadableStream(
|
|
3275
|
+
{
|
|
3276
|
+
async cancel(reason) {
|
|
3277
|
+
cancelled = true;
|
|
3278
|
+
dispose?.(reason);
|
|
3279
|
+
try {
|
|
3280
|
+
await reader.cancel(reason);
|
|
3281
|
+
} finally {
|
|
3282
|
+
reader.releaseLock();
|
|
3283
|
+
}
|
|
3284
|
+
},
|
|
3285
|
+
async pull(controller) {
|
|
3286
|
+
try {
|
|
3287
|
+
if (options.abortSignal?.aborted)
|
|
3288
|
+
throw createAbortError(options.abortSignal.reason);
|
|
3289
|
+
const next = await reader.read();
|
|
3290
|
+
if (isCancelled()) return;
|
|
3291
|
+
if (options.abortSignal?.aborted)
|
|
3292
|
+
throw createAbortError(options.abortSignal.reason);
|
|
3293
|
+
if (next.done) {
|
|
3294
|
+
reader.releaseLock();
|
|
3295
|
+
controller.close();
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
const part = convertResponsesStreamPartToV3(next.value);
|
|
3299
|
+
if (part.type === "stream-start") {
|
|
3300
|
+
controller.enqueue({ ...part, warnings: [...warnings, ...part.warnings] });
|
|
3301
|
+
} else if (part.type === "finish") {
|
|
3302
|
+
controller.enqueue({
|
|
3303
|
+
...part,
|
|
3304
|
+
providerMetadata: responseMetadata(part.providerMetadata, providerName)
|
|
3305
|
+
});
|
|
3306
|
+
} else if (part.type === "error") {
|
|
3307
|
+
controller.enqueue({
|
|
3308
|
+
...part,
|
|
3309
|
+
error: convertError(part.error, config, options, "doStream")
|
|
3310
|
+
});
|
|
3311
|
+
} else if ("providerMetadata" in part || part.type === "text-end") {
|
|
3312
|
+
controller.enqueue(fromOpenAIContent(part, providerName));
|
|
3313
|
+
} else {
|
|
3314
|
+
controller.enqueue(part);
|
|
3315
|
+
}
|
|
3316
|
+
} catch (error) {
|
|
3317
|
+
if (isCancelled()) return;
|
|
3318
|
+
const failure = convertError(error, config, options, "doStream");
|
|
3319
|
+
dispose?.(failure);
|
|
3320
|
+
await reader.cancel(error).catch(() => void 0);
|
|
3321
|
+
if (isCancelled()) return;
|
|
3322
|
+
reader.releaseLock();
|
|
3323
|
+
controller.enqueue({
|
|
3324
|
+
error: failure,
|
|
3325
|
+
type: "error"
|
|
3326
|
+
});
|
|
3327
|
+
controller.close();
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
},
|
|
3331
|
+
{ highWaterMark: 0 }
|
|
3332
|
+
)
|
|
3333
|
+
};
|
|
3334
|
+
} catch (error) {
|
|
3335
|
+
const failure = convertError(error, config, options, "doStream");
|
|
3336
|
+
dispose?.(failure);
|
|
3337
|
+
throw failure;
|
|
3338
|
+
}
|
|
2073
3339
|
}
|
|
2074
3340
|
};
|
|
2075
3341
|
}
|
|
2076
3342
|
});
|
|
2077
3343
|
|
|
2078
3344
|
// src/stream-transformer.ts
|
|
2079
|
-
function createAbortError(reason) {
|
|
2080
|
-
const error = new Error("The operation was aborted.", { cause: reason });
|
|
2081
|
-
error.name = "AbortError";
|
|
2082
|
-
return error;
|
|
2083
|
-
}
|
|
2084
3345
|
function createInitialStreamState() {
|
|
2085
3346
|
return {
|
|
2086
3347
|
activeText: false,
|
|
@@ -2109,13 +3370,15 @@ function createStreamTransformer(config) {
|
|
|
2109
3370
|
cancel,
|
|
2110
3371
|
convertToAISDKError: convertToAISDKError2,
|
|
2111
3372
|
extractChunkMetadata,
|
|
3373
|
+
extractProviderSpecificFields,
|
|
3374
|
+
extractReasoningBlocks,
|
|
2112
3375
|
idGenerator,
|
|
2113
3376
|
includeRawChunks,
|
|
2114
3377
|
modelId,
|
|
2115
3378
|
options,
|
|
2116
3379
|
providerName,
|
|
2117
3380
|
requestId,
|
|
2118
|
-
responseMetadata,
|
|
3381
|
+
responseMetadata: responseMetadata2,
|
|
2119
3382
|
sdkStream,
|
|
2120
3383
|
streamResponseGetCitations,
|
|
2121
3384
|
streamResponseGetFinishReason,
|
|
@@ -2127,10 +3390,51 @@ function createStreamTransformer(config) {
|
|
|
2127
3390
|
let textBlockId = null;
|
|
2128
3391
|
const streamState = createInitialStreamState();
|
|
2129
3392
|
const toolCallsInProgress = /* @__PURE__ */ new Map();
|
|
2130
|
-
const resolvedResponseMetadata = { ...
|
|
3393
|
+
const resolvedResponseMetadata = { ...responseMetadata2 };
|
|
2131
3394
|
let resolvedRequestId = requestId;
|
|
2132
3395
|
let tokenUsage;
|
|
2133
3396
|
let citations;
|
|
3397
|
+
let providerSpecificFields;
|
|
3398
|
+
let providerFinishReason;
|
|
3399
|
+
let reasoningBlocks;
|
|
3400
|
+
function collectReasoningBlocks(incoming, controller) {
|
|
3401
|
+
if (incoming === void 0) return true;
|
|
3402
|
+
if (!Array.isArray(incoming)) {
|
|
3403
|
+
handleStreamError(
|
|
3404
|
+
new TypeError("Invalid Orchestration reasoning_content: expected an array."),
|
|
3405
|
+
controller,
|
|
3406
|
+
convertToAISDKError2,
|
|
3407
|
+
options,
|
|
3408
|
+
modelId,
|
|
3409
|
+
url
|
|
3410
|
+
);
|
|
3411
|
+
return false;
|
|
3412
|
+
}
|
|
3413
|
+
const blocks = incoming;
|
|
3414
|
+
if (blocks.length === 0) return true;
|
|
3415
|
+
reasoningBlocks ??= [];
|
|
3416
|
+
for (const [index, value] of blocks.entries()) {
|
|
3417
|
+
const parsed = orchestrationReasoningBlockSchema.safeParse(value);
|
|
3418
|
+
if (!parsed.success) {
|
|
3419
|
+
handleStreamError(parsed.error, controller, convertToAISDKError2, options, modelId, url);
|
|
3420
|
+
return false;
|
|
3421
|
+
}
|
|
3422
|
+
const block = parsed.data;
|
|
3423
|
+
let state = reasoningBlocks[index];
|
|
3424
|
+
if (state) {
|
|
3425
|
+
state.block.content = (state.block.content ?? "") + (block.content ?? "");
|
|
3426
|
+
if (block.signature) state.block.signature = block.signature;
|
|
3427
|
+
} else {
|
|
3428
|
+
state = { block, id: idGenerator.generateReasoningBlockId() };
|
|
3429
|
+
reasoningBlocks.push(state);
|
|
3430
|
+
controller.enqueue({ id: state.id, type: "reasoning-start" });
|
|
3431
|
+
}
|
|
3432
|
+
if (block.content) {
|
|
3433
|
+
controller.enqueue({ delta: block.content, id: state.id, type: "reasoning-delta" });
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
return true;
|
|
3437
|
+
}
|
|
2134
3438
|
function collectCitations(incoming) {
|
|
2135
3439
|
if (!incoming?.length) return;
|
|
2136
3440
|
citations ??= /* @__PURE__ */ new Map();
|
|
@@ -2207,6 +3511,13 @@ function createStreamTransformer(config) {
|
|
|
2207
3511
|
);
|
|
2208
3512
|
return;
|
|
2209
3513
|
}
|
|
3514
|
+
for (const state of reasoningBlocks ?? []) {
|
|
3515
|
+
controller.enqueue({
|
|
3516
|
+
id: state.id,
|
|
3517
|
+
providerMetadata: buildOrchestrationReasoningMetadata(state.block, providerName),
|
|
3518
|
+
type: "reasoning-end"
|
|
3519
|
+
});
|
|
3520
|
+
}
|
|
2210
3521
|
const didEmitAnyToolCalls = finalizeToolCalls(
|
|
2211
3522
|
controller,
|
|
2212
3523
|
toolCallsInProgress,
|
|
@@ -2218,13 +3529,16 @@ function createStreamTransformer(config) {
|
|
|
2218
3529
|
}
|
|
2219
3530
|
const finalFinishReason = streamResponseGetFinishReason();
|
|
2220
3531
|
if (finalFinishReason) {
|
|
2221
|
-
streamState.finishReason = mapFinishReason(finalFinishReason);
|
|
3532
|
+
streamState.finishReason = mapFinishReason(finalFinishReason, providerFinishReason);
|
|
2222
3533
|
} else if (didEmitAnyToolCalls) {
|
|
2223
3534
|
streamState.finishReason = {
|
|
2224
|
-
raw:
|
|
3535
|
+
raw: providerFinishReason,
|
|
2225
3536
|
unified: "tool-calls"
|
|
2226
3537
|
};
|
|
2227
3538
|
}
|
|
3539
|
+
if (providerFinishReason !== void 0) {
|
|
3540
|
+
streamState.finishReason = { ...streamState.finishReason, raw: providerFinishReason };
|
|
3541
|
+
}
|
|
2228
3542
|
streamState.usage = mapTokenUsage(tokenUsage);
|
|
2229
3543
|
collectCitations(streamResponseGetCitations?.());
|
|
2230
3544
|
if (citations) {
|
|
@@ -2246,6 +3560,7 @@ function createStreamTransformer(config) {
|
|
|
2246
3560
|
...buildAnthropicCacheMetadata(tokenUsage),
|
|
2247
3561
|
finishReason: streamState.finishReason.raw ?? "unknown",
|
|
2248
3562
|
finishReasonMapped: streamState.finishReason,
|
|
3563
|
+
...providerSpecificFields && { providerSpecificFields },
|
|
2249
3564
|
...streamIntermediateFailures?.length ? {
|
|
2250
3565
|
intermediateFailures: sanitizeAsJSONArray(streamIntermediateFailures)
|
|
2251
3566
|
} : {},
|
|
@@ -2285,6 +3600,14 @@ function createStreamTransformer(config) {
|
|
|
2285
3600
|
Object.assign(resolvedResponseMetadata, incomingMetadata);
|
|
2286
3601
|
collectUsage(chunk.getTokenUsage?.());
|
|
2287
3602
|
collectCitations(chunk.getCitations?.());
|
|
3603
|
+
const incomingProviderFields = parseProviderSpecificFields(
|
|
3604
|
+
extractProviderSpecificFields?.(chunk)
|
|
3605
|
+
);
|
|
3606
|
+
if (incomingProviderFields) {
|
|
3607
|
+
providerSpecificFields = { ...providerSpecificFields, ...incomingProviderFields };
|
|
3608
|
+
providerFinishReason = getProviderFinishReason(incomingProviderFields) ?? providerFinishReason;
|
|
3609
|
+
}
|
|
3610
|
+
if (!collectReasoningBlocks(extractReasoningBlocks?.(chunk), controller)) return;
|
|
2288
3611
|
if (streamState.isFirstChunk || metadataChanged) {
|
|
2289
3612
|
streamState.isFirstChunk = false;
|
|
2290
3613
|
controller.enqueue({
|
|
@@ -2314,7 +3637,7 @@ function createStreamTransformer(config) {
|
|
|
2314
3637
|
}
|
|
2315
3638
|
const chunkFinishReason = chunk.getFinishReason();
|
|
2316
3639
|
if (chunkFinishReason) {
|
|
2317
|
-
streamState.finishReason = mapFinishReason(chunkFinishReason);
|
|
3640
|
+
streamState.finishReason = mapFinishReason(chunkFinishReason, providerFinishReason);
|
|
2318
3641
|
if (streamState.finishReason.unified === "tool-calls") {
|
|
2319
3642
|
finalizeToolCalls(controller, toolCallsInProgress, idGenerator, emitToolInputStart);
|
|
2320
3643
|
if (streamState.activeText && textBlockId) {
|
|
@@ -2437,8 +3760,16 @@ var StreamIdGenerator;
|
|
|
2437
3760
|
var init_stream_transformer = __esm({
|
|
2438
3761
|
"src/stream-transformer.ts"() {
|
|
2439
3762
|
"use strict";
|
|
3763
|
+
init_abort_utils();
|
|
3764
|
+
init_sap_ai_provider_options();
|
|
2440
3765
|
init_strategy_utils();
|
|
2441
3766
|
StreamIdGenerator = class {
|
|
3767
|
+
/**
|
|
3768
|
+
* @returns A UUID string for identifying a native reasoning block.
|
|
3769
|
+
*/
|
|
3770
|
+
generateReasoningBlockId() {
|
|
3771
|
+
return crypto.randomUUID();
|
|
3772
|
+
}
|
|
2442
3773
|
/**
|
|
2443
3774
|
* @returns A UUID string for identifying the response.
|
|
2444
3775
|
*/
|
|
@@ -2466,6 +3797,7 @@ var BaseLanguageModelStrategy;
|
|
|
2466
3797
|
var init_base_language_model_strategy = __esm({
|
|
2467
3798
|
"src/base-language-model-strategy.ts"() {
|
|
2468
3799
|
"use strict";
|
|
3800
|
+
init_abort_utils();
|
|
2469
3801
|
init_convert_to_sap_messages();
|
|
2470
3802
|
init_sap_ai_error();
|
|
2471
3803
|
init_sap_ai_provider_options();
|
|
@@ -2497,15 +3829,19 @@ var init_base_language_model_strategy = __esm({
|
|
|
2497
3829
|
];
|
|
2498
3830
|
async doGenerate(config, settings, options) {
|
|
2499
3831
|
try {
|
|
2500
|
-
|
|
3832
|
+
throwIfAborted(options.abortSignal);
|
|
2501
3833
|
const commonParts = this.buildCommonParts(config, settings, options);
|
|
2502
3834
|
const { request, warnings } = this.buildRequest(config, settings, options, commonParts);
|
|
2503
3835
|
const client = this.createClient(config, settings, commonParts);
|
|
2504
|
-
const response = await
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
3836
|
+
const response = await waitWithAbort(
|
|
3837
|
+
this.executeApiCall(
|
|
3838
|
+
client,
|
|
3839
|
+
request,
|
|
3840
|
+
mergeRequestConfig(config.requestConfig, options.abortSignal, options.headers)
|
|
3841
|
+
),
|
|
3842
|
+
options.abortSignal
|
|
2508
3843
|
);
|
|
3844
|
+
throwIfAborted(options.abortSignal);
|
|
2509
3845
|
return buildGenerateResult({
|
|
2510
3846
|
providerName: commonParts.providerName,
|
|
2511
3847
|
requestBody: request,
|
|
@@ -2527,7 +3863,7 @@ var init_base_language_model_strategy = __esm({
|
|
|
2527
3863
|
}
|
|
2528
3864
|
async doStream(config, settings, options) {
|
|
2529
3865
|
try {
|
|
2530
|
-
|
|
3866
|
+
throwIfAborted(options.abortSignal);
|
|
2531
3867
|
const commonParts = this.buildCommonParts(config, settings, options);
|
|
2532
3868
|
const { request, warnings } = this.buildRequest(config, settings, options, commonParts);
|
|
2533
3869
|
const client = this.createClient(config, settings, commonParts);
|
|
@@ -2539,12 +3875,21 @@ var init_base_language_model_strategy = __esm({
|
|
|
2539
3875
|
mergeRequestConfig(config.requestConfig, void 0, options.headers),
|
|
2540
3876
|
commonParts
|
|
2541
3877
|
);
|
|
3878
|
+
if (options.abortSignal?.aborted) {
|
|
3879
|
+
try {
|
|
3880
|
+
streamResponse.cancel();
|
|
3881
|
+
} finally {
|
|
3882
|
+
throwIfAborted(options.abortSignal);
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
2542
3885
|
const idGenerator = new StreamIdGenerator();
|
|
2543
3886
|
const streamWarnings = this.collectStreamWarnings(settings, commonParts.sapOptions);
|
|
2544
3887
|
const transformedStream = createStreamTransformer({
|
|
2545
3888
|
cancel: streamResponse.cancel,
|
|
2546
3889
|
convertToAISDKError,
|
|
2547
3890
|
extractChunkMetadata: (chunk) => this.extractMetadata(chunk),
|
|
3891
|
+
extractProviderSpecificFields: streamResponse.extractProviderSpecificFields,
|
|
3892
|
+
extractReasoningBlocks: streamResponse.extractReasoningBlocks,
|
|
2548
3893
|
idGenerator,
|
|
2549
3894
|
includeRawChunks: options.includeRawChunks ?? false,
|
|
2550
3895
|
modelId: config.modelId,
|
|
@@ -2604,6 +3949,7 @@ var init_base_language_model_strategy = __esm({
|
|
|
2604
3949
|
const messages = convertToSAPMessages(options.prompt, {
|
|
2605
3950
|
escapeTemplatePlaceholders: this.getEscapeTemplatePlaceholders(sapOptions, settings),
|
|
2606
3951
|
includeReasoning: this.getIncludeReasoning(sapOptions, settings),
|
|
3952
|
+
nativeReasoningProviderName: this.getNativeReasoningProviderName(providerName),
|
|
2607
3953
|
parsePartProviderOptions: this.getPartProviderOptionsParser(),
|
|
2608
3954
|
warnings
|
|
2609
3955
|
});
|
|
@@ -2643,12 +3989,12 @@ var init_base_language_model_strategy = __esm({
|
|
|
2643
3989
|
* @internal
|
|
2644
3990
|
*/
|
|
2645
3991
|
extractMetadata(response) {
|
|
2646
|
-
const
|
|
3992
|
+
const responseMetadata2 = extractCompletionMetadata(
|
|
2647
3993
|
response,
|
|
2648
3994
|
this.getCompletionDataPath()
|
|
2649
3995
|
);
|
|
2650
3996
|
const { headers, requestId } = extractResponseMetadata(response, "rawResponse");
|
|
2651
|
-
return { requestId, responseHeaders: headers, responseMetadata };
|
|
3997
|
+
return { requestId, responseHeaders: headers, responseMetadata: responseMetadata2 };
|
|
2652
3998
|
}
|
|
2653
3999
|
/**
|
|
2654
4000
|
* Returns whether to escape template placeholders for this API.
|
|
@@ -2668,7 +4014,16 @@ var init_base_language_model_strategy = __esm({
|
|
|
2668
4014
|
* @internal
|
|
2669
4015
|
*/
|
|
2670
4016
|
getIncludeReasoning(sapOptions, settings) {
|
|
2671
|
-
return sapOptions?.includeReasoning ?? settings.includeReasoning ?? false;
|
|
4017
|
+
return sapOptions?.includeReasoning ?? ("includeReasoning" in settings ? settings.includeReasoning : false) ?? false;
|
|
4018
|
+
}
|
|
4019
|
+
/**
|
|
4020
|
+
* Enables native reasoning history only for strategies supporting the Orchestration wire format.
|
|
4021
|
+
* @param _providerName - Configured provider namespace.
|
|
4022
|
+
* @returns The native reasoning namespace, or undefined for legacy text-only history.
|
|
4023
|
+
* @internal
|
|
4024
|
+
*/
|
|
4025
|
+
getNativeReasoningProviderName(_providerName) {
|
|
4026
|
+
return void 0;
|
|
2672
4027
|
}
|
|
2673
4028
|
/**
|
|
2674
4029
|
* Returns a parser for per-message-part `providerOptions['sap-ai']`.
|
|
@@ -2711,6 +4066,7 @@ var init_foundation_models_language_model_strategy = __esm({
|
|
|
2711
4066
|
"src/foundation-models-language-model-strategy.ts"() {
|
|
2712
4067
|
"use strict";
|
|
2713
4068
|
init_base_language_model_strategy();
|
|
4069
|
+
init_sap_http_stream();
|
|
2714
4070
|
init_strategy_utils();
|
|
2715
4071
|
FOUNDATION_MODELS_PARAM_MAPPINGS = [
|
|
2716
4072
|
...BaseLanguageModelStrategy.COMMON_PARAM_MAPPINGS,
|
|
@@ -2756,7 +4112,7 @@ var init_foundation_models_language_model_strategy = __esm({
|
|
|
2756
4112
|
}
|
|
2757
4113
|
async executeApiCall(client, request, requestConfig) {
|
|
2758
4114
|
const response = await client.run(request, requestConfig);
|
|
2759
|
-
const { requestId, responseMetadata } = this.extractMetadata(response);
|
|
4115
|
+
const { requestId, responseMetadata: responseMetadata2 } = this.extractMetadata(response);
|
|
2760
4116
|
return {
|
|
2761
4117
|
getContent: () => response.getContent(),
|
|
2762
4118
|
getFinishReason: () => response.getFinishReason(),
|
|
@@ -2765,21 +4121,28 @@ var init_foundation_models_language_model_strategy = __esm({
|
|
|
2765
4121
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- SAP SDK types headers as any
|
|
2766
4122
|
rawResponse: { headers: response.rawResponse.headers },
|
|
2767
4123
|
requestId,
|
|
2768
|
-
responseMetadata
|
|
4124
|
+
responseMetadata: responseMetadata2
|
|
2769
4125
|
};
|
|
2770
4126
|
}
|
|
2771
4127
|
async executeStreamCall(client, request, abortSignal, _settings, requestConfig, _commonParts) {
|
|
2772
|
-
const streamResponse = await
|
|
2773
|
-
|
|
4128
|
+
const streamResponse = await executeSapStream(
|
|
4129
|
+
(streamRequestConfig) => client.stream(request, abortSignal, streamRequestConfig),
|
|
4130
|
+
abortSignal,
|
|
4131
|
+
requestConfig
|
|
4132
|
+
);
|
|
4133
|
+
const { requestId, responseHeaders, responseMetadata: responseMetadata2 } = this.extractMetadata(streamResponse);
|
|
2774
4134
|
return {
|
|
2775
4135
|
cancel: () => {
|
|
2776
|
-
streamResponse
|
|
4136
|
+
disposeSapStream(streamResponse);
|
|
2777
4137
|
},
|
|
2778
4138
|
getFinishReason: () => streamResponse.getFinishReason(),
|
|
2779
4139
|
requestId,
|
|
2780
4140
|
responseHeaders,
|
|
2781
|
-
responseMetadata,
|
|
2782
|
-
stream:
|
|
4141
|
+
responseMetadata: responseMetadata2,
|
|
4142
|
+
stream: withSapStreamCleanup(
|
|
4143
|
+
streamResponse,
|
|
4144
|
+
streamResponse.stream
|
|
4145
|
+
)
|
|
2783
4146
|
};
|
|
2784
4147
|
}
|
|
2785
4148
|
getCompletionDataPath() {
|
|
@@ -2840,10 +4203,12 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2840
4203
|
init_deep_merge();
|
|
2841
4204
|
init_sap_ai_provider_options();
|
|
2842
4205
|
init_sap_ai_validation();
|
|
4206
|
+
init_sap_http_stream();
|
|
2843
4207
|
init_strategy_utils();
|
|
2844
4208
|
ORCHESTRATION_MODULE_KEYS = ["masking", "filtering", "grounding", "translation"];
|
|
2845
4209
|
CONFIG_REF_IGNORED_MODULES = [
|
|
2846
4210
|
...ORCHESTRATION_MODULE_KEYS,
|
|
4211
|
+
"dropUnsupportedParams",
|
|
2847
4212
|
"fallbackModuleConfigs",
|
|
2848
4213
|
"promptTemplateRef",
|
|
2849
4214
|
"responseFormat",
|
|
@@ -2851,7 +4216,11 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2851
4216
|
"modelParams",
|
|
2852
4217
|
"modelVersion"
|
|
2853
4218
|
];
|
|
2854
|
-
CONFIG_REF_IGNORED_PROVIDER_OPTIONS = [
|
|
4219
|
+
CONFIG_REF_IGNORED_PROVIDER_OPTIONS = [
|
|
4220
|
+
"dropUnsupportedParams",
|
|
4221
|
+
"promptTemplateRef",
|
|
4222
|
+
"modelParams"
|
|
4223
|
+
];
|
|
2855
4224
|
ORCHESTRATION_PARAM_MAPPINGS = [
|
|
2856
4225
|
...BaseLanguageModelStrategy.COMMON_PARAM_MAPPINGS,
|
|
2857
4226
|
{ camelCaseKey: "topK", optionKey: "topK", outputKey: "top_k" }
|
|
@@ -2900,11 +4269,12 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2900
4269
|
return warnings;
|
|
2901
4270
|
}
|
|
2902
4271
|
createClient(config, settings, commonParts) {
|
|
2903
|
-
const { configRef, promptTemplateRef, responseFormat, tools } = commonParts.resolvedState;
|
|
4272
|
+
const { configRef, dropUnsupportedParams, promptTemplateRef, responseFormat, tools } = commonParts.resolvedState;
|
|
2904
4273
|
if (configRef) {
|
|
2905
4274
|
return new this.ClientClass(configRef, config.deploymentConfig, config.destination);
|
|
2906
4275
|
}
|
|
2907
4276
|
const clientConfig = this.buildOrchestrationModuleConfig(config, settings, {
|
|
4277
|
+
dropUnsupportedParams,
|
|
2908
4278
|
modelParams: commonParts.modelParams,
|
|
2909
4279
|
promptTemplateRef,
|
|
2910
4280
|
responseFormat,
|
|
@@ -2922,41 +4292,47 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2922
4292
|
}
|
|
2923
4293
|
async executeApiCall(client, request, requestConfig) {
|
|
2924
4294
|
const response = await client.chatCompletion(request, requestConfig);
|
|
2925
|
-
const { requestId, responseMetadata } = this.extractMetadata(response);
|
|
4295
|
+
const { requestId, responseMetadata: responseMetadata2 } = this.extractMetadata(response);
|
|
2926
4296
|
return {
|
|
2927
4297
|
getCitations: () => response.getCitations(),
|
|
2928
4298
|
getContent: () => response.getContent(),
|
|
2929
4299
|
getFinishReason: () => response.getFinishReason(),
|
|
2930
4300
|
getIntermediateFailures: () => response.getIntermediateFailures(),
|
|
4301
|
+
getProviderSpecificFields: () => response.findChoiceByIndex(0)?.provider_specific_fields,
|
|
4302
|
+
getReasoningBlocks: () => response.getAssistantMessage()?.reasoning_content,
|
|
2931
4303
|
getTokenUsage: () => response.getTokenUsage(),
|
|
2932
4304
|
getToolCalls: () => response.getToolCalls(),
|
|
2933
4305
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- SAP SDK types headers as any
|
|
2934
4306
|
rawResponse: { headers: response.rawResponse.headers },
|
|
2935
4307
|
requestId,
|
|
2936
|
-
responseMetadata
|
|
4308
|
+
responseMetadata: responseMetadata2
|
|
2937
4309
|
};
|
|
2938
4310
|
}
|
|
2939
4311
|
async executeStreamCall(client, request, abortSignal, settings, requestConfig, commonParts) {
|
|
2940
4312
|
const { configRef } = commonParts.resolvedState;
|
|
2941
4313
|
const sdkStreamOptions = configRef ? void 0 : this.buildSdkStreamOptions(settings.streamOptions);
|
|
2942
|
-
const streamResponse = await
|
|
2943
|
-
request,
|
|
4314
|
+
const streamResponse = await executeSapStream(
|
|
4315
|
+
(streamRequestConfig) => client.stream(request, abortSignal, sdkStreamOptions, streamRequestConfig),
|
|
2944
4316
|
abortSignal,
|
|
2945
|
-
sdkStreamOptions,
|
|
2946
4317
|
requestConfig
|
|
2947
4318
|
);
|
|
2948
|
-
const { requestId, responseHeaders, responseMetadata } = this.extractMetadata(streamResponse);
|
|
4319
|
+
const { requestId, responseHeaders, responseMetadata: responseMetadata2 } = this.extractMetadata(streamResponse);
|
|
2949
4320
|
return {
|
|
2950
4321
|
cancel: () => {
|
|
2951
|
-
streamResponse
|
|
4322
|
+
disposeSapStream(streamResponse);
|
|
2952
4323
|
},
|
|
4324
|
+
extractProviderSpecificFields: (chunk) => chunk.findChoiceByIndex(0)?.provider_specific_fields,
|
|
4325
|
+
extractReasoningBlocks: (chunk) => chunk.findChoiceByIndex(0)?.delta.reasoning_content,
|
|
2953
4326
|
getCitations: () => streamResponse.getCitations(),
|
|
2954
4327
|
getFinishReason: () => streamResponse.getFinishReason(),
|
|
2955
4328
|
getIntermediateFailures: () => streamResponse.getIntermediateFailures(),
|
|
2956
4329
|
requestId,
|
|
2957
4330
|
responseHeaders,
|
|
2958
|
-
responseMetadata,
|
|
2959
|
-
stream:
|
|
4331
|
+
responseMetadata: responseMetadata2,
|
|
4332
|
+
stream: withSapStreamCleanup(
|
|
4333
|
+
streamResponse,
|
|
4334
|
+
streamResponse.stream
|
|
4335
|
+
)
|
|
2960
4336
|
};
|
|
2961
4337
|
}
|
|
2962
4338
|
getCompletionDataPath() {
|
|
@@ -2965,6 +4341,9 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2965
4341
|
getEscapeTemplatePlaceholders(sapOptions, settings) {
|
|
2966
4342
|
return sapOptions?.escapeTemplatePlaceholders ?? settings.escapeTemplatePlaceholders ?? true;
|
|
2967
4343
|
}
|
|
4344
|
+
getNativeReasoningProviderName(providerName) {
|
|
4345
|
+
return providerName;
|
|
4346
|
+
}
|
|
2968
4347
|
getParamMappings() {
|
|
2969
4348
|
return ORCHESTRATION_PARAM_MAPPINGS;
|
|
2970
4349
|
}
|
|
@@ -2998,7 +4377,8 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
2998
4377
|
if (converted.warning) warnings.push(converted.warning);
|
|
2999
4378
|
}
|
|
3000
4379
|
const tools = this.resolveTools(settings, options, warnings);
|
|
3001
|
-
|
|
4380
|
+
const dropUnsupportedParams = sapOptions?.dropUnsupportedParams ?? settings.dropUnsupportedParams;
|
|
4381
|
+
return { configRef, dropUnsupportedParams, promptTemplateRef, responseFormat, tools };
|
|
3002
4382
|
}
|
|
3003
4383
|
/**
|
|
3004
4384
|
* Builds request for orchestrationConfigRef mode.
|
|
@@ -3043,6 +4423,7 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
3043
4423
|
* @param config - Strategy configuration.
|
|
3044
4424
|
* @param settings - Model settings.
|
|
3045
4425
|
* @param params - Build parameters.
|
|
4426
|
+
* @param params.dropUnsupportedParams - Optional unsupported-parameter policy for the primary model.
|
|
3046
4427
|
* @param params.modelParams - LLM model parameters.
|
|
3047
4428
|
* @param params.promptTemplateRef - Optional prompt template reference.
|
|
3048
4429
|
* @param params.responseFormat - Optional response format specification.
|
|
@@ -3052,7 +4433,14 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
3052
4433
|
* @internal
|
|
3053
4434
|
*/
|
|
3054
4435
|
buildOrchestrationModuleConfig(config, settings, params) {
|
|
3055
|
-
const {
|
|
4436
|
+
const {
|
|
4437
|
+
dropUnsupportedParams,
|
|
4438
|
+
modelParams,
|
|
4439
|
+
promptTemplateRef,
|
|
4440
|
+
responseFormat,
|
|
4441
|
+
toolChoice,
|
|
4442
|
+
tools
|
|
4443
|
+
} = params;
|
|
3056
4444
|
const promptConfig = promptTemplateRef ? this.buildTemplateRefPromptConfig(promptTemplateRef, tools, responseFormat) : this.buildInlineTemplateConfig(tools, responseFormat);
|
|
3057
4445
|
const effectiveModelParams = toolChoice ? { ...modelParams, tool_choice: toolChoice } : modelParams;
|
|
3058
4446
|
const moduleConfig = {
|
|
@@ -3060,7 +4448,8 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
3060
4448
|
model: {
|
|
3061
4449
|
name: config.modelId,
|
|
3062
4450
|
params: effectiveModelParams,
|
|
3063
|
-
...settings.modelVersion ? { version: settings.modelVersion } : {}
|
|
4451
|
+
...settings.modelVersion ? { version: settings.modelVersion } : {},
|
|
4452
|
+
...dropUnsupportedParams !== void 0 ? { drop_unsupported_params: dropUnsupportedParams } : {}
|
|
3064
4453
|
},
|
|
3065
4454
|
prompt: promptConfig
|
|
3066
4455
|
}
|
|
@@ -3149,7 +4538,7 @@ var init_orchestration_language_model_strategy = __esm({
|
|
|
3149
4538
|
}
|
|
3150
4539
|
}
|
|
3151
4540
|
for (const key of CONFIG_REF_IGNORED_PROVIDER_OPTIONS) {
|
|
3152
|
-
if (sapOptions?.[key] &&
|
|
4541
|
+
if (sapOptions?.[key] !== void 0 && settings[key] === void 0) {
|
|
3153
4542
|
ignoredSettings.push(`providerOptions.${key}`);
|
|
3154
4543
|
}
|
|
3155
4544
|
}
|
|
@@ -3290,6 +4679,52 @@ __export(index_v2_exports, {
|
|
|
3290
4679
|
module.exports = __toCommonJS(index_v2_exports);
|
|
3291
4680
|
init_convert_to_sap_messages();
|
|
3292
4681
|
|
|
4682
|
+
// src/sap-ai-adapters-v3-to-v2.ts
|
|
4683
|
+
var import_provider2 = require("@ai-sdk/provider");
|
|
4684
|
+
|
|
4685
|
+
// src/map-readable-stream.ts
|
|
4686
|
+
function mapReadableStream(source, convert) {
|
|
4687
|
+
const reader = source.getReader();
|
|
4688
|
+
let cancelled = false;
|
|
4689
|
+
return new ReadableStream(
|
|
4690
|
+
{
|
|
4691
|
+
async cancel(reason) {
|
|
4692
|
+
cancelled = true;
|
|
4693
|
+
try {
|
|
4694
|
+
await reader.cancel(reason);
|
|
4695
|
+
} finally {
|
|
4696
|
+
reader.releaseLock();
|
|
4697
|
+
}
|
|
4698
|
+
},
|
|
4699
|
+
async pull(controller) {
|
|
4700
|
+
try {
|
|
4701
|
+
for (; ; ) {
|
|
4702
|
+
const next = await reader.read();
|
|
4703
|
+
if (cancelled) return;
|
|
4704
|
+
if (next.done) {
|
|
4705
|
+
reader.releaseLock();
|
|
4706
|
+
controller.close();
|
|
4707
|
+
return;
|
|
4708
|
+
}
|
|
4709
|
+
const converted = convert(next.value);
|
|
4710
|
+
if (converted !== null) {
|
|
4711
|
+
controller.enqueue(converted);
|
|
4712
|
+
return;
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4715
|
+
} catch (error) {
|
|
4716
|
+
if (cancelled) return;
|
|
4717
|
+
await reader.cancel(error).catch(() => void 0);
|
|
4718
|
+
if (cancelled) return;
|
|
4719
|
+
reader.releaseLock();
|
|
4720
|
+
controller.error(error);
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
},
|
|
4724
|
+
{ highWaterMark: 0 }
|
|
4725
|
+
);
|
|
4726
|
+
}
|
|
4727
|
+
|
|
3293
4728
|
// src/sap-ai-adapters-v3-to-v2.ts
|
|
3294
4729
|
function convertStreamPartToV2(internalPart) {
|
|
3295
4730
|
const compatiblePart = internalPart;
|
|
@@ -3307,7 +4742,7 @@ function convertStreamPartToV2(internalPart) {
|
|
|
3307
4742
|
case "stream-start":
|
|
3308
4743
|
return { ...compatiblePart, warnings: convertWarningsToV2(compatiblePart.warnings) };
|
|
3309
4744
|
case "tool-approval-request":
|
|
3310
|
-
|
|
4745
|
+
throw createV2ToolApprovalError();
|
|
3311
4746
|
case "tool-call": {
|
|
3312
4747
|
const { dynamic: _dynamic, ...part } = compatiblePart;
|
|
3313
4748
|
return part;
|
|
@@ -3345,19 +4780,17 @@ function convertWarningToV2(internalWarning) {
|
|
|
3345
4780
|
};
|
|
3346
4781
|
}
|
|
3347
4782
|
function createV2StreamFromInternal(internalStream) {
|
|
3348
|
-
return internalStream
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
})
|
|
3355
|
-
);
|
|
4783
|
+
return mapReadableStream(internalStream, convertStreamPartToV2);
|
|
4784
|
+
}
|
|
4785
|
+
function createV2ToolApprovalError() {
|
|
4786
|
+
return new import_provider2.UnsupportedFunctionalityError({
|
|
4787
|
+
functionality: "Tool approvals are unavailable through the V2 provider. Use /v3 with AI SDK 6 or /v4 with AI SDK 7."
|
|
4788
|
+
});
|
|
3356
4789
|
}
|
|
3357
4790
|
|
|
3358
4791
|
// src/sap-ai-embedding-model.ts
|
|
3359
|
-
var
|
|
3360
|
-
var
|
|
4792
|
+
var import_provider_utils3 = require("@ai-sdk/provider-utils");
|
|
4793
|
+
var import_zod4 = require("zod");
|
|
3361
4794
|
init_sap_ai_provider_options();
|
|
3362
4795
|
|
|
3363
4796
|
// src/sap-ai-strategy.ts
|
|
@@ -3388,6 +4821,10 @@ function getOrCreateLanguageModelStrategy(api) {
|
|
|
3388
4821
|
return strategyPromise;
|
|
3389
4822
|
}
|
|
3390
4823
|
async function createEmbeddingModelStrategy(api) {
|
|
4824
|
+
if (api === "responses") {
|
|
4825
|
+
const { UnsupportedFeatureError: UnsupportedFeatureError2 } = await Promise.resolve().then(() => (init_sap_ai_error(), sap_ai_error_exports));
|
|
4826
|
+
throw new UnsupportedFeatureError2("Embeddings", "responses", "foundation-models");
|
|
4827
|
+
}
|
|
3391
4828
|
if (api === "foundation-models") {
|
|
3392
4829
|
const { AzureOpenAiEmbeddingClient } = await import("@sap-ai-sdk/foundation-models");
|
|
3393
4830
|
const { FoundationModelsEmbeddingModelStrategy: FoundationModelsEmbeddingModelStrategy2 } = await Promise.resolve().then(() => (init_foundation_models_embedding_model_strategy(), foundation_models_embedding_model_strategy_exports));
|
|
@@ -3398,6 +4835,10 @@ async function createEmbeddingModelStrategy(api) {
|
|
|
3398
4835
|
return new OrchestrationEmbeddingModelStrategy2(OrchestrationEmbeddingClient2);
|
|
3399
4836
|
}
|
|
3400
4837
|
async function createLanguageModelStrategy(api) {
|
|
4838
|
+
if (api === "responses") {
|
|
4839
|
+
const { ResponsesLanguageModelStrategy: ResponsesLanguageModelStrategy2 } = await Promise.resolve().then(() => (init_responses_language_model_strategy(), responses_language_model_strategy_exports));
|
|
4840
|
+
return new ResponsesLanguageModelStrategy2();
|
|
4841
|
+
}
|
|
3401
4842
|
if (api === "foundation-models") {
|
|
3402
4843
|
const { AzureOpenAiChatClient } = await import("@sap-ai-sdk/foundation-models");
|
|
3403
4844
|
const { FoundationModelsLanguageModelStrategy: FoundationModelsLanguageModelStrategy2 } = await Promise.resolve().then(() => (init_foundation_models_language_model_strategy(), foundation_models_language_model_strategy_exports));
|
|
@@ -3411,7 +4852,7 @@ async function createLanguageModelStrategy(api) {
|
|
|
3411
4852
|
// src/sap-ai-embedding-model.ts
|
|
3412
4853
|
init_sap_ai_validation();
|
|
3413
4854
|
var DEFAULT_MAX_EMBEDDINGS_PER_CALL = 2048;
|
|
3414
|
-
var maxEmbeddingsPerCallSchema =
|
|
4855
|
+
var maxEmbeddingsPerCallSchema = import_zod4.z.number().int().positive().or(import_zod4.z.literal(Infinity));
|
|
3415
4856
|
var SAPAIEmbeddingModel = class {
|
|
3416
4857
|
maxEmbeddingsPerCall;
|
|
3417
4858
|
modelId;
|
|
@@ -3440,7 +4881,7 @@ var SAPAIEmbeddingModel = class {
|
|
|
3440
4881
|
}
|
|
3441
4882
|
async doEmbed(options) {
|
|
3442
4883
|
const providerName = getProviderName(this.config.provider);
|
|
3443
|
-
const sapOptions = await (0,
|
|
4884
|
+
const sapOptions = await (0, import_provider_utils3.parseProviderOptions)({
|
|
3444
4885
|
provider: providerName,
|
|
3445
4886
|
providerOptions: options.providerOptions,
|
|
3446
4887
|
schema: sapAIEmbeddingProviderOptions
|
|
@@ -3461,7 +4902,12 @@ var SAPAIEmbeddingModel = class {
|
|
|
3461
4902
|
provider: this.config.provider,
|
|
3462
4903
|
requestConfig: this.config.requestConfig
|
|
3463
4904
|
};
|
|
3464
|
-
return strategy.doEmbed(
|
|
4905
|
+
return strategy.doEmbed(
|
|
4906
|
+
strategyConfig,
|
|
4907
|
+
this.settings,
|
|
4908
|
+
options,
|
|
4909
|
+
this.maxEmbeddingsPerCall
|
|
4910
|
+
);
|
|
3465
4911
|
}
|
|
3466
4912
|
};
|
|
3467
4913
|
|
|
@@ -3516,8 +4962,57 @@ var SAPAIEmbeddingModelV2 = class {
|
|
|
3516
4962
|
// src/index-v2.ts
|
|
3517
4963
|
init_sap_ai_error();
|
|
3518
4964
|
|
|
4965
|
+
// src/sap-ai-adapters-v2-to-v3.ts
|
|
4966
|
+
var import_provider_utils4 = require("@ai-sdk/provider-utils");
|
|
4967
|
+
function normalizeV2PromptToV3(prompt) {
|
|
4968
|
+
return prompt.map((message) => {
|
|
4969
|
+
switch (message.role) {
|
|
4970
|
+
case "assistant":
|
|
4971
|
+
return {
|
|
4972
|
+
...message,
|
|
4973
|
+
content: message.content.map(
|
|
4974
|
+
(part) => part.type === "tool-result" ? normalizeToolResultPart(part) : part
|
|
4975
|
+
)
|
|
4976
|
+
};
|
|
4977
|
+
case "tool":
|
|
4978
|
+
return {
|
|
4979
|
+
...message,
|
|
4980
|
+
content: message.content.map(
|
|
4981
|
+
(part) => part.type === "tool-result" ? normalizeToolResultPart(part) : part
|
|
4982
|
+
)
|
|
4983
|
+
};
|
|
4984
|
+
default:
|
|
4985
|
+
return message;
|
|
4986
|
+
}
|
|
4987
|
+
});
|
|
4988
|
+
}
|
|
4989
|
+
function normalizeToolOutput(output) {
|
|
4990
|
+
if (output.type !== "content") return output;
|
|
4991
|
+
return {
|
|
4992
|
+
...output,
|
|
4993
|
+
value: output.value.map((item) => {
|
|
4994
|
+
if (item.type !== "media") return item;
|
|
4995
|
+
const mediaType = (0, import_provider_utils4.resolveFullMediaType)({
|
|
4996
|
+
part: {
|
|
4997
|
+
data: { data: item.data, type: "data" },
|
|
4998
|
+
mediaType: item.mediaType.toLowerCase(),
|
|
4999
|
+
type: "file"
|
|
5000
|
+
}
|
|
5001
|
+
});
|
|
5002
|
+
return {
|
|
5003
|
+
...item,
|
|
5004
|
+
mediaType,
|
|
5005
|
+
type: mediaType.startsWith("image/") ? "image-data" : "file-data"
|
|
5006
|
+
};
|
|
5007
|
+
})
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
5010
|
+
function normalizeToolResultPart(part) {
|
|
5011
|
+
return { ...part, output: normalizeToolOutput(part.output) };
|
|
5012
|
+
}
|
|
5013
|
+
|
|
3519
5014
|
// src/sap-ai-language-model.ts
|
|
3520
|
-
var
|
|
5015
|
+
var import_provider_utils5 = require("@ai-sdk/provider-utils");
|
|
3521
5016
|
init_sap_ai_provider_options();
|
|
3522
5017
|
init_sap_ai_validation();
|
|
3523
5018
|
var SAPAILanguageModel = class {
|
|
@@ -3551,11 +5046,13 @@ var SAPAILanguageModel = class {
|
|
|
3551
5046
|
}
|
|
3552
5047
|
async doGenerate(options) {
|
|
3553
5048
|
const { strategy, strategyConfig } = await this.prepareInvocation(options);
|
|
3554
|
-
|
|
5049
|
+
const result = strategy.doGenerate(strategyConfig, this.settings, options);
|
|
5050
|
+
return result;
|
|
3555
5051
|
}
|
|
3556
5052
|
async doStream(options) {
|
|
3557
5053
|
const { strategy, strategyConfig } = await this.prepareInvocation(options);
|
|
3558
|
-
|
|
5054
|
+
const result = strategy.doStream(strategyConfig, this.settings, options);
|
|
5055
|
+
return result;
|
|
3559
5056
|
}
|
|
3560
5057
|
supportsUrl(url) {
|
|
3561
5058
|
if (url.protocol === "https:") return true;
|
|
@@ -3572,7 +5069,7 @@ var SAPAILanguageModel = class {
|
|
|
3572
5069
|
*/
|
|
3573
5070
|
async prepareInvocation(options) {
|
|
3574
5071
|
const providerName = getProviderName(this.config.provider);
|
|
3575
|
-
const sapOptions = await (0,
|
|
5072
|
+
const sapOptions = await (0, import_provider_utils5.parseProviderOptions)({
|
|
3576
5073
|
provider: providerName,
|
|
3577
5074
|
providerOptions: options.providerOptions,
|
|
3578
5075
|
schema: sapAILanguageModelProviderOptions
|
|
@@ -3582,10 +5079,12 @@ var SAPAILanguageModel = class {
|
|
|
3582
5079
|
api: effectiveApi,
|
|
3583
5080
|
invocationSettings: sapOptions ? {
|
|
3584
5081
|
api: sapOptions.api,
|
|
5082
|
+
dropUnsupportedParams: sapOptions.dropUnsupportedParams,
|
|
3585
5083
|
escapeTemplatePlaceholders: sapOptions.escapeTemplatePlaceholders,
|
|
3586
5084
|
orchestrationConfigRef: sapOptions.orchestrationConfigRef,
|
|
3587
5085
|
placeholderValues: sapOptions.placeholderValues,
|
|
3588
|
-
promptTemplateRef: sapOptions.promptTemplateRef
|
|
5086
|
+
promptTemplateRef: sapOptions.promptTemplateRef,
|
|
5087
|
+
responses: sapOptions.responses
|
|
3589
5088
|
} : void 0,
|
|
3590
5089
|
modelApi: this.settings.api,
|
|
3591
5090
|
modelSettings: this.settings
|
|
@@ -3626,7 +5125,10 @@ var SAPAILanguageModelV2 = class {
|
|
|
3626
5125
|
this.internalModel = new SAPAILanguageModel(modelId, settings, config);
|
|
3627
5126
|
}
|
|
3628
5127
|
async doGenerate(options) {
|
|
3629
|
-
const result = await this.internalModel.doGenerate(options);
|
|
5128
|
+
const result = await this.internalModel.doGenerate(normalizeCallOptions(options));
|
|
5129
|
+
if (result.content.some((part) => part.type === "tool-approval-request")) {
|
|
5130
|
+
throw createV2ToolApprovalError();
|
|
5131
|
+
}
|
|
3630
5132
|
return {
|
|
3631
5133
|
content: result.content,
|
|
3632
5134
|
finishReason: result.finishReason.unified,
|
|
@@ -3638,7 +5140,7 @@ var SAPAILanguageModelV2 = class {
|
|
|
3638
5140
|
};
|
|
3639
5141
|
}
|
|
3640
5142
|
async doStream(options) {
|
|
3641
|
-
const result = await this.internalModel.doStream(options);
|
|
5143
|
+
const result = await this.internalModel.doStream(normalizeCallOptions(options));
|
|
3642
5144
|
return {
|
|
3643
5145
|
request: result.request,
|
|
3644
5146
|
response: result.response ? {
|
|
@@ -3648,13 +5150,22 @@ var SAPAILanguageModelV2 = class {
|
|
|
3648
5150
|
};
|
|
3649
5151
|
}
|
|
3650
5152
|
};
|
|
5153
|
+
function normalizeCallOptions(options) {
|
|
5154
|
+
const normalized = {
|
|
5155
|
+
...options,
|
|
5156
|
+
prompt: normalizeV2PromptToV3(options.prompt),
|
|
5157
|
+
// Legacy provider-defined tools keep their unsupported warning/skip behavior.
|
|
5158
|
+
tools: options.tools
|
|
5159
|
+
};
|
|
5160
|
+
return normalized;
|
|
5161
|
+
}
|
|
3651
5162
|
|
|
3652
5163
|
// src/index-v2.ts
|
|
3653
5164
|
init_sap_ai_provider_options();
|
|
3654
5165
|
|
|
3655
5166
|
// src/sap-ai-provider-v2.ts
|
|
3656
|
-
var
|
|
3657
|
-
var
|
|
5167
|
+
var import_provider10 = require("@ai-sdk/provider");
|
|
5168
|
+
var import_util3 = require("@sap-cloud-sdk/util");
|
|
3658
5169
|
init_sap_ai_provider_options();
|
|
3659
5170
|
init_sap_ai_validation();
|
|
3660
5171
|
function createSAPAIProvider(options = {}) {
|
|
@@ -3671,7 +5182,7 @@ function createSAPAIProvider(options = {}) {
|
|
|
3671
5182
|
}
|
|
3672
5183
|
if (typeof process === "undefined" || !process.env.SAP_CLOUD_SDK_LOG_LEVEL) {
|
|
3673
5184
|
const logLevel = options.logLevel ?? "warn";
|
|
3674
|
-
(0,
|
|
5185
|
+
(0, import_util3.setGlobalLogLevel)(logLevel);
|
|
3675
5186
|
}
|
|
3676
5187
|
const deploymentConfig = options.deploymentId ? { deploymentId: options.deploymentId } : { resourceGroup };
|
|
3677
5188
|
const providerApi = options.api ?? "orchestration";
|
|
@@ -3713,7 +5224,7 @@ function createSAPAIProvider(options = {}) {
|
|
|
3713
5224
|
provider.languageModel = createModel;
|
|
3714
5225
|
provider.textEmbeddingModel = createEmbeddingModel;
|
|
3715
5226
|
provider.imageModel = (modelId) => {
|
|
3716
|
-
throw new
|
|
5227
|
+
throw new import_provider10.NoSuchModelError({
|
|
3717
5228
|
message: `SAP AI Core does not support image generation. Model '${modelId}' is not available.`,
|
|
3718
5229
|
modelId,
|
|
3719
5230
|
modelType: "imageModel"
|