@jerome-benoit/sap-ai-provider-v2 5.0.1 → 5.0.3
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 +39 -32
- package/dist/{chunk-JRUSQTKB.js → chunk-3H5C5U22.js} +19 -11
- package/dist/chunk-3H5C5U22.js.map +1 -0
- package/dist/{chunk-AFZC2DH2.js → chunk-4JLNWASF.js} +59 -387
- package/dist/chunk-4JLNWASF.js.map +1 -0
- package/dist/{chunk-U23M3VYO.js → chunk-E76ZDPIW.js} +17 -7
- package/dist/chunk-E76ZDPIW.js.map +1 -0
- package/dist/chunk-NF355OFT.js +635 -0
- package/dist/chunk-NF355OFT.js.map +1 -0
- package/dist/chunk-UIBQ5AFS.js +778 -0
- package/dist/chunk-UIBQ5AFS.js.map +1 -0
- package/dist/{chunk-MF3VO3ER.js → chunk-YP3AADWD.js} +47 -40
- package/dist/chunk-YP3AADWD.js.map +1 -0
- package/dist/{foundation-models-embedding-model-strategy-2GUADNXT.js → foundation-models-embedding-model-strategy-SAVQFBF4.js} +8 -9
- package/dist/foundation-models-embedding-model-strategy-SAVQFBF4.js.map +1 -0
- package/dist/{foundation-models-language-model-strategy-5AYZ5KHA.js → foundation-models-language-model-strategy-ZDOWVYTA.js} +19 -22
- package/dist/foundation-models-language-model-strategy-ZDOWVYTA.js.map +1 -0
- package/dist/index.cjs +1317 -31652
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -32
- package/dist/index.d.ts +17 -32
- package/dist/index.js +48 -194
- package/dist/index.js.map +1 -1
- package/dist/{orchestration-embedding-model-strategy-F7WHDLX7.js → orchestration-embedding-model-strategy-GT27AFII.js} +7 -11
- package/dist/orchestration-embedding-model-strategy-GT27AFII.js.map +1 -0
- package/dist/{orchestration-language-model-strategy-Z72AFW62.js → orchestration-language-model-strategy-7QTPQHCC.js} +32 -27
- package/dist/orchestration-language-model-strategy-7QTPQHCC.js.map +1 -0
- package/package.json +16 -13
- package/dist/chunk-2KOXKYVT.js +0 -31083
- package/dist/chunk-2KOXKYVT.js.map +0 -1
- package/dist/chunk-643USI3B.js +0 -251
- package/dist/chunk-643USI3B.js.map +0 -1
- package/dist/chunk-AFZC2DH2.js.map +0 -1
- package/dist/chunk-JRUSQTKB.js.map +0 -1
- package/dist/chunk-MF3VO3ER.js.map +0 -1
- package/dist/chunk-U23M3VYO.js.map +0 -1
- package/dist/foundation-models-embedding-model-strategy-2GUADNXT.js.map +0 -1
- package/dist/foundation-models-language-model-strategy-5AYZ5KHA.js.map +0 -1
- package/dist/orchestration-embedding-model-strategy-F7WHDLX7.js.map +0 -1
- package/dist/orchestration-language-model-strategy-Z72AFW62.js.map +0 -1
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
import {createRequire as __createRequire} from 'module';var require=__createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/sap-ai-provider-options.ts
|
|
4
|
+
import { lazySchema, zodSchema } from "@ai-sdk/provider-utils";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var SAP_AI_PROVIDER_NAME = "sap-ai";
|
|
7
|
+
function getProviderName(providerIdentifier) {
|
|
8
|
+
const dotIndex = providerIdentifier.indexOf(".");
|
|
9
|
+
return dotIndex === -1 ? providerIdentifier : providerIdentifier.slice(0, dotIndex);
|
|
10
|
+
}
|
|
11
|
+
var modelParamsSchema = z.object({
|
|
12
|
+
frequencyPenalty: z.number().min(-2).max(2).optional(),
|
|
13
|
+
maxTokens: z.number().int().positive().optional(),
|
|
14
|
+
n: z.number().int().positive().optional(),
|
|
15
|
+
parallel_tool_calls: z.boolean().optional(),
|
|
16
|
+
presencePenalty: z.number().min(-2).max(2).optional(),
|
|
17
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
18
|
+
topP: z.number().min(0).max(1).optional()
|
|
19
|
+
}).catchall(z.unknown());
|
|
20
|
+
var embeddingModelParamsSchema = z.object({
|
|
21
|
+
dimensions: z.number().int().positive().optional(),
|
|
22
|
+
encoding_format: z.enum(["base64", "binary", "float"]).optional(),
|
|
23
|
+
normalize: z.boolean().optional()
|
|
24
|
+
}).catchall(z.unknown());
|
|
25
|
+
function validateEmbeddingModelParamsSettings(modelParams) {
|
|
26
|
+
return embeddingModelParamsSchema.parse(modelParams);
|
|
27
|
+
}
|
|
28
|
+
function validateModelParamsSettings(modelParams) {
|
|
29
|
+
return modelParamsSchema.parse(modelParams);
|
|
30
|
+
}
|
|
31
|
+
function validateModelParamsWithWarnings(params, warnings) {
|
|
32
|
+
const result = modelParamsSchema.safeParse(params);
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
for (const issue of result.error.issues) {
|
|
35
|
+
const path = issue.path.join(".");
|
|
36
|
+
const value = path ? params[path] : void 0;
|
|
37
|
+
warnings.push({
|
|
38
|
+
message: `${path}=${String(value)} is invalid: ${issue.message}. The API may reject this value.`,
|
|
39
|
+
type: "other"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
var sapAIApiTypeSchema = z.enum(["orchestration", "foundation-models"]);
|
|
45
|
+
var cacheControlSchema = z.object({
|
|
46
|
+
ttl: z.enum(["5m", "1h"]).optional(),
|
|
47
|
+
type: z.literal("ephemeral")
|
|
48
|
+
});
|
|
49
|
+
var sapAIPartProviderOptionsSchema = z.object({
|
|
50
|
+
cacheControl: cacheControlSchema.optional()
|
|
51
|
+
});
|
|
52
|
+
function parseSAPPartProviderOptions(providerOptions, warnings) {
|
|
53
|
+
if (!providerOptions || typeof providerOptions !== "object") {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
const block = providerOptions[SAP_AI_PROVIDER_NAME];
|
|
57
|
+
if (block === void 0) {
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
const parsed = sapAIPartProviderOptionsSchema.safeParse(block);
|
|
61
|
+
if (parsed.success) {
|
|
62
|
+
return parsed.data;
|
|
63
|
+
}
|
|
64
|
+
if (warnings) {
|
|
65
|
+
for (const issue of parsed.error.issues) {
|
|
66
|
+
const path = issue.path.join(".");
|
|
67
|
+
const message = `providerOptions['sap-ai']${path ? `.${path}` : ""} is invalid: ${issue.message}. The directive was dropped.`;
|
|
68
|
+
if (!warnings.some((w) => w.message === message)) {
|
|
69
|
+
warnings.push({ message, type: "other" });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
var promptTemplateScopeSchema = z.enum(["tenant", "resource_group"]);
|
|
76
|
+
var promptTemplateRefByIdSchema = z.object({
|
|
77
|
+
id: z.string().min(1, "Template ID cannot be empty"),
|
|
78
|
+
scope: promptTemplateScopeSchema.optional()
|
|
79
|
+
});
|
|
80
|
+
var promptTemplateRefByScenarioNameVersionSchema = z.object({
|
|
81
|
+
name: z.string().min(1, "Template name cannot be empty"),
|
|
82
|
+
scenario: z.string().min(1, "Scenario cannot be empty"),
|
|
83
|
+
scope: promptTemplateScopeSchema.optional(),
|
|
84
|
+
version: z.string().min(1, "Version cannot be empty")
|
|
85
|
+
});
|
|
86
|
+
var promptTemplateRefSchema = z.union([
|
|
87
|
+
promptTemplateRefByIdSchema,
|
|
88
|
+
promptTemplateRefByScenarioNameVersionSchema
|
|
89
|
+
]);
|
|
90
|
+
var orchestrationConfigRefOverrideSchema = z.custom(
|
|
91
|
+
(value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
92
|
+
{ message: "overrideConfig must be an object" }
|
|
93
|
+
).refine(
|
|
94
|
+
(value) => {
|
|
95
|
+
let stream;
|
|
96
|
+
try {
|
|
97
|
+
stream = value.stream;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return stream === void 0 || Boolean(stream) && typeof stream === "object" && !Array.isArray(stream);
|
|
102
|
+
},
|
|
103
|
+
{ message: "overrideConfig.stream must be an object" }
|
|
104
|
+
).refine(
|
|
105
|
+
(value) => {
|
|
106
|
+
let stream;
|
|
107
|
+
try {
|
|
108
|
+
stream = value.stream;
|
|
109
|
+
} catch {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (stream === void 0 || stream === null || typeof stream !== "object") {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return !("enabled" in stream);
|
|
117
|
+
} catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
message: "stream.enabled is not allowed in overrideConfig: it is controlled by the call site (stream() or chatCompletion())"
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
var orchestrationConfigRefByIdSchema = z.object({
|
|
126
|
+
id: z.string().min(1, "Config ID cannot be empty"),
|
|
127
|
+
overrideConfig: orchestrationConfigRefOverrideSchema.optional()
|
|
128
|
+
});
|
|
129
|
+
var orchestrationConfigRefByScenarioNameVersionSchema = z.object({
|
|
130
|
+
name: z.string().min(1, "Config name cannot be empty"),
|
|
131
|
+
overrideConfig: orchestrationConfigRefOverrideSchema.optional(),
|
|
132
|
+
scenario: z.string().min(1, "Scenario cannot be empty"),
|
|
133
|
+
version: z.string().min(1, "Version cannot be empty")
|
|
134
|
+
});
|
|
135
|
+
var orchestrationConfigRefSchema = z.union([
|
|
136
|
+
orchestrationConfigRefByIdSchema,
|
|
137
|
+
orchestrationConfigRefByScenarioNameVersionSchema
|
|
138
|
+
]);
|
|
139
|
+
var sapAILanguageModelProviderOptions = lazySchema(
|
|
140
|
+
() => zodSchema(
|
|
141
|
+
z.object({
|
|
142
|
+
api: sapAIApiTypeSchema.optional(),
|
|
143
|
+
escapeTemplatePlaceholders: z.boolean().optional(),
|
|
144
|
+
includeReasoning: z.boolean().optional(),
|
|
145
|
+
modelParams: modelParamsSchema.optional(),
|
|
146
|
+
orchestrationConfigRef: orchestrationConfigRefSchema.optional(),
|
|
147
|
+
placeholderValues: z.record(z.string(), z.string()).optional(),
|
|
148
|
+
promptTemplateRef: promptTemplateRefSchema.optional()
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
var sapAIEmbeddingProviderOptions = lazySchema(
|
|
153
|
+
() => zodSchema(
|
|
154
|
+
z.object({
|
|
155
|
+
api: sapAIApiTypeSchema.optional(),
|
|
156
|
+
modelParams: embeddingModelParamsSchema.optional(),
|
|
157
|
+
type: z.enum(["document", "query", "text"]).optional()
|
|
158
|
+
})
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// src/deep-merge.ts
|
|
163
|
+
var MAX_DEPTH = 100;
|
|
164
|
+
function deepMerge(...sources) {
|
|
165
|
+
const result = {};
|
|
166
|
+
for (const source of sources) {
|
|
167
|
+
if (source != null) mergeInto(result, source, /* @__PURE__ */ new Set(), 0);
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
function isPlainObject(value) {
|
|
172
|
+
if (value === null || typeof value !== "object") return false;
|
|
173
|
+
const proto = Object.getPrototypeOf(value);
|
|
174
|
+
return proto === Object.prototype || proto === null;
|
|
175
|
+
}
|
|
176
|
+
function mergeInto(target, source, ancestors, depth) {
|
|
177
|
+
if (depth > MAX_DEPTH) throw new Error("Maximum merge depth exceeded");
|
|
178
|
+
if (ancestors.has(source)) throw new Error("Circular reference detected during deep merge");
|
|
179
|
+
ancestors.add(source);
|
|
180
|
+
for (const key of Object.keys(source)) {
|
|
181
|
+
const sourceValue = source[key];
|
|
182
|
+
const targetValue = Object.hasOwn(target, key) ? target[key] : void 0;
|
|
183
|
+
const value = isPlainObject(sourceValue) ? mergeInto(isPlainObject(targetValue) ? targetValue : {}, sourceValue, ancestors, depth + 1) : sourceValue;
|
|
184
|
+
Object.defineProperty(target, key, {
|
|
185
|
+
configurable: true,
|
|
186
|
+
enumerable: true,
|
|
187
|
+
value,
|
|
188
|
+
writable: true
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
ancestors.delete(source);
|
|
192
|
+
return target;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/sap-ai-error.ts
|
|
196
|
+
import {
|
|
197
|
+
APICallError,
|
|
198
|
+
InvalidPromptError,
|
|
199
|
+
LoadAPIKeyError,
|
|
200
|
+
NoSuchModelError,
|
|
201
|
+
UnsupportedFunctionalityError
|
|
202
|
+
} from "@ai-sdk/provider";
|
|
203
|
+
import { isErrorWithCause } from "@sap-cloud-sdk/util";
|
|
204
|
+
var HTTP_STATUS = {
|
|
205
|
+
BAD_REQUEST: 400,
|
|
206
|
+
CLIENT_CLOSED_REQUEST: 499,
|
|
207
|
+
CONFLICT: 409,
|
|
208
|
+
FORBIDDEN: 403,
|
|
209
|
+
INTERNAL_ERROR: 500,
|
|
210
|
+
NOT_FOUND: 404,
|
|
211
|
+
RATE_LIMIT: 429,
|
|
212
|
+
REQUEST_TIMEOUT: 408,
|
|
213
|
+
SERVICE_UNAVAILABLE: 503,
|
|
214
|
+
UNAUTHORIZED: 401
|
|
215
|
+
};
|
|
216
|
+
var ERROR_MATCHERS = [
|
|
217
|
+
{
|
|
218
|
+
category: "network",
|
|
219
|
+
isRetryable: true,
|
|
220
|
+
keywords: ["econnrefused", "enotfound", "network", "timeout"],
|
|
221
|
+
statusCode: HTTP_STATUS.SERVICE_UNAVAILABLE
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
category: "destination",
|
|
225
|
+
isRetryable: false,
|
|
226
|
+
keywords: ["could not resolve destination"],
|
|
227
|
+
message: (original) => `SAP AI Core destination error: ${original}
|
|
228
|
+
|
|
229
|
+
Check your destination configuration or provide a valid destinationName.`,
|
|
230
|
+
statusCode: HTTP_STATUS.BAD_REQUEST
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
category: "content filtered",
|
|
234
|
+
isRetryable: false,
|
|
235
|
+
keywords: ["filtered by the output filter"],
|
|
236
|
+
message: (original) => `Content was filtered: ${original}
|
|
237
|
+
|
|
238
|
+
The model's response was blocked by content safety filters. Try a different prompt.`,
|
|
239
|
+
statusCode: HTTP_STATUS.BAD_REQUEST
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
category: "stream consumption",
|
|
243
|
+
isRetryable: false,
|
|
244
|
+
keywords: ["consumed stream"],
|
|
245
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
category: "streaming",
|
|
249
|
+
isRetryable: true,
|
|
250
|
+
keywords: [
|
|
251
|
+
"iterating over",
|
|
252
|
+
"parse message into json",
|
|
253
|
+
"received from",
|
|
254
|
+
"no body",
|
|
255
|
+
"invalid sse payload"
|
|
256
|
+
],
|
|
257
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
category: "configuration",
|
|
261
|
+
isRetryable: false,
|
|
262
|
+
keywords: [
|
|
263
|
+
"prompt template or messages must be defined",
|
|
264
|
+
"filtering parameters cannot be empty",
|
|
265
|
+
"templating yaml string must be non-empty",
|
|
266
|
+
"could not access response data",
|
|
267
|
+
"could not parse json",
|
|
268
|
+
"error parsing yaml",
|
|
269
|
+
"yaml does not conform",
|
|
270
|
+
"validation errors"
|
|
271
|
+
],
|
|
272
|
+
statusCode: HTTP_STATUS.BAD_REQUEST
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
category: "environment",
|
|
276
|
+
isRetryable: false,
|
|
277
|
+
keywords: ["buffer is not available as globals"],
|
|
278
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
category: "response stream",
|
|
282
|
+
isRetryable: false,
|
|
283
|
+
keywords: ["response stream is undefined"],
|
|
284
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
category: "response processing",
|
|
288
|
+
isRetryable: true,
|
|
289
|
+
keywords: [
|
|
290
|
+
"response is required to process",
|
|
291
|
+
"stream is still open",
|
|
292
|
+
"data is not available yet"
|
|
293
|
+
],
|
|
294
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
category: "deployment retrieval",
|
|
298
|
+
isRetryable: true,
|
|
299
|
+
keywords: ["failed to fetch the list of deployments"],
|
|
300
|
+
statusCode: HTTP_STATUS.SERVICE_UNAVAILABLE
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
category: "stream buffer",
|
|
304
|
+
isRetryable: false,
|
|
305
|
+
keywords: ["received non-uint8array"],
|
|
306
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
307
|
+
}
|
|
308
|
+
];
|
|
309
|
+
var AUTHENTICATION_ERROR_KEYWORDS = [
|
|
310
|
+
"authentication",
|
|
311
|
+
"unauthorized",
|
|
312
|
+
"aicore_service_key",
|
|
313
|
+
"invalid credentials",
|
|
314
|
+
"service credentials",
|
|
315
|
+
"service binding"
|
|
316
|
+
];
|
|
317
|
+
var DEPLOYMENT_ERROR_KEYWORDS = [
|
|
318
|
+
"failed to resolve deployment",
|
|
319
|
+
"no deployment matched"
|
|
320
|
+
];
|
|
321
|
+
var ApiSwitchError = class extends Error {
|
|
322
|
+
/**
|
|
323
|
+
* Creates a new ApiSwitchError.
|
|
324
|
+
* @param fromApi - The API the model was configured with.
|
|
325
|
+
* @param toApi - The API being switched to at invocation time.
|
|
326
|
+
* @param conflictingFeature - The feature that prevents the API switch.
|
|
327
|
+
*/
|
|
328
|
+
constructor(fromApi, toApi, conflictingFeature) {
|
|
329
|
+
super(
|
|
330
|
+
`Cannot switch from ${fromApi} to ${toApi} API at invocation time because ${conflictingFeature} would be ignored. Create a new model instance without ${fromApi}-specific features, or keep using the ${fromApi} API.`
|
|
331
|
+
);
|
|
332
|
+
this.fromApi = fromApi;
|
|
333
|
+
this.toApi = toApi;
|
|
334
|
+
this.conflictingFeature = conflictingFeature;
|
|
335
|
+
this.name = "ApiSwitchError";
|
|
336
|
+
}
|
|
337
|
+
fromApi;
|
|
338
|
+
toApi;
|
|
339
|
+
conflictingFeature;
|
|
340
|
+
};
|
|
341
|
+
var UnsupportedFeatureError = class extends Error {
|
|
342
|
+
/**
|
|
343
|
+
* Creates a new UnsupportedFeatureError.
|
|
344
|
+
* @param feature - The name of the unsupported feature (e.g., "Content filtering").
|
|
345
|
+
* @param api - The API being used that does not support the feature.
|
|
346
|
+
* @param suggestedApi - The API that supports this feature.
|
|
347
|
+
*/
|
|
348
|
+
constructor(feature, api, suggestedApi) {
|
|
349
|
+
const apiName = api === "foundation-models" ? "Foundation Models" : "Orchestration";
|
|
350
|
+
const suggestedApiName = suggestedApi === "foundation-models" ? "Foundation Models" : "Orchestration";
|
|
351
|
+
super(`${feature} is not supported by ${apiName} API. Use ${suggestedApiName} API instead.`);
|
|
352
|
+
this.feature = feature;
|
|
353
|
+
this.api = api;
|
|
354
|
+
this.suggestedApi = suggestedApi;
|
|
355
|
+
this.name = "UnsupportedFeatureError";
|
|
356
|
+
}
|
|
357
|
+
feature;
|
|
358
|
+
api;
|
|
359
|
+
suggestedApi;
|
|
360
|
+
};
|
|
361
|
+
function convertSAPErrorToAPICallError(errorResponse, context) {
|
|
362
|
+
const { code, location, message, requestId } = extractErrorFields(errorResponse);
|
|
363
|
+
const statusCode = getStatusCodeFromSAPError(code, context?.httpStatusCode);
|
|
364
|
+
const responseBody = JSON.stringify({
|
|
365
|
+
error: {
|
|
366
|
+
code,
|
|
367
|
+
location,
|
|
368
|
+
message,
|
|
369
|
+
request_id: requestId
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
let enhancedMessage = message;
|
|
373
|
+
if (statusCode === HTTP_STATUS.UNAUTHORIZED || statusCode === HTTP_STATUS.FORBIDDEN) {
|
|
374
|
+
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";
|
|
375
|
+
if (requestId) {
|
|
376
|
+
enhancedMessage += `
|
|
377
|
+
Request ID: ${requestId}`;
|
|
378
|
+
}
|
|
379
|
+
return new LoadAPIKeyError({
|
|
380
|
+
message: enhancedMessage
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
if (statusCode === HTTP_STATUS.NOT_FOUND) {
|
|
384
|
+
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";
|
|
385
|
+
if (requestId) {
|
|
386
|
+
enhancedMessage += `
|
|
387
|
+
Request ID: ${requestId}`;
|
|
388
|
+
}
|
|
389
|
+
const modelId = context?.modelId ?? extractModelIdentifier(message, location);
|
|
390
|
+
return new NoSuchModelError({
|
|
391
|
+
message: enhancedMessage,
|
|
392
|
+
modelId: modelId ?? "unknown",
|
|
393
|
+
modelType: context?.modelType ?? "languageModel"
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (statusCode === HTTP_STATUS.RATE_LIMIT) {
|
|
397
|
+
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";
|
|
398
|
+
} else if (statusCode >= HTTP_STATUS.INTERNAL_ERROR) {
|
|
399
|
+
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";
|
|
400
|
+
} else if (location) {
|
|
401
|
+
enhancedMessage += `
|
|
402
|
+
|
|
403
|
+
Error location: ${location}`;
|
|
404
|
+
}
|
|
405
|
+
if (requestId) {
|
|
406
|
+
enhancedMessage += `
|
|
407
|
+
Request ID: ${requestId}`;
|
|
408
|
+
}
|
|
409
|
+
return new APICallError({
|
|
410
|
+
isRetryable: isRetryable(statusCode),
|
|
411
|
+
message: enhancedMessage,
|
|
412
|
+
requestBodyValues: context?.requestBody,
|
|
413
|
+
responseBody,
|
|
414
|
+
responseHeaders: context?.responseHeaders,
|
|
415
|
+
statusCode,
|
|
416
|
+
url: context?.url ?? ""
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function convertToAISDKError(error, context) {
|
|
420
|
+
if (APICallError.isInstance(error) || LoadAPIKeyError.isInstance(error) || NoSuchModelError.isInstance(error) || InvalidPromptError.isInstance(error) || UnsupportedFunctionalityError.isInstance(error)) {
|
|
421
|
+
return error;
|
|
422
|
+
}
|
|
423
|
+
const { aborted, response, rootError } = inspectError(error);
|
|
424
|
+
const responseHeaders = context?.responseHeaders ?? normalizeHeaders(response?.headers);
|
|
425
|
+
if (!aborted) {
|
|
426
|
+
const errorResponse = findStructuredErrorResponse(
|
|
427
|
+
rootError instanceof SyntaxError ? void 0 : rootError,
|
|
428
|
+
response?.data
|
|
429
|
+
);
|
|
430
|
+
if (errorResponse) {
|
|
431
|
+
return convertSAPErrorToAPICallError(errorResponse, {
|
|
432
|
+
...context,
|
|
433
|
+
httpStatusCode: response?.status ?? context?.httpStatusCode,
|
|
434
|
+
responseHeaders
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const resolvedContext = {
|
|
439
|
+
...context,
|
|
440
|
+
responseBody: serializeAxiosResponseData(response?.data),
|
|
441
|
+
responseHeaders
|
|
442
|
+
};
|
|
443
|
+
if (aborted) {
|
|
444
|
+
return createAPICallError(
|
|
445
|
+
error,
|
|
446
|
+
{
|
|
447
|
+
isRetryable: false,
|
|
448
|
+
message: "Request was aborted by the client",
|
|
449
|
+
statusCode: HTTP_STATUS.CLIENT_CLOSED_REQUEST
|
|
450
|
+
},
|
|
451
|
+
resolvedContext
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
if (isHttpStatus(response?.status)) {
|
|
455
|
+
return createAPICallError(
|
|
456
|
+
error,
|
|
457
|
+
{
|
|
458
|
+
isRetryable: isRetryable(response.status),
|
|
459
|
+
message: rootError instanceof SyntaxError && error instanceof Error ? error.message : rootError instanceof Error ? rootError.message : "SAP AI Core request failed",
|
|
460
|
+
statusCode: response.status
|
|
461
|
+
},
|
|
462
|
+
resolvedContext
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
if (rootError instanceof SyntaxError) {
|
|
466
|
+
return createAPICallError(
|
|
467
|
+
error,
|
|
468
|
+
{
|
|
469
|
+
isRetryable: false,
|
|
470
|
+
message: error instanceof Error && error !== rootError ? error.message : "Failed to parse SAP AI Core data.",
|
|
471
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
472
|
+
},
|
|
473
|
+
resolvedContext
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
if (rootError instanceof Error) {
|
|
477
|
+
const errorMsg = rootError.message.toLowerCase();
|
|
478
|
+
const originalErrorMsg = rootError.message;
|
|
479
|
+
if (AUTHENTICATION_ERROR_KEYWORDS.some((keyword) => errorMsg.includes(keyword))) {
|
|
480
|
+
return new LoadAPIKeyError({
|
|
481
|
+
message: `SAP AI Core authentication failed: ${originalErrorMsg}
|
|
482
|
+
|
|
483
|
+
Make sure your AICORE_SERVICE_KEY environment variable is set correctly.
|
|
484
|
+
See: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-service-key`
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (DEPLOYMENT_ERROR_KEYWORDS.some((keyword) => errorMsg.includes(keyword))) {
|
|
488
|
+
const modelId = context?.modelId ?? extractModelIdentifier(originalErrorMsg);
|
|
489
|
+
return new NoSuchModelError({
|
|
490
|
+
message: `SAP AI Core deployment error: ${originalErrorMsg}
|
|
491
|
+
|
|
492
|
+
Make sure you have a running orchestration deployment in your SAP AI Core instance.
|
|
493
|
+
See: https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-deployment-for-orchestration`,
|
|
494
|
+
modelId: modelId ?? "unknown",
|
|
495
|
+
modelType: context?.modelType ?? "languageModel"
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
const statusMatch = /status code (\d+)/i.exec(originalErrorMsg);
|
|
499
|
+
const extractedStatus = statusMatch?.[1] ? Number.parseInt(statusMatch[1], 10) : void 0;
|
|
500
|
+
if (isHttpStatus(extractedStatus)) {
|
|
501
|
+
return createAPICallError(
|
|
502
|
+
error,
|
|
503
|
+
{
|
|
504
|
+
isRetryable: isRetryable(extractedStatus),
|
|
505
|
+
message: `SAP AI Core request failed: ${originalErrorMsg}`,
|
|
506
|
+
statusCode: extractedStatus
|
|
507
|
+
},
|
|
508
|
+
resolvedContext
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
for (const matcher of ERROR_MATCHERS) {
|
|
512
|
+
if (matcher.keywords.some((keyword) => errorMsg.includes(keyword))) {
|
|
513
|
+
const message2 = "message" in matcher ? matcher.message(originalErrorMsg) : `SAP AI Core ${matcher.category} error: ${originalErrorMsg}`;
|
|
514
|
+
return createAPICallError(
|
|
515
|
+
error,
|
|
516
|
+
{
|
|
517
|
+
isRetryable: matcher.isRetryable,
|
|
518
|
+
message: message2,
|
|
519
|
+
statusCode: matcher.statusCode
|
|
520
|
+
},
|
|
521
|
+
resolvedContext
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const message = rootError instanceof Error ? rootError.message : typeof rootError === "string" ? rootError : "Unknown error occurred";
|
|
527
|
+
const fullMessage = context?.operation ? `SAP AI Core ${context.operation} failed: ${message}` : `SAP AI Core error: ${message}`;
|
|
528
|
+
return createAPICallError(
|
|
529
|
+
error,
|
|
530
|
+
{
|
|
531
|
+
isRetryable: false,
|
|
532
|
+
message: fullMessage,
|
|
533
|
+
statusCode: HTTP_STATUS.INTERNAL_ERROR
|
|
534
|
+
},
|
|
535
|
+
resolvedContext
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
function normalizeHeaders(headers) {
|
|
539
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
540
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
541
|
+
const out = Object.fromEntries(headers.entries());
|
|
542
|
+
return Object.keys(out).length === 0 ? void 0 : out;
|
|
543
|
+
}
|
|
544
|
+
const record = headers;
|
|
545
|
+
const entries = Object.entries(record).flatMap(([key, value]) => {
|
|
546
|
+
const k = key.toLowerCase();
|
|
547
|
+
if (typeof value === "string") return [[k, value]];
|
|
548
|
+
if (Array.isArray(value)) {
|
|
549
|
+
const strings = value.filter((item) => typeof item === "string").join("; ");
|
|
550
|
+
return strings.length > 0 ? [[k, strings]] : [];
|
|
551
|
+
}
|
|
552
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
553
|
+
return [[k, String(value)]];
|
|
554
|
+
}
|
|
555
|
+
return [];
|
|
556
|
+
});
|
|
557
|
+
if (entries.length === 0) return void 0;
|
|
558
|
+
return Object.fromEntries(entries);
|
|
559
|
+
}
|
|
560
|
+
function createAPICallError(error, options, context) {
|
|
561
|
+
return new APICallError({
|
|
562
|
+
cause: error,
|
|
563
|
+
isRetryable: options.isRetryable,
|
|
564
|
+
message: options.message,
|
|
565
|
+
requestBodyValues: context?.requestBody,
|
|
566
|
+
responseBody: context?.responseBody,
|
|
567
|
+
responseHeaders: context?.responseHeaders,
|
|
568
|
+
statusCode: options.statusCode,
|
|
569
|
+
url: context?.url ?? ""
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
function extractErrorFields(response) {
|
|
573
|
+
const innerError = response.error;
|
|
574
|
+
if (Array.isArray(innerError)) {
|
|
575
|
+
const first = innerError[0];
|
|
576
|
+
return {
|
|
577
|
+
code: first?.code,
|
|
578
|
+
location: first?.location,
|
|
579
|
+
message: first?.message ?? "Unknown SAP AI error",
|
|
580
|
+
requestId: first?.request_id
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const entry = innerError;
|
|
584
|
+
return {
|
|
585
|
+
code: entry.code,
|
|
586
|
+
location: entry.location,
|
|
587
|
+
message: entry.message,
|
|
588
|
+
requestId: entry.request_id
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
function extractModelIdentifier(message, location) {
|
|
592
|
+
const patterns = [
|
|
593
|
+
/deployment[:\s]+([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)/i,
|
|
594
|
+
/model[:\s]+([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)/i,
|
|
595
|
+
/resource[:\s]+([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)/i
|
|
596
|
+
];
|
|
597
|
+
for (const pattern of patterns) {
|
|
598
|
+
const match = pattern.exec(message);
|
|
599
|
+
if (match?.[1]) {
|
|
600
|
+
return match[1];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (location) {
|
|
604
|
+
const locationMatch = /([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)/.exec(location);
|
|
605
|
+
if (locationMatch?.[1]) {
|
|
606
|
+
return locationMatch[1];
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return void 0;
|
|
610
|
+
}
|
|
611
|
+
function findStructuredErrorResponse(rootError, axiosData) {
|
|
612
|
+
if (isStructuredErrorResponse(rootError)) return rootError;
|
|
613
|
+
if (isStructuredErrorResponse(axiosData)) return axiosData;
|
|
614
|
+
if (rootError instanceof Error) {
|
|
615
|
+
const parsed = tryExtractSAPErrorFromMessage(rootError.message);
|
|
616
|
+
if (isStructuredErrorResponse(parsed)) return parsed;
|
|
617
|
+
}
|
|
618
|
+
return void 0;
|
|
619
|
+
}
|
|
620
|
+
function getStatusCodeFromSAPError(code, httpStatusCode) {
|
|
621
|
+
if (isHttpStatus(code)) {
|
|
622
|
+
return code;
|
|
623
|
+
}
|
|
624
|
+
if (isHttpStatus(httpStatusCode)) {
|
|
625
|
+
return httpStatusCode;
|
|
626
|
+
}
|
|
627
|
+
return HTTP_STATUS.INTERNAL_ERROR;
|
|
628
|
+
}
|
|
629
|
+
function inspectError(error) {
|
|
630
|
+
const seen = /* @__PURE__ */ new Set();
|
|
631
|
+
let rootError = error;
|
|
632
|
+
let current = error;
|
|
633
|
+
let response;
|
|
634
|
+
let aborted = false;
|
|
635
|
+
while (typeof current === "object" && current !== null && !seen.has(current)) {
|
|
636
|
+
seen.add(current);
|
|
637
|
+
rootError = current;
|
|
638
|
+
aborted ||= isAbortError(current);
|
|
639
|
+
const entry = current;
|
|
640
|
+
if (response === void 0 && entry.isAxiosError === true) response = entry.response;
|
|
641
|
+
const cause = "cause" in entry ? entry.cause : current instanceof Error && isErrorWithCause(current) ? current.rootCause : void 0;
|
|
642
|
+
if (cause === void 0 || typeof cause === "object" && cause !== null && seen.has(cause)) {
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
rootError = cause;
|
|
646
|
+
current = cause;
|
|
647
|
+
}
|
|
648
|
+
return { aborted, response, rootError };
|
|
649
|
+
}
|
|
650
|
+
function isAbortError(error) {
|
|
651
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
652
|
+
return true;
|
|
653
|
+
}
|
|
654
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
const transportError = error;
|
|
658
|
+
return transportError.isAxiosError === true && transportError.code === "ERR_CANCELED";
|
|
659
|
+
}
|
|
660
|
+
function isHttpStatus(status) {
|
|
661
|
+
return typeof status === "number" && Number.isInteger(status) && status >= 100 && status < 600;
|
|
662
|
+
}
|
|
663
|
+
function isRetryable(statusCode) {
|
|
664
|
+
return statusCode === HTTP_STATUS.REQUEST_TIMEOUT || statusCode === HTTP_STATUS.CONFLICT || statusCode === HTTP_STATUS.RATE_LIMIT || statusCode >= HTTP_STATUS.INTERNAL_ERROR && statusCode < 600;
|
|
665
|
+
}
|
|
666
|
+
function isStructuredErrorResponse(error) {
|
|
667
|
+
if (error === null || typeof error !== "object" || !("error" in error)) {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
const errorEnvelope = error;
|
|
671
|
+
const innerError = errorEnvelope.error;
|
|
672
|
+
if (innerError === void 0) return false;
|
|
673
|
+
if (Array.isArray(innerError)) {
|
|
674
|
+
return innerError.every((entry) => {
|
|
675
|
+
if (entry === null || typeof entry !== "object" || !("message" in entry)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
const errorEntry = entry;
|
|
679
|
+
if (typeof errorEntry.message !== "string") {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
if ("code" in entry && errorEntry.code != null && typeof errorEntry.code !== "number") {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
return true;
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
if (typeof innerError !== "object" || innerError === null || !("message" in innerError)) {
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
const errorObj = innerError;
|
|
692
|
+
if (typeof errorObj.message !== "string") {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
if ("code" in innerError && errorObj.code != null && typeof errorObj.code !== "number") {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
return true;
|
|
699
|
+
}
|
|
700
|
+
function serializeAxiosResponseData(data, maxLength = 2e3) {
|
|
701
|
+
if (data === void 0) return void 0;
|
|
702
|
+
let serialized;
|
|
703
|
+
try {
|
|
704
|
+
if (typeof data === "string") {
|
|
705
|
+
serialized = data;
|
|
706
|
+
} else {
|
|
707
|
+
const json = JSON.stringify(data, null, 2);
|
|
708
|
+
serialized = typeof json === "string" ? json : `[Unable to serialize: ${typeof data}]`;
|
|
709
|
+
}
|
|
710
|
+
} catch {
|
|
711
|
+
serialized = `[Unable to serialize: ${typeof data}]`;
|
|
712
|
+
}
|
|
713
|
+
if (serialized.length > maxLength) {
|
|
714
|
+
return serialized.slice(0, maxLength) + "...[truncated]";
|
|
715
|
+
}
|
|
716
|
+
return serialized;
|
|
717
|
+
}
|
|
718
|
+
function tryExtractSAPErrorFromMessage(message) {
|
|
719
|
+
const startIdx = message.indexOf("{");
|
|
720
|
+
if (startIdx === -1) return null;
|
|
721
|
+
let depth = 0;
|
|
722
|
+
let endIdx = -1;
|
|
723
|
+
let inString = false;
|
|
724
|
+
let escaped = false;
|
|
725
|
+
for (let i = startIdx; i < message.length; i++) {
|
|
726
|
+
const character = message.charCodeAt(i);
|
|
727
|
+
if (inString) {
|
|
728
|
+
if (escaped) escaped = false;
|
|
729
|
+
else if (character === 92) escaped = true;
|
|
730
|
+
else if (character === 34) inString = false;
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (character === 34) inString = true;
|
|
734
|
+
else if (character === 123) depth++;
|
|
735
|
+
else if (character === 125) {
|
|
736
|
+
depth--;
|
|
737
|
+
if (depth === 0) {
|
|
738
|
+
endIdx = i;
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (endIdx === -1) return null;
|
|
744
|
+
try {
|
|
745
|
+
const parsed = JSON.parse(message.slice(startIdx, endIdx + 1));
|
|
746
|
+
if (parsed && typeof parsed === "object" && "error" in parsed) {
|
|
747
|
+
return parsed;
|
|
748
|
+
}
|
|
749
|
+
if (parsed && typeof parsed === "object" && "message" in parsed) {
|
|
750
|
+
return { error: parsed };
|
|
751
|
+
}
|
|
752
|
+
return null;
|
|
753
|
+
} catch {
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// src/version.ts
|
|
759
|
+
var VERSION = true ? "5.0.3" : "0.0.0-test";
|
|
760
|
+
|
|
761
|
+
export {
|
|
762
|
+
SAP_AI_PROVIDER_NAME,
|
|
763
|
+
getProviderName,
|
|
764
|
+
validateEmbeddingModelParamsSettings,
|
|
765
|
+
validateModelParamsSettings,
|
|
766
|
+
validateModelParamsWithWarnings,
|
|
767
|
+
parseSAPPartProviderOptions,
|
|
768
|
+
orchestrationConfigRefSchema,
|
|
769
|
+
sapAILanguageModelProviderOptions,
|
|
770
|
+
sapAIEmbeddingProviderOptions,
|
|
771
|
+
deepMerge,
|
|
772
|
+
ApiSwitchError,
|
|
773
|
+
UnsupportedFeatureError,
|
|
774
|
+
convertToAISDKError,
|
|
775
|
+
normalizeHeaders,
|
|
776
|
+
VERSION
|
|
777
|
+
};
|
|
778
|
+
//# sourceMappingURL=chunk-UIBQ5AFS.js.map
|