@juspay/neurolink 12.49.13 → 12.49.15
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/CHANGELOG.md +2 -2
- package/dist/browser/neurolink.min.js +411 -421
- package/dist/cli/factories/commandFactory.d.ts +12 -0
- package/dist/cli/factories/commandFactory.js +11 -1
- package/dist/constants/bedrockIdentifiers.d.ts +16 -0
- package/dist/constants/bedrockIdentifiers.js +79 -0
- package/dist/constants/contextWindows.d.ts +6 -15
- package/dist/constants/contextWindows.js +18 -52
- package/dist/constants/enums.d.ts +12 -0
- package/dist/constants/enums.js +15 -0
- package/dist/constants/tokens.js +9 -0
- package/dist/core/loopEngine.js +8 -0
- package/dist/providers/amazonBedrock/client.js +3 -0
- package/dist/providers/amazonBedrock/inferenceProfile.js +9 -5
- package/dist/providers/catalog/abliteration.json +85 -0
- package/dist/providers/catalog/aihubmix.json +77 -0
- package/dist/providers/catalog/api-route.json +1 -1
- package/dist/providers/catalog/baseten.json +1 -1
- package/dist/providers/catalog/deepseek.json +1 -1
- package/dist/providers/catalog/gmicloud.json +1 -1
- package/dist/providers/catalog/huggingface.json +1 -1
- package/dist/providers/catalog/inception-labs.json +1 -1
- package/dist/providers/catalog/index.generated.d.ts +1 -1
- package/dist/providers/catalog/index.generated.js +9 -0
- package/dist/providers/catalog/io-intelligence.json +1 -1
- package/dist/providers/catalog/loader.js +3 -0
- package/dist/providers/catalog/mancer.json +1 -1
- package/dist/providers/catalog/morph.json +1 -1
- package/dist/providers/catalog/naver-clova-studio.json +68 -0
- package/dist/providers/catalog/novita.json +1 -1
- package/dist/providers/catalog/provider-catalog.schema.json +27 -4
- package/dist/providers/catalog/schema.d.ts +3 -1
- package/dist/providers/catalog/schema.js +15 -2
- package/dist/providers/catalog/upstage.json +1 -1
- package/dist/providers/cohere.js +7 -2
- package/dist/providers/configuredOpenAICompat.js +7 -0
- package/dist/providers/embeddingResponseParsing.d.ts +15 -0
- package/dist/providers/embeddingResponseParsing.js +4 -3
- package/dist/providers/googleAiStudio/client.js +104 -26
- package/dist/rag/chunking/htmlChunker.js +4 -11
- package/dist/rag/document/loaders.js +12 -14
- package/dist/server/openapi/generator.d.ts +0 -6
- package/dist/server/openapi/generator.js +2 -72
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/loopEngine.d.ts +7 -0
- package/dist/types/providerCatalog.d.ts +15 -1
- package/dist/types/providerCatalog.generated.d.ts +2 -2
- package/dist/types/providers.d.ts +15 -0
- package/dist/types/safeFetch.d.ts +1 -1
- package/dist/utils/htmlEntities.d.ts +8 -0
- package/dist/utils/htmlEntities.js +29 -0
- package/dist/utils/safeFetch.js +11 -3
- package/dist/utils/tokenLimits.js +23 -4
- package/docs-site/static/search-index.json +27 -16
- package/package.json +5 -3
|
@@ -7,6 +7,7 @@ import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, Ra
|
|
|
7
7
|
import { ERROR_CODES, NeuroLinkError } from "../../utils/errorHandling.js";
|
|
8
8
|
import { logger } from "../../utils/logger.js";
|
|
9
9
|
import { drainDetachedPump } from "../../utils/drainDetachedPump.js";
|
|
10
|
+
import { attachStreamCancel, cancelStream, releaseIterator, } from "../../utils/streamCancellation.js";
|
|
10
11
|
import { createGeminiLoopAdapter } from "../../core/geminiLoopAdapter.js";
|
|
11
12
|
import { isDirectTTSRequest } from "../../core/resolveRequestKind.js";
|
|
12
13
|
import { runAgenticLoop } from "../../core/loopEngine.js";
|
|
@@ -2186,21 +2187,58 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
2186
2187
|
"gemini-2.5-flash-preview-native-audio-dialog";
|
|
2187
2188
|
// Simple async queue for yielding audio events to the outer AsyncIterable
|
|
2188
2189
|
const queue = [];
|
|
2189
|
-
let
|
|
2190
|
+
let notifyNext = null;
|
|
2190
2191
|
let done = false;
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2192
|
+
let terminalQueued = false;
|
|
2193
|
+
let cleanupRequested = false;
|
|
2194
|
+
let liveSession = undefined;
|
|
2195
|
+
let sessionCloseIssued = false;
|
|
2196
|
+
let inputIterator;
|
|
2197
|
+
let removeAbortListener = () => undefined;
|
|
2198
|
+
const wake = () => {
|
|
2199
|
+
const notify = notifyNext;
|
|
2200
|
+
notifyNext = null;
|
|
2201
|
+
notify?.();
|
|
2202
|
+
};
|
|
2203
|
+
const cleanup = () => {
|
|
2204
|
+
if (!cleanupRequested) {
|
|
2205
|
+
cleanupRequested = true;
|
|
2206
|
+
removeAbortListener();
|
|
2207
|
+
cancelStream(options.input?.audio?.frames);
|
|
2208
|
+
if (inputIterator) {
|
|
2209
|
+
releaseIterator(inputIterator);
|
|
2210
|
+
inputIterator = undefined;
|
|
2211
|
+
}
|
|
2194
2212
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2213
|
+
// A close callback can run just before connect() yields its session.
|
|
2214
|
+
// Keep cleanup repeatable so that newly acquired handle is still closed.
|
|
2215
|
+
if (liveSession && !sessionCloseIssued) {
|
|
2216
|
+
sessionCloseIssued = true;
|
|
2217
|
+
try {
|
|
2218
|
+
void Promise.resolve(liveSession.close?.()).catch(() => { });
|
|
2219
|
+
}
|
|
2220
|
+
catch {
|
|
2221
|
+
// Cleanup cannot replace the stream's original outcome.
|
|
2201
2222
|
}
|
|
2202
2223
|
}
|
|
2224
|
+
};
|
|
2225
|
+
const push = (item) => {
|
|
2226
|
+
if (done || terminalQueued) {
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2203
2229
|
queue.push(item);
|
|
2230
|
+
if (item.type !== "audio") {
|
|
2231
|
+
terminalQueued = true;
|
|
2232
|
+
cleanup();
|
|
2233
|
+
}
|
|
2234
|
+
// A consumer can already be parked before either end or error arrives.
|
|
2235
|
+
wake();
|
|
2236
|
+
};
|
|
2237
|
+
const cancel = () => {
|
|
2238
|
+
done = true;
|
|
2239
|
+
queue.length = 0;
|
|
2240
|
+
cleanup();
|
|
2241
|
+
wake();
|
|
2204
2242
|
};
|
|
2205
2243
|
// @google/genai 2.x waits inside connect() for the server's setupComplete
|
|
2206
2244
|
// message and does not reject when the socket errors or closes first, so a
|
|
@@ -2219,6 +2257,9 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
2219
2257
|
// no-op
|
|
2220
2258
|
},
|
|
2221
2259
|
onmessage: async (message) => {
|
|
2260
|
+
if (done || terminalQueued) {
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2222
2263
|
try {
|
|
2223
2264
|
const audio = message?.serverContent?.modelTurn?.parts?.[0]?.inlineData;
|
|
2224
2265
|
if (audio?.data) {
|
|
@@ -2260,16 +2301,50 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
2260
2301
|
},
|
|
2261
2302
|
});
|
|
2262
2303
|
const session = await Promise.race([connecting, connectFailed]);
|
|
2304
|
+
liveSession = session;
|
|
2263
2305
|
sessionOpen = true;
|
|
2306
|
+
if (cleanupRequested) {
|
|
2307
|
+
cleanup();
|
|
2308
|
+
}
|
|
2309
|
+
const signal = options.abortSignal;
|
|
2310
|
+
if (signal && !cleanupRequested) {
|
|
2311
|
+
const onAbort = () => {
|
|
2312
|
+
push({
|
|
2313
|
+
type: "error",
|
|
2314
|
+
error: signal.reason instanceof Error
|
|
2315
|
+
? signal.reason
|
|
2316
|
+
: new DOMException("The operation was aborted", "AbortError"),
|
|
2317
|
+
});
|
|
2318
|
+
};
|
|
2319
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2320
|
+
removeAbortListener = () => signal.removeEventListener("abort", onAbort);
|
|
2321
|
+
if (signal.aborted) {
|
|
2322
|
+
onAbort();
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2264
2325
|
// Feed upstream audio frames concurrently
|
|
2265
2326
|
(async () => {
|
|
2266
2327
|
try {
|
|
2328
|
+
if (cleanupRequested) {
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2267
2331
|
const spec = options.input?.audio;
|
|
2268
2332
|
if (!spec) {
|
|
2269
2333
|
logger.debug("[GeminiLive] No audio spec found on input; skipping upstream send");
|
|
2270
2334
|
return;
|
|
2271
2335
|
}
|
|
2272
|
-
|
|
2336
|
+
const framesIterator = spec.frames[Symbol.asyncIterator]();
|
|
2337
|
+
inputIterator = framesIterator;
|
|
2338
|
+
while (!cleanupRequested) {
|
|
2339
|
+
const nextFrame = await framesIterator.next();
|
|
2340
|
+
if (cleanupRequested) {
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
if (nextFrame.done) {
|
|
2344
|
+
inputIterator = undefined;
|
|
2345
|
+
break;
|
|
2346
|
+
}
|
|
2347
|
+
const frame = nextFrame.value;
|
|
2273
2348
|
// Zero-length frame acts as a 'flush' control signal
|
|
2274
2349
|
if (!frame || frame.byteLength === 0) {
|
|
2275
2350
|
try {
|
|
@@ -2294,6 +2369,9 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
2294
2369
|
media: { data: base64, mimeType },
|
|
2295
2370
|
});
|
|
2296
2371
|
}
|
|
2372
|
+
if (cleanupRequested) {
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2297
2375
|
// Best-effort flush signal if supported
|
|
2298
2376
|
try {
|
|
2299
2377
|
if (session.sendInput) {
|
|
@@ -2320,40 +2398,40 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
2320
2398
|
[Symbol.asyncIterator]() {
|
|
2321
2399
|
return {
|
|
2322
2400
|
async next() {
|
|
2323
|
-
|
|
2401
|
+
while (true) {
|
|
2324
2402
|
const item = queue.shift();
|
|
2325
|
-
if (
|
|
2326
|
-
// `done: true` selects the IteratorReturnResult arm, whose
|
|
2327
|
-
// value type accepts undefined.
|
|
2328
|
-
return { value: undefined, done: true };
|
|
2329
|
-
}
|
|
2330
|
-
if (item.type === "audio") {
|
|
2403
|
+
if (item?.type === "audio") {
|
|
2331
2404
|
return {
|
|
2332
2405
|
value: { type: "audio", audio: item.audio },
|
|
2333
2406
|
done: false,
|
|
2334
2407
|
};
|
|
2335
2408
|
}
|
|
2336
|
-
if (item
|
|
2409
|
+
if (item?.type === "end") {
|
|
2337
2410
|
done = true;
|
|
2338
2411
|
return { value: undefined, done: true };
|
|
2339
2412
|
}
|
|
2340
|
-
if (item
|
|
2413
|
+
if (item?.type === "error") {
|
|
2341
2414
|
done = true;
|
|
2342
2415
|
throw item.error instanceof Error
|
|
2343
2416
|
? item.error
|
|
2344
2417
|
: new Error(String(item.error));
|
|
2345
2418
|
}
|
|
2419
|
+
if (done) {
|
|
2420
|
+
return { value: undefined, done: true };
|
|
2421
|
+
}
|
|
2422
|
+
await new Promise((resolve) => {
|
|
2423
|
+
notifyNext = resolve;
|
|
2424
|
+
});
|
|
2346
2425
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
return
|
|
2351
|
-
resolveNext = resolve;
|
|
2352
|
-
});
|
|
2426
|
+
},
|
|
2427
|
+
async return() {
|
|
2428
|
+
cancel();
|
|
2429
|
+
return { value: undefined, done: true };
|
|
2353
2430
|
},
|
|
2354
2431
|
};
|
|
2355
2432
|
},
|
|
2356
2433
|
};
|
|
2434
|
+
attachStreamCancel(asyncIterable, cancel);
|
|
2357
2435
|
return {
|
|
2358
2436
|
stream: asyncIterable,
|
|
2359
2437
|
provider: this.providerName,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Best for web pages, email templates, and structured HTML content.
|
|
6
6
|
*/
|
|
7
7
|
import { randomUUID } from "crypto";
|
|
8
|
+
import { decodeHtmlTextEntitiesOnce } from "../../utils/htmlEntities.js";
|
|
8
9
|
/**
|
|
9
10
|
* HTML-aware chunker implementation
|
|
10
11
|
* Splits based on HTML structure (tags, elements)
|
|
@@ -170,7 +171,7 @@ export class HTMLChunker {
|
|
|
170
171
|
* Extract plain text from HTML
|
|
171
172
|
*/
|
|
172
173
|
extractText(html) {
|
|
173
|
-
return (html
|
|
174
|
+
return decodeHtmlTextEntitiesOnce(html
|
|
174
175
|
// Remove script and style elements
|
|
175
176
|
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
176
177
|
.replace(/<style[\s\S]*?<\/style>/gi, "")
|
|
@@ -179,17 +180,9 @@ export class HTMLChunker {
|
|
|
179
180
|
// Replace block elements with newlines
|
|
180
181
|
.replace(/<\/(p|div|br|h[1-6]|li|tr)>/gi, "\n")
|
|
181
182
|
// Remove remaining tags
|
|
182
|
-
.replace(/<[^>]+>/g, "")
|
|
183
|
-
// Decode common HTML entities
|
|
184
|
-
.replace(/ /gi, " ")
|
|
185
|
-
.replace(/&/gi, "&")
|
|
186
|
-
.replace(/</gi, "<")
|
|
187
|
-
.replace(/>/gi, ">")
|
|
188
|
-
.replace(/"/gi, '"')
|
|
189
|
-
.replace(/'/gi, "'")
|
|
190
|
-
// Normalize whitespace
|
|
183
|
+
.replace(/<[^>]+>/g, ""), { nbsp: " ", amp: "&", lt: "<", gt: ">", quot: '"', "#039": "'" })
|
|
191
184
|
.replace(/\s+/g, " ")
|
|
192
|
-
.trim()
|
|
185
|
+
.trim();
|
|
193
186
|
}
|
|
194
187
|
/**
|
|
195
188
|
* Split content that exceeds max size
|
|
@@ -27,6 +27,7 @@ import { existsSync } from "fs";
|
|
|
27
27
|
import { readFile } from "fs/promises";
|
|
28
28
|
import { basename, extname } from "path";
|
|
29
29
|
import { logger } from "../../utils/logger.js";
|
|
30
|
+
import { decodeHtmlTextEntitiesOnce } from "../../utils/htmlEntities.js";
|
|
30
31
|
import { CSVProcessor, stripBom, stripMetadataLine, splitCsvLines, dedupeColumnNames, sanitizeColumnName, } from "../../utils/csvProcessor.js";
|
|
31
32
|
import { splitCSVFields } from "../../utils/csvUtils.js";
|
|
32
33
|
import { MDocument } from "./MDocument.js";
|
|
@@ -428,7 +429,7 @@ export class WebLoader {
|
|
|
428
429
|
* Convert HTML to plain text
|
|
429
430
|
*/
|
|
430
431
|
htmlToText(html) {
|
|
431
|
-
return (html
|
|
432
|
+
return decodeHtmlTextEntitiesOnce(html
|
|
432
433
|
// Remove script and style elements
|
|
433
434
|
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
434
435
|
.replace(/<style[\s\S]*?<\/style>/gi, "")
|
|
@@ -438,21 +439,18 @@ export class WebLoader {
|
|
|
438
439
|
.replace(/<\/(p|div|h[1-6]|br|li|tr|blockquote)>/gi, "\n")
|
|
439
440
|
.replace(/<(br|hr)\s*\/?>/gi, "\n")
|
|
440
441
|
// Remove remaining tags
|
|
441
|
-
.replace(/<[^>]+>/g, "")
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// Decode numeric entities
|
|
451
|
-
.replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code)))
|
|
452
|
-
// Normalize whitespace
|
|
442
|
+
.replace(/<[^>]+>/g, ""), {
|
|
443
|
+
nbsp: " ",
|
|
444
|
+
amp: "&",
|
|
445
|
+
lt: "<",
|
|
446
|
+
gt: ">",
|
|
447
|
+
quot: '"',
|
|
448
|
+
"#039": "'",
|
|
449
|
+
apos: "'",
|
|
450
|
+
}, true)
|
|
453
451
|
.replace(/\n\s*\n/g, "\n\n")
|
|
454
452
|
.replace(/[ \t]+/g, " ")
|
|
455
|
-
.trim()
|
|
453
|
+
.trim();
|
|
456
454
|
}
|
|
457
455
|
}
|
|
458
456
|
/**
|
|
@@ -29,7 +29,6 @@ export declare class OpenAPIGenerator {
|
|
|
29
29
|
toJSON(pretty?: boolean): string;
|
|
30
30
|
/**
|
|
31
31
|
* Generate OpenAPI spec as YAML string
|
|
32
|
-
* Note: For full YAML support, use a YAML library
|
|
33
32
|
*/
|
|
34
33
|
toYAML(): string;
|
|
35
34
|
private generateInfo;
|
|
@@ -41,11 +40,6 @@ export declare class OpenAPIGenerator {
|
|
|
41
40
|
private generateComponents;
|
|
42
41
|
private convertPath;
|
|
43
42
|
private extractPathParameters;
|
|
44
|
-
/**
|
|
45
|
-
* Simple JSON to YAML converter
|
|
46
|
-
* For production use, consider using a proper YAML library
|
|
47
|
-
*/
|
|
48
|
-
private jsonToYaml;
|
|
49
43
|
}
|
|
50
44
|
/**
|
|
51
45
|
* Create an OpenAPI generator with default configuration
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* OpenAPI 3.1 Specification Generator
|
|
3
3
|
* Generates OpenAPI documentation from NeuroLink server routes
|
|
4
4
|
*/
|
|
5
|
+
import { dump } from "js-yaml";
|
|
5
6
|
import { OpenAPISchemas } from "./schemas.js";
|
|
6
7
|
import { CommonParameters, createDeleteOperation, createGetOperation, createPostOperation, createStreamingPostOperation, DefaultServers, NeuroLinkApiInfo, StandardErrorResponses, StandardTags, BearerSecurityScheme, ApiKeySecurityScheme, } from "./templates.js";
|
|
7
8
|
// ============================================
|
|
@@ -63,11 +64,9 @@ export class OpenAPIGenerator {
|
|
|
63
64
|
}
|
|
64
65
|
/**
|
|
65
66
|
* Generate OpenAPI spec as YAML string
|
|
66
|
-
* Note: For full YAML support, use a YAML library
|
|
67
67
|
*/
|
|
68
68
|
toYAML() {
|
|
69
|
-
|
|
70
|
-
return this.jsonToYaml(spec);
|
|
69
|
+
return dump(this.generate(), { noRefs: true, lineWidth: -1 });
|
|
71
70
|
}
|
|
72
71
|
// ============================================
|
|
73
72
|
// Private Methods
|
|
@@ -291,75 +290,6 @@ export class OpenAPIGenerator {
|
|
|
291
290
|
}
|
|
292
291
|
return params;
|
|
293
292
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Simple JSON to YAML converter
|
|
296
|
-
* For production use, consider using a proper YAML library
|
|
297
|
-
*/
|
|
298
|
-
jsonToYaml(obj, indent = 0) {
|
|
299
|
-
const spaces = " ".repeat(indent);
|
|
300
|
-
if (obj === null || obj === undefined) {
|
|
301
|
-
return "null";
|
|
302
|
-
}
|
|
303
|
-
if (typeof obj === "boolean" || typeof obj === "number") {
|
|
304
|
-
return String(obj);
|
|
305
|
-
}
|
|
306
|
-
if (typeof obj === "string") {
|
|
307
|
-
// Check if string needs quotes
|
|
308
|
-
if (obj.includes("\n") ||
|
|
309
|
-
obj.includes(":") ||
|
|
310
|
-
obj.includes("#") ||
|
|
311
|
-
obj.includes("'") ||
|
|
312
|
-
obj.includes('"') ||
|
|
313
|
-
obj.startsWith(" ") ||
|
|
314
|
-
obj.endsWith(" ")) {
|
|
315
|
-
// Use block scalar for multiline
|
|
316
|
-
if (obj.includes("\n")) {
|
|
317
|
-
const lines = obj.split("\n");
|
|
318
|
-
return `|\n${lines.map((line) => spaces + " " + line).join("\n")}`;
|
|
319
|
-
}
|
|
320
|
-
return `"${obj.replace(/"/g, '\\"')}"`;
|
|
321
|
-
}
|
|
322
|
-
return obj;
|
|
323
|
-
}
|
|
324
|
-
if (Array.isArray(obj)) {
|
|
325
|
-
if (obj.length === 0) {
|
|
326
|
-
return "[]";
|
|
327
|
-
}
|
|
328
|
-
return obj
|
|
329
|
-
.map((item) => {
|
|
330
|
-
const itemYaml = this.jsonToYaml(item, indent + 1);
|
|
331
|
-
if (typeof item === "object" && item !== null) {
|
|
332
|
-
return `${spaces}- ${itemYaml
|
|
333
|
-
.trim()
|
|
334
|
-
.replace(/^\s+/gm, (match) => spaces + " " + match.trim() + "\n")
|
|
335
|
-
.trim()}`;
|
|
336
|
-
}
|
|
337
|
-
return `${spaces}- ${itemYaml}`;
|
|
338
|
-
})
|
|
339
|
-
.join("\n");
|
|
340
|
-
}
|
|
341
|
-
if (typeof obj === "object") {
|
|
342
|
-
const entries = Object.entries(obj);
|
|
343
|
-
if (entries.length === 0) {
|
|
344
|
-
return "{}";
|
|
345
|
-
}
|
|
346
|
-
return entries
|
|
347
|
-
.map(([key, value]) => {
|
|
348
|
-
const valueYaml = this.jsonToYaml(value, indent + 1);
|
|
349
|
-
if (typeof value === "object" &&
|
|
350
|
-
value !== null &&
|
|
351
|
-
!Array.isArray(value)) {
|
|
352
|
-
return `${spaces}${key}:\n${valueYaml}`;
|
|
353
|
-
}
|
|
354
|
-
if (Array.isArray(value)) {
|
|
355
|
-
return `${spaces}${key}:\n${valueYaml}`;
|
|
356
|
-
}
|
|
357
|
-
return `${spaces}${key}: ${valueYaml}`;
|
|
358
|
-
})
|
|
359
|
-
.join("\n");
|
|
360
|
-
}
|
|
361
|
-
return String(obj);
|
|
362
|
-
}
|
|
363
293
|
}
|
|
364
294
|
// ============================================
|
|
365
295
|
// Factory Functions
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -70,6 +70,8 @@ export type GenerateCommandArgs = BaseCommandArgs & CliToolRoutingFlags & CliCla
|
|
|
70
70
|
context?: string;
|
|
71
71
|
/** Disable tools */
|
|
72
72
|
disableTools?: boolean;
|
|
73
|
+
/** Keep the request on the selected provider and model. */
|
|
74
|
+
disableInternalFallback?: boolean;
|
|
73
75
|
/** Maximum steps for multi-turn */
|
|
74
76
|
maxSteps?: number;
|
|
75
77
|
/** Output file */
|
|
@@ -133,6 +135,8 @@ export type StreamCommandArgs = BaseCommandArgs & CliToolRoutingFlags & CliClass
|
|
|
133
135
|
maxTokens?: number;
|
|
134
136
|
/** Disable tools */
|
|
135
137
|
disableTools?: boolean;
|
|
138
|
+
/** Keep the request on the selected provider and model. */
|
|
139
|
+
disableInternalFallback?: boolean;
|
|
136
140
|
/** Enable extended thinking/reasoning */
|
|
137
141
|
thinking?: boolean;
|
|
138
142
|
/** Token budget for thinking */
|
|
@@ -164,6 +168,8 @@ export type BatchCommandArgs = BaseCommandArgs & CliToolRoutingFlags & CliClassi
|
|
|
164
168
|
output?: string;
|
|
165
169
|
/** Disable tools */
|
|
166
170
|
disableTools?: boolean;
|
|
171
|
+
/** Keep the request on the selected provider and model. */
|
|
172
|
+
disableInternalFallback?: boolean;
|
|
167
173
|
};
|
|
168
174
|
/**
|
|
169
175
|
* MCP command arguments - Enhanced with transport and server management
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import type { Span } from "@opentelemetry/api";
|
|
3
3
|
import type { Tool } from "./tools.js";
|
|
4
|
+
import type { GenerateStopReason } from "./generate.js";
|
|
4
5
|
import type { CollectedChunkResult, NativeFunctionCall, NativeToolDeclarationsResult } from "./providers.js";
|
|
5
6
|
import type { ExecutionControlDecision, ExecutionControlStepContext } from "./stream.js";
|
|
6
7
|
/**
|
|
@@ -603,6 +604,12 @@ export type AgenticLoopResult<TConversation> = {
|
|
|
603
604
|
usage: AgenticLoopUsage;
|
|
604
605
|
finishReason: string;
|
|
605
606
|
rawStopReason: string | undefined;
|
|
607
|
+
/**
|
|
608
|
+
* A known engine-owned termination condition, distinct from the provider's
|
|
609
|
+
* raw reason. Optional for adapters/fixtures that predate this field; the
|
|
610
|
+
* engine reports step-cap or aborted when it has observed that condition.
|
|
611
|
+
*/
|
|
612
|
+
stopReason?: GenerateStopReason;
|
|
606
613
|
conversation: TConversation;
|
|
607
614
|
/**
|
|
608
615
|
* True when the turn ended because its abort signal fired rather than
|
|
@@ -91,6 +91,10 @@ export type CatalogQuirks = {
|
|
|
91
91
|
* without it once tools are in play). ConfiguredOpenAICompatProvider
|
|
92
92
|
* turns on the replay; every other provider leaves the field off. */
|
|
93
93
|
replayReasoningContent?: boolean;
|
|
94
|
+
/** The endpoint accepts auto/none/named tool choices but not required.
|
|
95
|
+
* Reject that explicit caller intent with nonempty tools before sending;
|
|
96
|
+
* never silently downgrade it to auto. Omitted preserves existing behavior. */
|
|
97
|
+
rejectRequiredToolChoice?: boolean;
|
|
94
98
|
/** Vendor's chat-completions endpoint authenticates with a vendor-specific
|
|
95
99
|
* header instead of the OpenAI-standard `Authorization: Bearer <key>`.
|
|
96
100
|
* "x-api-key": send `X-Api-Key: <key>` and omit Authorization entirely —
|
|
@@ -101,7 +105,9 @@ export type CatalogQuirks = {
|
|
|
101
105
|
* inherited Bearer default. */
|
|
102
106
|
authHeaderStyle?: "x-api-key";
|
|
103
107
|
};
|
|
104
|
-
|
|
108
|
+
/** Promotional allowance is conditional; setup text must describe eligibility,
|
|
109
|
+
* activation and expiry without implying current account entitlement. */
|
|
110
|
+
export type CatalogBillingPolicy = "free-tier" | "free-with-card" | "no-free-tier" | "promotional-credit";
|
|
105
111
|
export type CatalogSetup = {
|
|
106
112
|
url: string;
|
|
107
113
|
apiKeyFormat: string | null;
|
|
@@ -122,6 +128,9 @@ export type CatalogProbeEvidence = {
|
|
|
122
128
|
method?: string;
|
|
123
129
|
};
|
|
124
130
|
export type CatalogEvidence = {
|
|
131
|
+
/** Historical dated evidence. Its presence does not reverify an account
|
|
132
|
+
* roster or live execution; the authoring admission command reports those
|
|
133
|
+
* states separately without changing existing catalog records. */
|
|
125
134
|
rosterVerified: CatalogProbeEvidence;
|
|
126
135
|
authProbe?: CatalogProbeEvidence;
|
|
127
136
|
billingProbe?: CatalogProbeEvidence;
|
|
@@ -129,6 +138,8 @@ export type CatalogEvidence = {
|
|
|
129
138
|
date: string;
|
|
130
139
|
result: string;
|
|
131
140
|
} | null;
|
|
141
|
+
/** Introduction PR identity, or PENDING_PR during local source authoring.
|
|
142
|
+
* A string/URL alone is not proof of PR association, merge or release. */
|
|
132
143
|
addedInPR: string;
|
|
133
144
|
};
|
|
134
145
|
export type CatalogCapabilities = {
|
|
@@ -198,7 +209,10 @@ export type ProviderCatalogJson = {
|
|
|
198
209
|
* registryDefaultModel is MISTRAL_LARGE_LATEST while its defaultModel
|
|
199
210
|
* is not). Must be a models.catalog key (validated). */
|
|
200
211
|
registryDefaultModel?: string;
|
|
212
|
+
/** Source-supported positive safe integer model ceiling; never a zero
|
|
213
|
+
* placeholder. This does not change caller maxTokens: 0 semantics. */
|
|
201
214
|
defaultContextWindow: number;
|
|
215
|
+
/** Source-supported positive safe integer output ceiling. */
|
|
202
216
|
defaultMaxOutputTokens: number;
|
|
203
217
|
catalog: Record<string, CatalogModelSpec>;
|
|
204
218
|
/** Ordered curated subset of `catalog` keys for wizard/choice surfaces
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type CatalogProviderName = "a2agent" | "above-dev" | "ai21" | "aiand" | "aionlabs" | "ambient" | "api-route" | "arcee" | "atlas-cloud" | "avian-io" | "baidu-qianfan" | "baseten" | "bee-heossi" | "byteplus-modelark" | "bytez" | "cerebras" | "charm-hyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherless-ai" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetzner-inference" | "huggingface" | "inception-labs" | "inceptron" | "inco" | "inference-net" | "io-intelligence" | "koscompute" | "lemonfox-ai" | "lilac" | "llmtech" | "mancer" | "meta-model-api" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshot-ai" | "morph" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "pareto-inference" | "perplexity" | "poolside" | "prime-intellect" | "reka" | "sakana-ai" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinking-machines" | "tinfoil" | "together-ai" | "umans-ai" | "upstage" | "venice-ai" | "vispark" | "vultr-inference" | "wafer" | "wandb-inference" | "xai" | "z-ai";
|
|
2
|
-
export type CatalogCredentialKey = "a2agent" | "aboveDev" | "ai21" | "aiand" | "aionlabs" | "ambient" | "apiRoute" | "arcee" | "atlasCloud" | "avianIo" | "baiduQianfan" | "baseten" | "beeHeossi" | "byteplusModelark" | "bytez" | "cerebras" | "charmHyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherlessAi" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetznerInference" | "huggingFace" | "inceptionLabs" | "inceptron" | "inco" | "inferenceNet" | "ioIntelligence" | "koscompute" | "lemonfoxAi" | "lilac" | "llmtech" | "mancer" | "metaModelApi" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshotAi" | "morph" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "paretoInference" | "perplexity" | "poolside" | "primeIntellect" | "reka" | "sakanaAi" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinkingMachines" | "tinfoil" | "together" | "umansAi" | "upstage" | "veniceAi" | "vispark" | "vultrInference" | "wafer" | "wandbInference" | "xai" | "zAi";
|
|
1
|
+
export type CatalogProviderName = "a2agent" | "abliteration" | "above-dev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "api-route" | "arcee" | "atlas-cloud" | "avian-io" | "baidu-qianfan" | "baseten" | "bee-heossi" | "byteplus-modelark" | "bytez" | "cerebras" | "charm-hyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherless-ai" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetzner-inference" | "huggingface" | "inception-labs" | "inceptron" | "inco" | "inference-net" | "io-intelligence" | "koscompute" | "lemonfox-ai" | "lilac" | "llmtech" | "mancer" | "meta-model-api" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshot-ai" | "morph" | "naver-clova-studio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "pareto-inference" | "perplexity" | "poolside" | "prime-intellect" | "reka" | "sakana-ai" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinking-machines" | "tinfoil" | "together-ai" | "umans-ai" | "upstage" | "venice-ai" | "vispark" | "vultr-inference" | "wafer" | "wandb-inference" | "xai" | "z-ai";
|
|
2
|
+
export type CatalogCredentialKey = "a2agent" | "abliteration" | "aboveDev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "apiRoute" | "arcee" | "atlasCloud" | "avianIo" | "baiduQianfan" | "baseten" | "beeHeossi" | "byteplusModelark" | "bytez" | "cerebras" | "charmHyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherlessAi" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetznerInference" | "huggingFace" | "inceptionLabs" | "inceptron" | "inco" | "inferenceNet" | "ioIntelligence" | "koscompute" | "lemonfoxAi" | "lilac" | "llmtech" | "mancer" | "metaModelApi" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshotAi" | "morph" | "naverClovaStudio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "paretoInference" | "perplexity" | "poolside" | "primeIntellect" | "reka" | "sakanaAi" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinkingMachines" | "tinfoil" | "together" | "umansAi" | "upstage" | "veniceAi" | "vispark" | "vultrInference" | "wafer" | "wandbInference" | "xai" | "zAi";
|
|
@@ -196,6 +196,10 @@ export type NeurolinkCredentials = {
|
|
|
196
196
|
apiKey?: string;
|
|
197
197
|
baseURL?: string;
|
|
198
198
|
};
|
|
199
|
+
abliteration?: {
|
|
200
|
+
apiKey?: string;
|
|
201
|
+
baseURL?: string;
|
|
202
|
+
};
|
|
199
203
|
aboveDev?: {
|
|
200
204
|
apiKey?: string;
|
|
201
205
|
baseURL?: string;
|
|
@@ -208,6 +212,10 @@ export type NeurolinkCredentials = {
|
|
|
208
212
|
apiKey?: string;
|
|
209
213
|
baseURL?: string;
|
|
210
214
|
};
|
|
215
|
+
aihubmix?: {
|
|
216
|
+
apiKey?: string;
|
|
217
|
+
baseURL?: string;
|
|
218
|
+
};
|
|
211
219
|
aionlabs?: {
|
|
212
220
|
apiKey?: string;
|
|
213
221
|
baseURL?: string;
|
|
@@ -389,6 +397,10 @@ export type NeurolinkCredentials = {
|
|
|
389
397
|
apiKey?: string;
|
|
390
398
|
baseURL?: string;
|
|
391
399
|
};
|
|
400
|
+
naverClovaStudio?: {
|
|
401
|
+
apiKey?: string;
|
|
402
|
+
baseURL?: string;
|
|
403
|
+
};
|
|
392
404
|
nebius?: {
|
|
393
405
|
apiKey?: string;
|
|
394
406
|
baseURL?: string;
|
|
@@ -1126,6 +1138,9 @@ export type OpenAICompatCatalogEntry = {
|
|
|
1126
1138
|
/** See CatalogQuirks.replayReasoningContent — a vendor that wants each
|
|
1127
1139
|
* assistant turn's `reasoning_content` sent back on later requests. */
|
|
1128
1140
|
replayReasoningContent?: boolean;
|
|
1141
|
+
/** See CatalogQuirks.rejectRequiredToolChoice. Applied only to a nonempty
|
|
1142
|
+
* tools request that explicitly requires a tool; no silent auto downgrade. */
|
|
1143
|
+
rejectRequiredToolChoice?: boolean;
|
|
1129
1144
|
/** See CatalogQuirks.authHeaderStyle — a vendor whose chat-completions
|
|
1130
1145
|
* endpoint authenticates via `X-Api-Key` instead of the inherited
|
|
1131
1146
|
* `Authorization: Bearer` default. */
|
|
@@ -19,6 +19,6 @@ export type SafeDownloadOptions = {
|
|
|
19
19
|
label: string;
|
|
20
20
|
/** Optional abort signal for caller-driven cancellation. */
|
|
21
21
|
signal?: AbortSignal;
|
|
22
|
-
/** Optional
|
|
22
|
+
/** Optional HTTP transfer timeout (ms), covering headers and body after URL validation. Default: 60_000. */
|
|
23
23
|
timeoutMs?: number;
|
|
24
24
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode a caller's supported HTML text references exactly once.
|
|
3
|
+
*
|
|
4
|
+
* Replacement scans the original string: a decoded ampersand is never
|
|
5
|
+
* reinterpreted as the beginning of another reference. Unknown references
|
|
6
|
+
* stay literal. This is text conversion, not HTML output sanitization.
|
|
7
|
+
*/
|
|
8
|
+
export declare function decodeHtmlTextEntitiesOnce(value: string, entities: Readonly<Record<string, string>>, decodeDecimalReferences?: boolean): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode a caller's supported HTML text references exactly once.
|
|
3
|
+
*
|
|
4
|
+
* Replacement scans the original string: a decoded ampersand is never
|
|
5
|
+
* reinterpreted as the beginning of another reference. Unknown references
|
|
6
|
+
* stay literal. This is text conversion, not HTML output sanitization.
|
|
7
|
+
*/
|
|
8
|
+
export function decodeHtmlTextEntitiesOnce(value, entities, decodeDecimalReferences = false) {
|
|
9
|
+
return value.replace(/&([a-z]+|#\d+);/gi, (match, body) => {
|
|
10
|
+
const reference = body.toLowerCase();
|
|
11
|
+
const decoded = Object.hasOwn(entities, reference)
|
|
12
|
+
? entities[reference]
|
|
13
|
+
: undefined;
|
|
14
|
+
if (typeof decoded === "string") {
|
|
15
|
+
return decoded;
|
|
16
|
+
}
|
|
17
|
+
if (!decodeDecimalReferences || !reference.startsWith("#")) {
|
|
18
|
+
return match;
|
|
19
|
+
}
|
|
20
|
+
const codePoint = Number(reference.slice(1));
|
|
21
|
+
if (!Number.isInteger(codePoint) ||
|
|
22
|
+
codePoint <= 0 ||
|
|
23
|
+
codePoint > 0x10ffff ||
|
|
24
|
+
(codePoint >= 0xd800 && codePoint <= 0xdfff)) {
|
|
25
|
+
return match;
|
|
26
|
+
}
|
|
27
|
+
return String.fromCodePoint(codePoint);
|
|
28
|
+
});
|
|
29
|
+
}
|
package/dist/utils/safeFetch.js
CHANGED
|
@@ -140,14 +140,23 @@ export async function safeDownload(url, options) {
|
|
|
140
140
|
const composedSignal = options.signal
|
|
141
141
|
? AbortSignal.any([options.signal, timeoutCtrl.signal])
|
|
142
142
|
: timeoutCtrl.signal;
|
|
143
|
-
let response;
|
|
144
143
|
try {
|
|
145
|
-
response = await undiciFetch(validatedUrl, {
|
|
144
|
+
const response = await undiciFetch(validatedUrl, {
|
|
146
145
|
method: "GET",
|
|
147
146
|
signal: composedSignal,
|
|
148
147
|
redirect: "manual", // a 3xx → private-IP redirect would bypass the guard
|
|
149
148
|
dispatcher,
|
|
150
149
|
});
|
|
150
|
+
// fetch resolves at the headers. Keep the same deadline and abort signal
|
|
151
|
+
// active while the bounded reader drains the response body as well.
|
|
152
|
+
return await readDownloadResponse(response, url, options);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
// A status/size rejection may happen before the body is consumed. Stop
|
|
156
|
+
// that request so a pinned agent can close and a shared proxy agent does
|
|
157
|
+
// not retain an unused response stream.
|
|
158
|
+
timeoutCtrl.abort();
|
|
159
|
+
throw error;
|
|
151
160
|
}
|
|
152
161
|
finally {
|
|
153
162
|
clearTimeout(timeoutId);
|
|
@@ -157,5 +166,4 @@ export async function safeDownload(url, options) {
|
|
|
157
166
|
dispatcher.close().catch(() => undefined);
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
|
-
return readDownloadResponse(response, url, options);
|
|
161
169
|
}
|