@librechat/agents 3.1.67-dev.4 → 3.1.68-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/graphs/MultiAgentGraph.cjs +36 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/summarization/index.cjs +41 -0
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +121 -19
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +36 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/summarization/index.mjs +41 -1
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +121 -19
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/types/graphs/MultiAgentGraph.d.ts +12 -0
- package/dist/types/summarization/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/graphs/MultiAgentGraph.ts +39 -0
- package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
- package/src/summarization/__tests__/node.test.ts +42 -0
- package/src/summarization/__tests__/trigger.test.ts +100 -1
- package/src/summarization/index.ts +47 -0
- package/src/summarization/node.ts +149 -24
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
import type { SummarizationTrigger } from '@/types';
|
|
2
2
|
|
|
3
|
+
const VALID_TRIGGER_TYPES = [
|
|
4
|
+
'token_ratio',
|
|
5
|
+
'remaining_tokens',
|
|
6
|
+
'messages_to_refine',
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Upper bound on the dedup set for unrecognized trigger types. Bounds memory in
|
|
11
|
+
* case a caller threads dynamic/user-provided strings through `trigger.type`.
|
|
12
|
+
* Well above the handful of legit misconfigurations a process would ever see.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_WARNED_TRIGGER_TYPES = 32;
|
|
15
|
+
|
|
16
|
+
const warnedUnrecognizedTriggerTypes = new Set<string>();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Warn (once per process, per unrecognized type) when the configured trigger
|
|
20
|
+
* type is something the runtime does not evaluate. Without this, a misconfigured
|
|
21
|
+
* `trigger.type` silently disables summarization with no visible signal.
|
|
22
|
+
*
|
|
23
|
+
* The dedup set is size-capped; on overflow we evict the oldest entry (Set
|
|
24
|
+
* preserves insertion order) so we keep bounded memory and still warn on
|
|
25
|
+
* recently-seen types.
|
|
26
|
+
*/
|
|
27
|
+
function warnUnrecognizedTriggerType(type: string): void {
|
|
28
|
+
if (warnedUnrecognizedTriggerTypes.has(type)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (warnedUnrecognizedTriggerTypes.size >= MAX_WARNED_TRIGGER_TYPES) {
|
|
32
|
+
const oldest = warnedUnrecognizedTriggerTypes.values().next().value;
|
|
33
|
+
if (oldest !== undefined) {
|
|
34
|
+
warnedUnrecognizedTriggerTypes.delete(oldest);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
warnedUnrecognizedTriggerTypes.add(type);
|
|
38
|
+
console.warn(
|
|
39
|
+
`[shouldTriggerSummarization] Unrecognized trigger.type: "${type}". ` +
|
|
40
|
+
`Summarization will not fire. Valid values: ${VALID_TRIGGER_TYPES.join(', ')}.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** For tests only. Resets the dedup set so warnings can be observed again. */
|
|
45
|
+
export function _resetUnrecognizedTriggerWarnings(): void {
|
|
46
|
+
warnedUnrecognizedTriggerTypes.clear();
|
|
47
|
+
}
|
|
48
|
+
|
|
3
49
|
/**
|
|
4
50
|
* Determines whether summarization should be triggered based on the configured trigger
|
|
5
51
|
* and current context state.
|
|
@@ -98,5 +144,6 @@ export function shouldTriggerSummarization(params: {
|
|
|
98
144
|
}
|
|
99
145
|
|
|
100
146
|
// Unrecognized trigger type: cannot evaluate, do not fire.
|
|
147
|
+
warnUnrecognizedTriggerType(trigger.type);
|
|
101
148
|
return false;
|
|
102
149
|
}
|
|
@@ -366,6 +366,122 @@ type LogFn = (
|
|
|
366
366
|
data?: Record<string, unknown>
|
|
367
367
|
) => void;
|
|
368
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Extracts an HTTP status code from a thrown LLM-provider error. Returns
|
|
371
|
+
* `undefined` for non-object values (including `null` or `undefined`, both
|
|
372
|
+
* valid `throw` targets in JS) so callers never dereference a nullish
|
|
373
|
+
* value.
|
|
374
|
+
*/
|
|
375
|
+
function extractHttpStatus(err: unknown): number | undefined {
|
|
376
|
+
if (err == null || typeof err !== 'object') {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
const errRecord = err as Record<string, unknown>;
|
|
380
|
+
const direct = errRecord.status;
|
|
381
|
+
if (typeof direct === 'number') {
|
|
382
|
+
return direct;
|
|
383
|
+
}
|
|
384
|
+
const statusCode = errRecord.statusCode;
|
|
385
|
+
if (typeof statusCode === 'number') {
|
|
386
|
+
return statusCode;
|
|
387
|
+
}
|
|
388
|
+
const response = errRecord.response;
|
|
389
|
+
if (response != null && typeof response === 'object') {
|
|
390
|
+
const nested = (response as Record<string, unknown>).status;
|
|
391
|
+
if (typeof nested === 'number') {
|
|
392
|
+
return nested;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Formats a provider-level error for logging. Returns both a human-readable
|
|
400
|
+
* suffix (safe to include in the message string so it survives any host-side
|
|
401
|
+
* formatter) and a structured metadata bag for rich log backends.
|
|
402
|
+
*/
|
|
403
|
+
function describeProviderError(
|
|
404
|
+
err: unknown,
|
|
405
|
+
provider: string,
|
|
406
|
+
modelName?: string
|
|
407
|
+
): { suffix: string; data: Record<string, unknown> } {
|
|
408
|
+
const providerLabel = `${provider}/${modelName ?? '(no-model)'}`;
|
|
409
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
410
|
+
|
|
411
|
+
const data: Record<string, unknown> = {
|
|
412
|
+
provider,
|
|
413
|
+
model: modelName,
|
|
414
|
+
};
|
|
415
|
+
if (err instanceof Error) {
|
|
416
|
+
data.errorName = err.name;
|
|
417
|
+
data.errorStack = err.stack;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const status = extractHttpStatus(err);
|
|
421
|
+
const statusSuffix = status != null ? ` (HTTP ${status})` : '';
|
|
422
|
+
if (status != null) {
|
|
423
|
+
data.status = status;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
suffix: `[${providerLabel}]${statusSuffix}: ${errMsg}`,
|
|
428
|
+
data,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Formats an exhausted-fallback error. `tryFallbackProviders` throws the
|
|
434
|
+
* last fallback provider's error, which may be from any of the configured
|
|
435
|
+
* fallbacks — not the primary — so we label the log with the list of
|
|
436
|
+
* fallback providers attempted rather than mis-attributing to the primary.
|
|
437
|
+
*
|
|
438
|
+
* Entries in `fallbacks` are normally strongly typed, but we defend against
|
|
439
|
+
* malformed runtime config (null/undefined entries, missing `provider`
|
|
440
|
+
* field) so a recoverable summarization failure is never promoted to an
|
|
441
|
+
* uncaught exception from inside the logging path.
|
|
442
|
+
*/
|
|
443
|
+
function describeFallbackError(
|
|
444
|
+
err: unknown,
|
|
445
|
+
fallbacks: unknown
|
|
446
|
+
): { suffix: string; data: Record<string, unknown> } {
|
|
447
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
448
|
+
const list: ReadonlyArray<unknown> = Array.isArray(fallbacks)
|
|
449
|
+
? fallbacks
|
|
450
|
+
: [];
|
|
451
|
+
const providerNames = list
|
|
452
|
+
.map((f) => {
|
|
453
|
+
if (f == null || typeof f !== 'object') {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
const raw = (f as { provider?: unknown }).provider;
|
|
457
|
+
return raw != null ? String(raw) : undefined;
|
|
458
|
+
})
|
|
459
|
+
.filter((p): p is string => typeof p === 'string');
|
|
460
|
+
const label =
|
|
461
|
+
providerNames.length > 0
|
|
462
|
+
? `fallbacks=[${providerNames.join(',')}]`
|
|
463
|
+
: 'no-fallbacks';
|
|
464
|
+
|
|
465
|
+
const data: Record<string, unknown> = {
|
|
466
|
+
fallbackProviders: providerNames,
|
|
467
|
+
fallbackCount: list.length,
|
|
468
|
+
};
|
|
469
|
+
if (err instanceof Error) {
|
|
470
|
+
data.errorName = err.name;
|
|
471
|
+
data.errorStack = err.stack;
|
|
472
|
+
}
|
|
473
|
+
const status = extractHttpStatus(err);
|
|
474
|
+
const statusSuffix = status != null ? ` (HTTP ${status})` : '';
|
|
475
|
+
if (status != null) {
|
|
476
|
+
data.status = status;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
suffix: `[${label}]${statusSuffix}: ${errMsg}`,
|
|
481
|
+
data,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
369
485
|
/**
|
|
370
486
|
* Runs the summarization LLM call with primary + fallback providers,
|
|
371
487
|
* falling back to a metadata stub when all calls fail.
|
|
@@ -389,18 +505,23 @@ async function executeSummarizationWithFallback(params: {
|
|
|
389
505
|
log,
|
|
390
506
|
} = params;
|
|
391
507
|
|
|
392
|
-
const summarizationModel = initializeModel({
|
|
393
|
-
provider: clientConfig.provider as Providers,
|
|
394
|
-
clientOptions: clientConfig.clientOptions as t.ClientOptions,
|
|
395
|
-
tools: agentContext.getToolsForBinding(),
|
|
396
|
-
}) as t.ChatModel;
|
|
397
|
-
|
|
398
508
|
const priorSummaryText = agentContext.getSummaryText()?.trim() ?? '';
|
|
399
509
|
|
|
400
510
|
let summaryText = '';
|
|
401
511
|
let summaryUsage: Partial<UsageMetadata> | undefined;
|
|
402
512
|
|
|
403
513
|
try {
|
|
514
|
+
/**
|
|
515
|
+
* Initialize inside the try so that a misconfigured provider
|
|
516
|
+
* (e.g. an unrecognized summarization.provider) surfaces through the
|
|
517
|
+
* `log('error', ...)` path below rather than bubbling up silently.
|
|
518
|
+
*/
|
|
519
|
+
const summarizationModel = initializeModel({
|
|
520
|
+
provider: clientConfig.provider as Providers,
|
|
521
|
+
clientOptions: clientConfig.clientOptions as t.ClientOptions,
|
|
522
|
+
tools: agentContext.getToolsForBinding(),
|
|
523
|
+
}) as t.ChatModel;
|
|
524
|
+
|
|
404
525
|
const result = await summarizeWithCacheHit({
|
|
405
526
|
model: summarizationModel,
|
|
406
527
|
messages,
|
|
@@ -417,19 +538,20 @@ async function executeSummarizationWithFallback(params: {
|
|
|
417
538
|
summaryText = result.text;
|
|
418
539
|
summaryUsage = result.usage;
|
|
419
540
|
} catch (primaryError) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
541
|
+
const primaryDescribed = describeProviderError(
|
|
542
|
+
primaryError,
|
|
543
|
+
clientConfig.provider,
|
|
544
|
+
clientConfig.modelName
|
|
545
|
+
);
|
|
546
|
+
log('error', `Summarization LLM call failed ${primaryDescribed.suffix}`, {
|
|
547
|
+
...primaryDescribed.data,
|
|
427
548
|
messagesToRefineCount: messages.length,
|
|
428
549
|
});
|
|
429
550
|
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
551
|
+
const rawFallbacks = (
|
|
552
|
+
clientConfig.clientOptions as unknown as t.LLMConfig | undefined
|
|
553
|
+
)?.fallbacks;
|
|
554
|
+
const fallbacks = Array.isArray(rawFallbacks) ? rawFallbacks : [];
|
|
433
555
|
if (fallbacks.length > 0) {
|
|
434
556
|
try {
|
|
435
557
|
const onChunk = createSummarizationChunkHandler({
|
|
@@ -462,18 +584,21 @@ async function executeSummarizationWithFallback(params: {
|
|
|
462
584
|
);
|
|
463
585
|
}
|
|
464
586
|
} catch (fbErr) {
|
|
465
|
-
|
|
466
|
-
|
|
587
|
+
const fbDescribed = describeFallbackError(fbErr, fallbacks);
|
|
588
|
+
log('warn', `Fallback providers also failed ${fbDescribed.suffix}`, {
|
|
589
|
+
...fbDescribed.data,
|
|
467
590
|
});
|
|
468
591
|
}
|
|
469
592
|
}
|
|
470
593
|
if (!summaryText) {
|
|
471
|
-
log(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
594
|
+
log(
|
|
595
|
+
'warn',
|
|
596
|
+
`Summarization failed, falling back to metadata stub ${primaryDescribed.suffix}`,
|
|
597
|
+
{
|
|
598
|
+
...primaryDescribed.data,
|
|
599
|
+
messagesToRefineCount: messages.length,
|
|
600
|
+
}
|
|
601
|
+
);
|
|
477
602
|
summaryText = generateMetadataStub(messages);
|
|
478
603
|
}
|
|
479
604
|
}
|