@llumiverse/core 1.2.0 → 1.4.0-dev.20260629.090753Z
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/lib/CompletionStream.d.ts +48 -0
- package/lib/CompletionStream.d.ts.map +1 -0
- package/lib/{esm/CompletionStream.js → CompletionStream.js} +142 -67
- package/lib/CompletionStream.js.map +1 -0
- package/lib/{types/Driver.d.ts → Driver.d.ts} +38 -5
- package/lib/Driver.d.ts.map +1 -0
- package/lib/{esm/Driver.js → Driver.js} +152 -107
- package/lib/Driver.js.map +1 -0
- package/lib/{types/async.d.ts → async.d.ts} +3 -3
- package/lib/async.d.ts.map +1 -0
- package/lib/{esm/async.js → async.js} +4 -4
- package/lib/async.js.map +1 -0
- package/lib/{types/conversation-utils.d.ts → conversation-utils.d.ts} +9 -0
- package/lib/conversation-utils.d.ts.map +1 -0
- package/lib/{esm/conversation-utils.js → conversation-utils.js} +78 -15
- package/lib/conversation-utils.js.map +1 -0
- package/lib/embeddings.d.ts +58 -0
- package/lib/embeddings.d.ts.map +1 -0
- package/lib/embeddings.js +131 -0
- package/lib/embeddings.js.map +1 -0
- package/lib/formatters/commons.d.ts +3 -0
- package/lib/formatters/commons.d.ts.map +1 -0
- package/lib/formatters/commons.js +4 -0
- package/lib/formatters/commons.js.map +1 -0
- package/lib/{types/formatters → formatters}/generic.d.ts +2 -2
- package/lib/formatters/generic.d.ts.map +1 -0
- package/lib/{esm/formatters → formatters}/generic.js +8 -8
- package/lib/formatters/generic.js.map +1 -0
- package/lib/formatters/index.d.ts +4 -0
- package/lib/formatters/index.d.ts.map +1 -0
- package/lib/formatters/index.js +4 -0
- package/lib/formatters/index.js.map +1 -0
- package/lib/{types/formatters → formatters}/nova.d.ts +4 -4
- package/lib/formatters/nova.d.ts.map +1 -0
- package/lib/{esm/formatters → formatters}/nova.js +19 -17
- package/lib/formatters/nova.js.map +1 -0
- package/lib/http-agent.d.ts +53 -0
- package/lib/http-agent.d.ts.map +1 -0
- package/lib/http-agent.js +141 -0
- package/lib/http-agent.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/{types/json.d.ts → json.d.ts} +1 -1
- package/lib/json.d.ts.map +1 -0
- package/lib/{esm/json.js → json.js} +4 -3
- package/lib/json.js.map +1 -0
- package/lib/logger.d.ts +3 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +42 -0
- package/lib/logger.js.map +1 -0
- package/lib/resolver.d.ts +2 -0
- package/lib/resolver.d.ts.map +1 -0
- package/lib/{esm/resolver.js → resolver.js} +7 -4
- package/lib/resolver.js.map +1 -0
- package/lib/stream.d.ts.map +1 -0
- package/lib/stream.js.map +1 -0
- package/lib/{types/validation.d.ts → validation.d.ts} +1 -1
- package/lib/validation.d.ts.map +1 -0
- package/lib/validation.js +100 -0
- package/lib/validation.js.map +1 -0
- package/package.json +29 -38
- package/src/CompletionStream.ts +208 -115
- package/src/Driver.error.test.ts +101 -72
- package/src/Driver.ts +208 -152
- package/src/async.ts +30 -30
- package/src/conversation-utils.ts +92 -16
- package/src/embeddings.ts +157 -0
- package/src/formatters/commons.ts +2 -2
- package/src/formatters/generic.ts +20 -17
- package/src/formatters/index.ts +3 -3
- package/src/formatters/nova.ts +53 -51
- package/src/http-agent.test.ts +281 -0
- package/src/http-agent.ts +177 -0
- package/src/index.ts +7 -5
- package/src/json.ts +6 -5
- package/src/logger.ts +42 -0
- package/src/resolver.ts +12 -9
- package/src/stream.ts +4 -5
- package/src/validation.ts +42 -29
- package/lib/cjs/CompletionStream.js +0 -293
- package/lib/cjs/CompletionStream.js.map +0 -1
- package/lib/cjs/Driver.js +0 -300
- package/lib/cjs/Driver.js.map +0 -1
- package/lib/cjs/async.js +0 -131
- package/lib/cjs/async.js.map +0 -1
- package/lib/cjs/conversation-utils.js +0 -579
- package/lib/cjs/conversation-utils.js.map +0 -1
- package/lib/cjs/formatters/commons.js +0 -7
- package/lib/cjs/formatters/commons.js.map +0 -1
- package/lib/cjs/formatters/generic.js +0 -59
- package/lib/cjs/formatters/generic.js.map +0 -1
- package/lib/cjs/formatters/index.js +0 -20
- package/lib/cjs/formatters/index.js.map +0 -1
- package/lib/cjs/formatters/nova.js +0 -99
- package/lib/cjs/formatters/nova.js.map +0 -1
- package/lib/cjs/index.js +0 -22
- package/lib/cjs/index.js.map +0 -1
- package/lib/cjs/json.js +0 -29
- package/lib/cjs/json.js.map +0 -1
- package/lib/cjs/package.json +0 -3
- package/lib/cjs/resolver.js +0 -45
- package/lib/cjs/resolver.js.map +0 -1
- package/lib/cjs/stream.js +0 -30
- package/lib/cjs/stream.js.map +0 -1
- package/lib/cjs/validation.js +0 -96
- package/lib/cjs/validation.js.map +0 -1
- package/lib/esm/CompletionStream.js.map +0 -1
- package/lib/esm/Driver.js.map +0 -1
- package/lib/esm/async.js.map +0 -1
- package/lib/esm/conversation-utils.js.map +0 -1
- package/lib/esm/formatters/commons.js +0 -4
- package/lib/esm/formatters/commons.js.map +0 -1
- package/lib/esm/formatters/generic.js.map +0 -1
- package/lib/esm/formatters/index.js +0 -4
- package/lib/esm/formatters/index.js.map +0 -1
- package/lib/esm/formatters/nova.js.map +0 -1
- package/lib/esm/index.js +0 -6
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/json.js.map +0 -1
- package/lib/esm/resolver.js.map +0 -1
- package/lib/esm/stream.js.map +0 -1
- package/lib/esm/validation.js +0 -88
- package/lib/esm/validation.js.map +0 -1
- package/lib/types/CompletionStream.d.ts +0 -20
- package/lib/types/CompletionStream.d.ts.map +0 -1
- package/lib/types/Driver.d.ts.map +0 -1
- package/lib/types/async.d.ts.map +0 -1
- package/lib/types/conversation-utils.d.ts.map +0 -1
- package/lib/types/formatters/commons.d.ts +0 -3
- package/lib/types/formatters/commons.d.ts.map +0 -1
- package/lib/types/formatters/generic.d.ts.map +0 -1
- package/lib/types/formatters/index.d.ts +0 -4
- package/lib/types/formatters/index.d.ts.map +0 -1
- package/lib/types/formatters/nova.d.ts.map +0 -1
- package/lib/types/index.d.ts +0 -6
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/json.d.ts.map +0 -1
- package/lib/types/resolver.d.ts +0 -2
- package/lib/types/resolver.d.ts.map +0 -1
- package/lib/types/stream.d.ts.map +0 -1
- package/lib/types/validation.d.ts.map +0 -1
- /package/lib/{types/stream.d.ts → stream.d.ts} +0 -0
- /package/lib/{esm/stream.js → stream.js} +0 -0
|
@@ -3,50 +3,18 @@
|
|
|
3
3
|
* Base abstract class is then implemented by each environment
|
|
4
4
|
* (eg: OpenAI, HuggingFace, etc.)
|
|
5
5
|
*/
|
|
6
|
-
import { LlumiverseError } from
|
|
7
|
-
import { DefaultCompletionStream, FallbackCompletionStream } from
|
|
8
|
-
import { formatTextPrompt } from
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
else if (msgOrNever !== undefined) {
|
|
18
|
-
// Object-first: logger.info({ obj }, "message", ...args)
|
|
19
|
-
consoleMethod(msgOrNever, objOrMsg, ...args);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
// Object-only: logger.info({ obj })
|
|
23
|
-
consoleMethod(objOrMsg, ...args);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const ConsoleLogger = {
|
|
28
|
-
debug: createConsoleLoggerMethod(console.debug.bind(console)),
|
|
29
|
-
info: createConsoleLoggerMethod(console.info.bind(console)),
|
|
30
|
-
warn: createConsoleLoggerMethod(console.warn.bind(console)),
|
|
31
|
-
error: createConsoleLoggerMethod(console.error.bind(console)),
|
|
32
|
-
};
|
|
33
|
-
const noop = () => void 0;
|
|
34
|
-
const NoopLogger = {
|
|
35
|
-
debug: noop,
|
|
36
|
-
info: noop,
|
|
37
|
-
warn: noop,
|
|
38
|
-
error: noop,
|
|
39
|
-
};
|
|
40
|
-
export function createLogger(logger) {
|
|
41
|
-
if (logger === "console") {
|
|
42
|
-
return ConsoleLogger;
|
|
43
|
-
}
|
|
44
|
-
else if (logger) {
|
|
45
|
-
return logger;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
return NoopLogger;
|
|
6
|
+
import { LlumiverseError, } from '@llumiverse/common';
|
|
7
|
+
import { DefaultCompletionStream, FallbackCompletionStream } from './CompletionStream.js';
|
|
8
|
+
import { formatTextPrompt } from './formatters/index.js';
|
|
9
|
+
import { createAgentBackedFetch, createDriverHttpAgent, createDriverHttpAgentScope, } from './http-agent.js';
|
|
10
|
+
import { createLogger } from './logger.js';
|
|
11
|
+
import { validateResult } from './validation.js';
|
|
12
|
+
export { createLogger } from './logger.js';
|
|
13
|
+
function getObjectProperty(value, key) {
|
|
14
|
+
if (value && typeof value === 'object' && key in value) {
|
|
15
|
+
return value[key];
|
|
49
16
|
}
|
|
17
|
+
return undefined;
|
|
50
18
|
}
|
|
51
19
|
/**
|
|
52
20
|
* To be implemented by each driver
|
|
@@ -54,25 +22,61 @@ export function createLogger(logger) {
|
|
|
54
22
|
export class AbstractDriver {
|
|
55
23
|
options;
|
|
56
24
|
logger;
|
|
25
|
+
_httpAgent;
|
|
26
|
+
_driverFetch;
|
|
57
27
|
constructor(opts) {
|
|
58
28
|
this.options = opts;
|
|
59
29
|
this.logger = createLogger(opts.logger);
|
|
60
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Lazily-created undici `Agent` driven by `options.httpTimeout`.
|
|
33
|
+
* Pools sockets for the lifetime of the driver. Subclasses can
|
|
34
|
+
* either pass this directly to an SDK that accepts a `dispatcher`
|
|
35
|
+
* option (rare), or — much more commonly — use {@link getDriverFetch}
|
|
36
|
+
* to get a fetch implementation backed by it.
|
|
37
|
+
*
|
|
38
|
+
* Released via {@link destroy}.
|
|
39
|
+
*/
|
|
40
|
+
getHttpAgent() {
|
|
41
|
+
if (!this._httpAgent) {
|
|
42
|
+
this._httpAgent = createDriverHttpAgent(this.options.httpTimeout);
|
|
43
|
+
}
|
|
44
|
+
return this._httpAgent;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Fetch-compatible function backed by the driver's HTTP agent.
|
|
48
|
+
* Pass to any SDK that accepts a custom `fetch` option (OpenAI,
|
|
49
|
+
* Anthropic, `@google/genai`, Bedrock via Smithy, …) or use as a
|
|
50
|
+
* drop-in replacement for the global `fetch` in drivers that make
|
|
51
|
+
* raw HTTP calls.
|
|
52
|
+
*/
|
|
53
|
+
getDriverFetch() {
|
|
54
|
+
if (!this._driverFetch) {
|
|
55
|
+
this._driverFetch = createAgentBackedFetch(this.getHttpAgent());
|
|
56
|
+
}
|
|
57
|
+
return this._driverFetch;
|
|
58
|
+
}
|
|
59
|
+
createExecutionHttpAgentScope(options) {
|
|
60
|
+
return createDriverHttpAgentScope(this.options.httpTimeout, options.httpTimeout);
|
|
61
|
+
}
|
|
61
62
|
async createTrainingPrompt(options) {
|
|
62
|
-
const prompt = await this.createPrompt(options.segments, {
|
|
63
|
+
const prompt = await this.createPrompt(options.segments, {
|
|
64
|
+
result_schema: options.schema,
|
|
65
|
+
model: options.model,
|
|
66
|
+
});
|
|
63
67
|
return JSON.stringify({
|
|
64
68
|
prompt,
|
|
65
|
-
completion: typeof options.completion === 'string' ? options.completion : JSON.stringify(options.completion)
|
|
69
|
+
completion: typeof options.completion === 'string' ? options.completion : JSON.stringify(options.completion),
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
72
|
startTraining(_dataset, _options) {
|
|
69
|
-
throw new Error(
|
|
73
|
+
throw new Error('Method not implemented.');
|
|
70
74
|
}
|
|
71
75
|
cancelTraining(_jobId) {
|
|
72
|
-
throw new Error(
|
|
76
|
+
throw new Error('Method not implemented.');
|
|
73
77
|
}
|
|
74
78
|
getTrainingJob(_jobId) {
|
|
75
|
-
throw new Error(
|
|
79
|
+
throw new Error('Method not implemented.');
|
|
76
80
|
}
|
|
77
81
|
validateResult(result, options) {
|
|
78
82
|
if (!result.tool_use && !result.error && options.result_schema) {
|
|
@@ -80,11 +84,14 @@ export class AbstractDriver {
|
|
|
80
84
|
result.result = validateResult(result.result, options.result_schema);
|
|
81
85
|
}
|
|
82
86
|
catch (error) {
|
|
83
|
-
const
|
|
87
|
+
const validationError = error instanceof Error ? error : new Error(String(error));
|
|
88
|
+
const rawCode = getObjectProperty(error, 'code');
|
|
89
|
+
const code = rawCode === 'json_error' || rawCode === 'validation_error' ? rawCode : undefined;
|
|
90
|
+
const errorMessage = `[${this.provider}] [${options.model}] ${code ? `[${code}] ` : ''}Result validation error: ${validationError.message}`;
|
|
84
91
|
this.logger.error({ err: error, data: result.result }, errorMessage);
|
|
85
92
|
result.error = {
|
|
86
|
-
code:
|
|
87
|
-
message:
|
|
93
|
+
code: code || 'validation_error',
|
|
94
|
+
message: validationError.message,
|
|
88
95
|
data: result.result,
|
|
89
96
|
};
|
|
90
97
|
}
|
|
@@ -105,41 +112,55 @@ export class AbstractDriver {
|
|
|
105
112
|
});
|
|
106
113
|
}
|
|
107
114
|
async _execute(prompt, options) {
|
|
115
|
+
const httpScope = this.createExecutionHttpAgentScope(options);
|
|
108
116
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
117
|
+
return await httpScope.run(async () => {
|
|
118
|
+
try {
|
|
119
|
+
const start = Date.now();
|
|
120
|
+
let result;
|
|
121
|
+
if (this.isImageModel(options.model)) {
|
|
122
|
+
this.logger.debug(`[${this.provider}] Executing prompt on ${options.model}, image pathway.`);
|
|
123
|
+
result = await this.requestImageGeneration(prompt, options);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.logger.debug(`[${this.provider}] Executing prompt on ${options.model}, text pathway.`);
|
|
127
|
+
result = await this.requestTextCompletion(prompt, options);
|
|
128
|
+
this.validateResult(result, options);
|
|
129
|
+
}
|
|
130
|
+
const execution_time = Date.now() - start;
|
|
131
|
+
return { ...result, prompt, execution_time };
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// Don't wrap if already a LlumiverseError
|
|
135
|
+
if (LlumiverseError.isLlumiverseError(error)) {
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
// Log the original error for debugging
|
|
139
|
+
this.logger.error({
|
|
140
|
+
err: error,
|
|
141
|
+
data: { provider: this.provider, model: options.model, operation: 'execute', prompt },
|
|
142
|
+
}, `Error during execution in provider ${this.provider}:`);
|
|
143
|
+
throw this.formatLlumiverseError(error, {
|
|
144
|
+
provider: this.provider,
|
|
145
|
+
model: options.model,
|
|
146
|
+
operation: 'execute',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
134
149
|
});
|
|
135
150
|
}
|
|
151
|
+
finally {
|
|
152
|
+
await httpScope.close();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
formatDebugPrompt(prompt) {
|
|
156
|
+
return prompt;
|
|
136
157
|
}
|
|
137
158
|
isImageModel(_model) {
|
|
138
159
|
return false;
|
|
139
160
|
}
|
|
140
161
|
// by default no stream is supported. we block and we return all at once
|
|
141
162
|
async stream(segments, options) {
|
|
142
|
-
this.logger.
|
|
163
|
+
this.logger.debug(options, `Executing prompt with provider ${this.provider} with options: ${JSON.stringify(options)}`);
|
|
143
164
|
const prompt = await this.createPrompt(segments, options);
|
|
144
165
|
const canStream = await this.canStream(options);
|
|
145
166
|
if (canStream) {
|
|
@@ -162,7 +183,9 @@ export class AbstractDriver {
|
|
|
162
183
|
return formatTextPrompt(segments, opts.result_schema);
|
|
163
184
|
}
|
|
164
185
|
async createPrompt(segments, opts) {
|
|
165
|
-
return await (opts.format
|
|
186
|
+
return await (opts.format
|
|
187
|
+
? opts.format(segments, opts.result_schema)
|
|
188
|
+
: this.formatPrompt(segments, opts));
|
|
166
189
|
}
|
|
167
190
|
/**
|
|
168
191
|
* Must be overridden if the implementation cannot stream.
|
|
@@ -206,8 +229,8 @@ export class AbstractDriver {
|
|
|
206
229
|
* - Status 429, 408: retryable (rate limit, timeout)
|
|
207
230
|
* - Status 529: retryable (overloaded)
|
|
208
231
|
* - Status 5xx: retryable (server errors)
|
|
209
|
-
* -
|
|
210
|
-
* -
|
|
232
|
+
* - High-confidence transient messages containing "rate limit", "timeout", etc.: retryable
|
|
233
|
+
* - Status 4xx (except above and transient provider quirks): not retryable (client errors)
|
|
211
234
|
*
|
|
212
235
|
* @param error - The error to format
|
|
213
236
|
* @param context - Context about where the error occurred
|
|
@@ -216,18 +239,17 @@ export class AbstractDriver {
|
|
|
216
239
|
formatLlumiverseError(error, context) {
|
|
217
240
|
// Extract status code from common locations (only if numeric)
|
|
218
241
|
let code;
|
|
219
|
-
const rawCode = error
|
|
220
|
-
|
|
221
|
-
|
|
242
|
+
const rawCode = getObjectProperty(error, 'status') ||
|
|
243
|
+
getObjectProperty(error, 'statusCode') ||
|
|
244
|
+
getObjectProperty(error, 'code');
|
|
222
245
|
if (typeof rawCode === 'number') {
|
|
223
246
|
code = rawCode;
|
|
224
247
|
}
|
|
225
248
|
// Extract error name if available
|
|
226
|
-
const
|
|
249
|
+
const rawErrorName = getObjectProperty(error, 'name');
|
|
250
|
+
const errorName = typeof rawErrorName === 'string' ? rawErrorName : undefined;
|
|
227
251
|
// Extract message
|
|
228
|
-
const message = error instanceof Error
|
|
229
|
-
? error.message
|
|
230
|
-
: String(error);
|
|
252
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
231
253
|
// Determine retryability
|
|
232
254
|
const retryable = this.isRetryableError(code, message);
|
|
233
255
|
return new LlumiverseError(`[${this.provider}] ${message}`, retryable, context, error, code, errorName);
|
|
@@ -241,34 +263,24 @@ export class AbstractDriver {
|
|
|
241
263
|
* @returns True if retryable, false if not retryable, undefined if unknown
|
|
242
264
|
*/
|
|
243
265
|
isRetryableError(statusCode, message) {
|
|
244
|
-
// Numeric status codes
|
|
245
|
-
if (statusCode !== undefined) {
|
|
246
|
-
if (statusCode === 429 || statusCode === 408)
|
|
247
|
-
return true; // Rate limit, timeout
|
|
248
|
-
if (statusCode === 529)
|
|
249
|
-
return true; // Overloaded
|
|
250
|
-
if (statusCode >= 500 && statusCode < 600)
|
|
251
|
-
return true; // Server errors
|
|
252
|
-
return false; // 4xx client errors not retryable
|
|
253
|
-
}
|
|
254
|
-
// Message-based detection for non-HTTP errors
|
|
255
266
|
const lowerMessage = message.toLowerCase();
|
|
256
|
-
//
|
|
267
|
+
// Provider APIs sometimes surface transient failures under misleading
|
|
268
|
+
// client status codes, so high-confidence transient message signals
|
|
269
|
+
// must be honored before the generic 4xx classification below.
|
|
270
|
+
if (lowerMessage.includes('url_rejected-rejected_client_throttled'))
|
|
271
|
+
return true;
|
|
272
|
+
if (lowerMessage.includes('url_rejected-rejected_rate_limited'))
|
|
273
|
+
return true;
|
|
257
274
|
if (lowerMessage.includes('rate') && lowerMessage.includes('limit'))
|
|
258
275
|
return true;
|
|
259
|
-
// Timeout variations (timeout, timed out, time out)
|
|
260
276
|
if (lowerMessage.includes('timeout'))
|
|
261
277
|
return true;
|
|
262
278
|
if (lowerMessage.includes('timed') && lowerMessage.includes('out'))
|
|
263
279
|
return true;
|
|
264
280
|
if (lowerMessage.includes('time') && lowerMessage.includes('out'))
|
|
265
281
|
return true;
|
|
266
|
-
// Resource exhausted variations
|
|
267
282
|
if (lowerMessage.includes('resource') && lowerMessage.includes('exhaust'))
|
|
268
283
|
return true;
|
|
269
|
-
// Other retryable patterns
|
|
270
|
-
if (lowerMessage.includes('retry'))
|
|
271
|
-
return true;
|
|
272
284
|
if (lowerMessage.includes('overload'))
|
|
273
285
|
return true;
|
|
274
286
|
if (lowerMessage.includes('throttl'))
|
|
@@ -277,19 +289,52 @@ export class AbstractDriver {
|
|
|
277
289
|
return true;
|
|
278
290
|
if (lowerMessage.includes('529'))
|
|
279
291
|
return true;
|
|
292
|
+
// A transport-level abort (request-timeout / dropped connection) or a
|
|
293
|
+
// deadline-exceeded is transient and should be retried — even when the provider
|
|
294
|
+
// surfaces it under a misleading 4xx status. A deliberate cancellation is raised
|
|
295
|
+
// as a Temporal CancelledFailure (not an LLM error), so it never reaches here.
|
|
296
|
+
if (lowerMessage.includes('aborted'))
|
|
297
|
+
return true;
|
|
298
|
+
if (lowerMessage.includes('deadline'))
|
|
299
|
+
return true;
|
|
300
|
+
// Explicit auth failures should never be retried even when they arrive without
|
|
301
|
+
// a numeric status code (for example, google-auth-library invalid_grant errors).
|
|
302
|
+
if (lowerMessage.includes('invalid_grant'))
|
|
303
|
+
return false;
|
|
304
|
+
if (lowerMessage.includes("credential's issuer"))
|
|
305
|
+
return false;
|
|
306
|
+
// Numeric status codes
|
|
307
|
+
if (statusCode !== undefined) {
|
|
308
|
+
if (statusCode === 429 || statusCode === 408)
|
|
309
|
+
return true; // Rate limit, timeout
|
|
310
|
+
if (statusCode === 529)
|
|
311
|
+
return true; // Overloaded
|
|
312
|
+
if (statusCode >= 500 && statusCode < 600)
|
|
313
|
+
return true; // Server errors
|
|
314
|
+
return false; // 4xx client errors not retryable
|
|
315
|
+
}
|
|
316
|
+
// Message-based detection for non-HTTP errors
|
|
317
|
+
if (lowerMessage.includes('retry'))
|
|
318
|
+
return true;
|
|
280
319
|
// Unknown errors - let consumer decide retry strategy
|
|
281
320
|
return undefined;
|
|
282
321
|
}
|
|
283
322
|
async requestImageGeneration(_prompt, _options) {
|
|
284
|
-
throw new Error(
|
|
323
|
+
throw new Error('Image generation not implemented.');
|
|
285
324
|
//Cannot be made abstract, as abstract methods are required in the derived class
|
|
286
325
|
}
|
|
287
326
|
/**
|
|
288
327
|
* Cleanup method called when the driver is evicted from the cache.
|
|
289
|
-
*
|
|
328
|
+
* Releases the lazily-created HTTP agent socket pool. Override this
|
|
329
|
+
* in driver implementations that need to release additional resources
|
|
330
|
+
* — MUST call `super.destroy()` to avoid leaking sockets.
|
|
290
331
|
*/
|
|
291
332
|
destroy() {
|
|
292
|
-
|
|
333
|
+
this._httpAgent?.close().catch(() => {
|
|
334
|
+
/* shutdown best-effort */
|
|
335
|
+
});
|
|
336
|
+
this._httpAgent = undefined;
|
|
337
|
+
this._driverFetch = undefined;
|
|
293
338
|
}
|
|
294
339
|
}
|
|
295
340
|
//# sourceMappingURL=Driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Driver.js","sourceRoot":"","sources":["../src/Driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { CompletionChunkObject } from '@llumiverse/common';
|
|
2
|
+
import type { ServerSentEvent } from '@vertesia/api-fetch-client';
|
|
3
3
|
export declare function asyncMap<T, R>(asyncIterable: AsyncIterable<T>, callback: (value: T, index: number) => R): AsyncGenerator<Awaited<R>, void, unknown>;
|
|
4
4
|
export declare function oneAsyncIterator<T>(value: T): AsyncIterable<T>;
|
|
5
5
|
/**
|
|
6
6
|
* Given a ReadableStream of server sent events, tran
|
|
7
7
|
*/
|
|
8
8
|
export declare function transformSSEStream(stream: ReadableStream<ServerSentEvent>, transform: (data: string) => CompletionChunkObject): ReadableStream<CompletionChunkObject> & AsyncIterable<CompletionChunkObject>;
|
|
9
|
-
export declare class EventStream<T, ReturnT =
|
|
9
|
+
export declare class EventStream<T, ReturnT = unknown> implements AsyncIterable<T> {
|
|
10
10
|
private queue;
|
|
11
11
|
private pending?;
|
|
12
12
|
private done;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../src/async.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,wBAAuB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,6CAG9G;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAM9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,cAAc,CAAC,eAAe,CAAC,EACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,qBAAqB,GACnD,cAAc,CAAC,qBAAqB,CAAC,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAiB9E;AAED,qBAAa,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAAC,CAGd;IACF,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,KAAK,EAAE,CAAC;IAYb;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO;IAQrB,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CA0BlE;AAED;;;;IAII;AACJ,wBAAuB,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAC9C,iBAAiB,EAAE,aAAa,CAAC,CAAC,CAAC,EACnC,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACvC,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACpC,aAAa,CAAC,CAAC,CAAC,CAOlB"}
|
|
@@ -7,7 +7,7 @@ export function oneAsyncIterator(value) {
|
|
|
7
7
|
return {
|
|
8
8
|
async *[Symbol.asyncIterator]() {
|
|
9
9
|
yield value;
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
@@ -22,12 +22,12 @@ export function transformSSEStream(stream, transform) {
|
|
|
22
22
|
const result = transform(event.data) ?? '';
|
|
23
23
|
controller.enqueue(result);
|
|
24
24
|
}
|
|
25
|
-
catch
|
|
25
|
+
catch {
|
|
26
26
|
// double check for the last event which is not a JSON - at this time togetherai and mistralai returns the string [DONE]
|
|
27
27
|
// do nothing - happens if data is not a JSON - the last event data is the [DONE] string
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
}
|
|
30
|
+
},
|
|
31
31
|
}));
|
|
32
32
|
}
|
|
33
33
|
export class EventStream {
|
|
@@ -82,7 +82,7 @@ export class EventStream {
|
|
|
82
82
|
}
|
|
83
83
|
const _value = await value;
|
|
84
84
|
return { done: true, value: _value };
|
|
85
|
-
}
|
|
85
|
+
},
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
}
|
package/lib/async.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async.js","sourceRoot":"","sources":["../src/async.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAAO,aAA+B,EAAE,QAAwC;IAC3G,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,aAAa;QAAE,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAI,KAAQ;IACxC,OAAO;QACH,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;YACzB,MAAM,KAAK,CAAC;QAChB,CAAC;KACJ,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAC9B,MAAuC,EACvC,SAAkD;IAElD,0DAA0D;IAC1D,OAAO,MAAM,CAAC,WAAW,CACrB,IAAI,eAAe,CAAyC;QACxD,SAAS,CAAC,KAAsB,EAAE,UAAU;YACxC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAClE,IAAI,CAAC;oBACD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC3C,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC/B,CAAC;gBAAC,MAAM,CAAC;oBACL,wHAAwH;oBACxH,wFAAwF;gBAC5F,CAAC;YACL,CAAC;QACL,CAAC;KACJ,CAAC,CACkF,CAAC;AAC7F,CAAC;AAED,MAAM,OAAO,WAAW;IACZ,KAAK,GAAQ,EAAE,CAAC;IAChB,OAAO,CAGb;IACM,IAAI,GAAG,KAAK,CAAC;IAErB,IAAI,CAAC,KAAQ;QACT,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACvC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC7B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAe;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC7B,CAAC;IACL,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,OAAO;YACH,IAAI;gBACA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;oBACrB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACnB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAoB,EAAE,CAAC,CAAC;gBACxE,CAAC;qBAAM,CAAC;oBACJ,OAAO,IAAI,OAAO,CAAyC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;wBAC3E,IAAI,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;oBACvC,CAAC,CAAC,CAAC;gBACP,CAAC;YACL,CAAC;YACD,KAAK,CAAC,MAAM,CAAC,KAAkC;gBAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBAChB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACtB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAoB,EAAE,CAAC;gBACvD,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;gBAC3B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YACzC,CAAC;SACJ,CAAC;IACN,CAAC;CACJ;AAED;;;;IAII;AACJ,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,sBAAsB,CACzC,iBAAmC,EACnC,SAAuC,EACvC,YAAmC;IAEnC,IAAI,YAAY,EAAE,CAAC;QACf,MAAM,YAAY,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,iBAAiB,EAAE,CAAC;QAC1C,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;AACL,CAAC;AAED,0BAA0B;AAC1B,+BAA+B;AAC/B,qDAAqD;AACrD,yBAAyB;AACzB,iBAAiB;AACjB,2CAA2C;AAC3C,uCAAuC;AACvC,2BAA2B;AAC3B,+CAA+C;AAC/C,0DAA0D;AAC1D,mBAAmB;AACnB,4CAA4C;AAC5C,8BAA8B;AAC9B,YAAY;AACZ,gBAAgB;AAChB,IAAI;AAEJ,4CAA4C;AAC5C,sBAAsB;AAEtB,sCAAsC;AACtC,wCAAwC;AACxC,IAAI"}
|
|
@@ -39,6 +39,15 @@ export interface StripOptions {
|
|
|
39
39
|
* - N > 0: Truncate text to approximately N tokens (~4 chars/token)
|
|
40
40
|
*/
|
|
41
41
|
textMaxTokens?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Number of most-recent messages to leave untouched when truncating large
|
|
44
|
+
* text (the active working set). Only messages OLDER than the last
|
|
45
|
+
* `keepRecentMessages` entries get their large strings truncated to
|
|
46
|
+
* `textMaxTokens`. Requires a conversation with a `messages` array.
|
|
47
|
+
* - undefined/0: No turn awareness — truncate every large string (legacy).
|
|
48
|
+
* - N > 0: Keep the last N messages full; truncate older ones.
|
|
49
|
+
*/
|
|
50
|
+
keepRecentMessages?: number;
|
|
42
51
|
}
|
|
43
52
|
/**
|
|
44
53
|
* Get metadata from a conversation object, or return defaults.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-utils.d.ts","sourceRoot":"","sources":["../src/conversation-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AA+JD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,OAAO,GAAG,gBAAgB,CAQ3E;AAKD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAS1F;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,GAAG,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,SAAS,CAQ3F;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAGxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAYzF;AA2BD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAwBlE;AAkDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAW/F;AAmDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B7F;AAuHD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAe7F"}
|
|
@@ -129,9 +129,7 @@ function isOpenAIBase64ImageBlock(obj) {
|
|
|
129
129
|
if (!o.image_url || typeof o.image_url !== 'object')
|
|
130
130
|
return false;
|
|
131
131
|
const imgUrl = o.image_url;
|
|
132
|
-
return typeof imgUrl.url === 'string' &&
|
|
133
|
-
imgUrl.url.startsWith('data:image/') &&
|
|
134
|
-
imgUrl.url.includes(';base64,');
|
|
132
|
+
return typeof imgUrl.url === 'string' && imgUrl.url.startsWith('data:image/') && imgUrl.url.includes(';base64,');
|
|
135
133
|
}
|
|
136
134
|
/**
|
|
137
135
|
* Check if an object is an Anthropic base64 image block: { type: "image", source: { type: "base64", data: "...", media_type: "..." } }
|
|
@@ -280,7 +278,7 @@ function serializeBinaryForStorage(obj) {
|
|
|
280
278
|
return { _base64: uint8ArrayToBase64(obj) };
|
|
281
279
|
}
|
|
282
280
|
if (Array.isArray(obj)) {
|
|
283
|
-
return obj.map(item => serializeBinaryForStorage(item));
|
|
281
|
+
return obj.map((item) => serializeBinaryForStorage(item));
|
|
284
282
|
}
|
|
285
283
|
if (typeof obj === 'object') {
|
|
286
284
|
const result = {};
|
|
@@ -306,7 +304,7 @@ export function deserializeBinaryFromStorage(obj) {
|
|
|
306
304
|
}
|
|
307
305
|
}
|
|
308
306
|
if (Array.isArray(obj)) {
|
|
309
|
-
return obj.map(item => deserializeBinaryFromStorage(item));
|
|
307
|
+
return obj.map((item) => deserializeBinaryFromStorage(item));
|
|
310
308
|
}
|
|
311
309
|
if (typeof obj === 'object') {
|
|
312
310
|
const result = {};
|
|
@@ -332,7 +330,7 @@ function stripBinaryFromConversationInternal(obj) {
|
|
|
332
330
|
}
|
|
333
331
|
}
|
|
334
332
|
if (Array.isArray(obj)) {
|
|
335
|
-
return obj.map(item => {
|
|
333
|
+
return obj.map((item) => {
|
|
336
334
|
// Replace entire Bedrock image/document/video blocks with text blocks
|
|
337
335
|
if (isBedrockImageBlock(item) || isSerializedBedrockImageBlock(item)) {
|
|
338
336
|
return { text: IMAGE_PLACEHOLDER };
|
|
@@ -392,7 +390,7 @@ function stripBase64ImagesFromConversationInternal(obj) {
|
|
|
392
390
|
return IMAGE_PLACEHOLDER;
|
|
393
391
|
}
|
|
394
392
|
if (Array.isArray(obj)) {
|
|
395
|
-
return obj.map(item => {
|
|
393
|
+
return obj.map((item) => {
|
|
396
394
|
// Replace entire OpenAI image_url blocks with text blocks
|
|
397
395
|
if (isOpenAIBase64ImageBlock(item)) {
|
|
398
396
|
return { type: 'text', text: IMAGE_PLACEHOLDER };
|
|
@@ -451,24 +449,78 @@ export function truncateLargeTextInConversation(obj, options) {
|
|
|
451
449
|
return obj;
|
|
452
450
|
}
|
|
453
451
|
const maxChars = maxTokens * CHARS_PER_TOKEN;
|
|
452
|
+
const keepRecent = options?.keepRecentMessages;
|
|
453
|
+
// Turn-aware path: keep the most recent `keepRecent` messages untouched (the
|
|
454
|
+
// agent's active working set — the file it just read/wrote, latest
|
|
455
|
+
// diagnostics) and truncate large strings only in older messages. This lets
|
|
456
|
+
// callers use an aggressive cap without blinding the model to current work.
|
|
457
|
+
if (keepRecent && keepRecent > 0) {
|
|
458
|
+
const messages = getConversationMessages(obj);
|
|
459
|
+
if (messages && messages.length > keepRecent) {
|
|
460
|
+
const cutoff = messages.length - keepRecent;
|
|
461
|
+
const truncated = messages.map((m, i) => (i < cutoff ? truncateLargeTextInternal(m, maxChars) : m));
|
|
462
|
+
return setConversationMessages(obj, truncated);
|
|
463
|
+
}
|
|
464
|
+
// No identifiable messages array, or short conversation: leave it full.
|
|
465
|
+
return obj;
|
|
466
|
+
}
|
|
467
|
+
// Legacy path: truncate every large string in the conversation.
|
|
454
468
|
return truncateLargeTextInternal(obj, maxChars);
|
|
455
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Extract the message history array from a conversation object, handling the
|
|
472
|
+
* `{ messages: [...] }` shape (Claude/OpenAI), the wrapped-array shape, and a
|
|
473
|
+
* plain array. Returns undefined when no message array is identifiable.
|
|
474
|
+
*/
|
|
475
|
+
function getConversationMessages(obj) {
|
|
476
|
+
if (Array.isArray(obj))
|
|
477
|
+
return obj;
|
|
478
|
+
const wrapped = unwrapConversationArray(obj);
|
|
479
|
+
if (wrapped)
|
|
480
|
+
return wrapped;
|
|
481
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
482
|
+
const messages = obj.messages;
|
|
483
|
+
if (Array.isArray(messages))
|
|
484
|
+
return messages;
|
|
485
|
+
}
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Rebuild a conversation with a new message array, matching the shape returned
|
|
490
|
+
* by getConversationMessages.
|
|
491
|
+
*/
|
|
492
|
+
function setConversationMessages(obj, messages) {
|
|
493
|
+
if (Array.isArray(obj))
|
|
494
|
+
return messages;
|
|
495
|
+
if (unwrapConversationArray(obj)) {
|
|
496
|
+
return { ...obj, [ARRAY_WRAPPER_KEY]: messages };
|
|
497
|
+
}
|
|
498
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
499
|
+
return { ...obj, messages };
|
|
500
|
+
}
|
|
501
|
+
return obj;
|
|
502
|
+
}
|
|
456
503
|
function shouldPreserveMediaPayload(obj) {
|
|
457
504
|
if (typeof obj !== 'object' || obj === null)
|
|
458
505
|
return false;
|
|
459
506
|
const o = obj;
|
|
460
507
|
// Preserved Bedrock binary blocks and their serialized storage wrapper.
|
|
461
|
-
if (isBedrockImageBlock(obj) ||
|
|
462
|
-
|
|
463
|
-
|
|
508
|
+
if (isBedrockImageBlock(obj) ||
|
|
509
|
+
isSerializedBedrockImageBlock(obj) ||
|
|
510
|
+
isBedrockDocumentBlock(obj) ||
|
|
511
|
+
isSerializedBedrockDocumentBlock(obj) ||
|
|
512
|
+
isBedrockVideoBlock(obj) ||
|
|
513
|
+
isSerializedBedrockVideoBlock(obj)) {
|
|
464
514
|
return true;
|
|
465
515
|
}
|
|
466
516
|
if (typeof o._base64 === 'string' && Object.keys(o).length === 1) {
|
|
467
517
|
return true;
|
|
468
518
|
}
|
|
469
519
|
// Preserved base64 media payloads for OpenAI, Gemini, and Anthropic/Claude.
|
|
470
|
-
if (isOpenAIBase64ImageBlock(obj) ||
|
|
471
|
-
|
|
520
|
+
if (isOpenAIBase64ImageBlock(obj) ||
|
|
521
|
+
isGeminiInlineDataBlock(obj) ||
|
|
522
|
+
isAnthropicBase64ImageBlock(obj) ||
|
|
523
|
+
isAnthropicBase64DocumentBlock(obj)) {
|
|
472
524
|
return true;
|
|
473
525
|
}
|
|
474
526
|
return false;
|
|
@@ -482,12 +534,23 @@ function truncateLargeTextInternal(obj, maxChars) {
|
|
|
482
534
|
return obj;
|
|
483
535
|
}
|
|
484
536
|
if (obj.length > maxChars) {
|
|
485
|
-
|
|
537
|
+
// Don't cut through a surrogate pair: substring() slices at a UTF-16
|
|
538
|
+
// code-unit index, so a boundary that lands between the two halves of
|
|
539
|
+
// a non-BMP character (emoji, CJK-ext, …) leaves a lone high surrogate.
|
|
540
|
+
// That is invalid Unicode — it can't be UTF-8 encoded losslessly and
|
|
541
|
+
// strict JSON parsers (e.g. Vertex/Gemini) reject the request body as
|
|
542
|
+
// "The input data is not valid json". Step back one unit in that case.
|
|
543
|
+
let end = maxChars;
|
|
544
|
+
const lastUnit = obj.charCodeAt(end - 1);
|
|
545
|
+
if (lastUnit >= 0xd800 && lastUnit <= 0xdbff) {
|
|
546
|
+
end -= 1;
|
|
547
|
+
}
|
|
548
|
+
return obj.substring(0, end) + TEXT_TRUNCATED_MARKER;
|
|
486
549
|
}
|
|
487
550
|
return obj;
|
|
488
551
|
}
|
|
489
552
|
if (Array.isArray(obj)) {
|
|
490
|
-
return obj.map(item => truncateLargeTextInternal(item, maxChars));
|
|
553
|
+
return obj.map((item) => truncateLargeTextInternal(item, maxChars));
|
|
491
554
|
}
|
|
492
555
|
if (typeof obj === 'object') {
|
|
493
556
|
if (shouldPreserveMediaPayload(obj)) {
|
|
@@ -548,7 +611,7 @@ function stripHeartbeatsInternal(obj) {
|
|
|
548
611
|
return obj;
|
|
549
612
|
}
|
|
550
613
|
if (Array.isArray(obj)) {
|
|
551
|
-
return obj.map(item => stripHeartbeatsInternal(item));
|
|
614
|
+
return obj.map((item) => stripHeartbeatsInternal(item));
|
|
552
615
|
}
|
|
553
616
|
if (typeof obj === 'object') {
|
|
554
617
|
const result = {};
|