@librechat/agents 3.7.7 → 3.7.8
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/agents/AgentContext.cjs +23 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +10 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +16 -5
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +75 -0
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +1 -1
- package/dist/cjs/llm/fake.cjs +9 -5
- package/dist/cjs/llm/fake.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +1 -1
- package/dist/cjs/llm/openrouter/toolCache.cjs +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +2 -2
- package/dist/cjs/llm/providers.cjs +1 -1
- package/dist/cjs/llm/truncation.cjs +1 -0
- package/dist/cjs/main.cjs +3 -2
- package/dist/cjs/messages/format.cjs +298 -3
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +1 -1
- package/dist/cjs/run.cjs +25 -15
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/node.cjs +43 -9
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/semanticIndex.cjs +362 -0
- package/dist/cjs/summarization/semanticIndex.cjs.map +1 -0
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +2 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/esm/agents/AgentContext.mjs +23 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +10 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +16 -5
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +75 -0
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +1 -1
- package/dist/esm/llm/fake.mjs +9 -5
- package/dist/esm/llm/fake.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +1 -1
- package/dist/esm/llm/openrouter/toolCache.mjs +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +2 -2
- package/dist/esm/llm/providers.mjs +1 -1
- package/dist/esm/llm/truncation.mjs +1 -1
- package/dist/esm/main.mjs +4 -4
- package/dist/esm/messages/format.mjs +298 -3
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +1 -1
- package/dist/esm/run.mjs +25 -15
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/node.mjs +43 -9
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/semanticIndex.mjs +360 -0
- package/dist/esm/summarization/semanticIndex.mjs.map +1 -0
- package/dist/esm/tools/subagent/childGraphConfig.mjs +2 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/types/agents/AgentContext.d.ts +27 -1
- package/dist/types/common/constants.d.ts +10 -0
- package/dist/types/graphs/Graph.d.ts +15 -0
- package/dist/types/llm/fake.d.ts +12 -2
- package/dist/types/messages/format.d.ts +10 -1
- package/dist/types/run.d.ts +17 -5
- package/dist/types/summarization/semanticIndex.d.ts +19 -0
- package/dist/types/types/graph.d.ts +9 -1
- package/dist/types/types/summarize.d.ts +38 -0
- package/package.json +2 -1
- package/src/agents/AgentContext.ts +61 -1
- package/src/common/constants.ts +11 -0
- package/src/graphs/Graph.ts +41 -8
- package/src/langfuseTraceShaping.ts +94 -0
- package/src/llm/fake.ts +35 -4
- package/src/messages/format.ts +652 -4
- package/src/run.ts +36 -10
- package/src/summarization/node.ts +90 -33
- package/src/summarization/semanticIndex.ts +653 -0
- package/src/tools/subagent/childGraphConfig.ts +3 -0
- package/src/types/graph.ts +9 -0
- package/src/types/summarize.ts +50 -0
package/src/run.ts
CHANGED
|
@@ -35,7 +35,6 @@ import {
|
|
|
35
35
|
ACTIVITY_PHASE_LABEL_RUN_NAME,
|
|
36
36
|
DEFAULT_RECURSION_LIMIT,
|
|
37
37
|
} from '@/common';
|
|
38
|
-
import { isBuiltRuntime } from '@/lazyRequire';
|
|
39
38
|
import {
|
|
40
39
|
requireValidSubagentResumeManifest,
|
|
41
40
|
stripSubagentResumeManifest,
|
|
@@ -94,14 +93,15 @@ import { applyGraphRuntimeConfig } from '@/graphs/applyGraphRuntimeConfig';
|
|
|
94
93
|
import { LANGFUSE_OPERATION_METADATA_KEY } from '@/langfuseOperation';
|
|
95
94
|
import { createTokenCounter, encodingForModel } from '@/utils/tokens';
|
|
96
95
|
import { stampSyntheticProviderMessage } from '@/messages/provenance';
|
|
96
|
+
import { isOpenAILike, isLibreChatOpenAIModel } from '@/utils/llm';
|
|
97
97
|
import { initializeLangfuseTracing } from './instrumentation';
|
|
98
98
|
import { seedRunInitialSessions } from '@/utils/toolSessions';
|
|
99
99
|
import { getTraceIdSeed } from '@/langfuseRuntimeContext';
|
|
100
100
|
import { createGraph } from '@/graphs/createGraph';
|
|
101
101
|
import { resolveMaxSeals } from '@/llm/preempt';
|
|
102
|
+
import { isBuiltRuntime } from '@/lazyRequire';
|
|
102
103
|
import { initializeModel } from '@/llm/init';
|
|
103
104
|
import { HandlerRegistry } from '@/events';
|
|
104
|
-
import { isOpenAILike, isLibreChatOpenAIModel } from '@/utils/llm';
|
|
105
105
|
import { executeHooks } from '@/hooks';
|
|
106
106
|
|
|
107
107
|
/** Source-mode runs have no dist siblings for the lazy-loading seam, so every
|
|
@@ -130,6 +130,7 @@ export const defaultOmitOptions = new Set([
|
|
|
130
130
|
const ACTIVITY_LABEL_TRACE_NAME = 'LibreChat Activity Label';
|
|
131
131
|
const ACTIVITY_PHASE_TRACE_NAME = 'LibreChat Activity Phase';
|
|
132
132
|
const REASONING_LABEL_TRACE_NAME = 'LibreChat Reasoning Label';
|
|
133
|
+
const OUTPUT_TRUNCATED_HALT_REASON = 'output_truncated';
|
|
133
134
|
|
|
134
135
|
const CUSTOM_GRAPH_EVENTS = new Set<string>([
|
|
135
136
|
GraphEvents.ON_AGENT_UPDATE,
|
|
@@ -794,6 +795,18 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
794
795
|
return this.Graph?.getToolCount() ?? 0;
|
|
795
796
|
}
|
|
796
797
|
|
|
798
|
+
/**
|
|
799
|
+
* True when the run's last turn ended at `END` because the provider hit
|
|
800
|
+
* its output token ceiling while producing plain text/reasoning — no tool
|
|
801
|
+
* call, so `assertNotTruncatedToolCall` never sees it and the graph reads
|
|
802
|
+
* the turn as an ordinary completion. Hosts check this alongside
|
|
803
|
+
* `getPreemptStats()` / `getHaltReason()` to decide whether to persist the
|
|
804
|
+
* response as unfinished instead of a silently truncated "complete" one.
|
|
805
|
+
*/
|
|
806
|
+
getOutputTruncated(): boolean {
|
|
807
|
+
return this.Graph?.outputTruncatedIncomplete ?? false;
|
|
808
|
+
}
|
|
809
|
+
|
|
797
810
|
/**
|
|
798
811
|
* Creates a custom event callback handler that intercepts custom events
|
|
799
812
|
* and processes them through our handler registry instead of EventStreamCallbackHandler
|
|
@@ -1362,6 +1375,13 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1362
1375
|
this._haltedReason == null &&
|
|
1363
1376
|
this.hookRegistry?.hasHookFor('Stop', this.id) === true
|
|
1364
1377
|
) {
|
|
1378
|
+
let stopReason = graph.preemptHaltReason;
|
|
1379
|
+
if (stopReason == null && graph.preemptIncomplete) {
|
|
1380
|
+
stopReason = 'preempt_incomplete';
|
|
1381
|
+
}
|
|
1382
|
+
if (stopReason == null && graph.outputTruncatedIncomplete) {
|
|
1383
|
+
stopReason = OUTPUT_TRUNCATED_HALT_REASON;
|
|
1384
|
+
}
|
|
1365
1385
|
await executeHooks({
|
|
1366
1386
|
registry: this.hookRegistry,
|
|
1367
1387
|
input: {
|
|
@@ -1377,9 +1397,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1377
1397
|
* actual cause, not the generic label — and `preempt_incomplete`
|
|
1378
1398
|
* is reserved for the boundary that simply had nothing to inject.
|
|
1379
1399
|
*/
|
|
1380
|
-
stopReason
|
|
1381
|
-
graph.preemptHaltReason ??
|
|
1382
|
-
(graph.preemptIncomplete ? 'preempt_incomplete' : undefined),
|
|
1400
|
+
stopReason,
|
|
1383
1401
|
stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)
|
|
1384
1402
|
},
|
|
1385
1403
|
sessionId: this.id,
|
|
@@ -1409,6 +1427,11 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1409
1427
|
this._haltedReason = graph.preemptHaltReason;
|
|
1410
1428
|
} else if (this._haltedReason == null && graph.preemptIncomplete) {
|
|
1411
1429
|
this._haltedReason = 'preempt_incomplete';
|
|
1430
|
+
} else if (
|
|
1431
|
+
this._haltedReason == null &&
|
|
1432
|
+
graph.outputTruncatedIncomplete
|
|
1433
|
+
) {
|
|
1434
|
+
this._haltedReason = OUTPUT_TRUNCATED_HALT_REASON;
|
|
1412
1435
|
}
|
|
1413
1436
|
};
|
|
1414
1437
|
|
|
@@ -1614,13 +1637,16 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1614
1637
|
}
|
|
1615
1638
|
|
|
1616
1639
|
/**
|
|
1617
|
-
* Returns the
|
|
1618
|
-
*
|
|
1640
|
+
* Returns why the run ended without a natural completion, or `undefined`
|
|
1641
|
+
* when it completed normally. Reasons include hook- and prompt-driven
|
|
1642
|
+
* halts, `preempt_incomplete` when a cooperative seal ended the turn
|
|
1643
|
+
* without continuation content, and `output_truncated` when the provider
|
|
1644
|
+
* stopped a plain-text/reasoning response at its output-token ceiling.
|
|
1619
1645
|
*
|
|
1620
1646
|
* Hosts inspect this after `processStream` returns to distinguish a
|
|
1621
|
-
* natural completion
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1647
|
+
* natural completion from a terminal partial response. Independent from
|
|
1648
|
+
* `getInterrupt()` — a halted run has no interrupt; an interrupted run has
|
|
1649
|
+
* no halt reason.
|
|
1624
1650
|
*/
|
|
1625
1651
|
getHaltReason(): string | undefined {
|
|
1626
1652
|
return this._haltedReason;
|
|
@@ -6,11 +6,19 @@ import {
|
|
|
6
6
|
} from '@langchain/core/messages';
|
|
7
7
|
import type { UsageMetadata, BaseMessage } from '@langchain/core/messages';
|
|
8
8
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
9
|
+
import type { RenderedCompactionSemanticIndex } from '@/summarization/semanticIndex';
|
|
9
10
|
import type { StreamLimitState } from '@/llm/streamLimits';
|
|
10
11
|
import type { AgentContext } from '@/agents/AgentContext';
|
|
11
12
|
import type { HookRegistry } from '@/hooks';
|
|
12
13
|
import type { OnChunk } from '@/llm/invoke';
|
|
13
14
|
import type * as t from '@/types';
|
|
15
|
+
import {
|
|
16
|
+
addTailCacheControl,
|
|
17
|
+
addBedrockTailCacheControl,
|
|
18
|
+
resolvePromptCacheTtl,
|
|
19
|
+
resolveBedrockPromptCacheTtl,
|
|
20
|
+
type PromptCacheTtl,
|
|
21
|
+
} from '@/messages/cache';
|
|
14
22
|
import {
|
|
15
23
|
cloneToolMessageWithContent,
|
|
16
24
|
compactToolContent,
|
|
@@ -22,13 +30,6 @@ import {
|
|
|
22
30
|
StreamLimitExceededError,
|
|
23
31
|
STREAM_LIMIT_EPOCH_KEY,
|
|
24
32
|
} from '@/llm/streamLimits';
|
|
25
|
-
import {
|
|
26
|
-
addTailCacheControl,
|
|
27
|
-
addBedrockTailCacheControl,
|
|
28
|
-
resolvePromptCacheTtl,
|
|
29
|
-
resolveBedrockPromptCacheTtl,
|
|
30
|
-
type PromptCacheTtl,
|
|
31
|
-
} from '@/messages/cache';
|
|
32
33
|
import {
|
|
33
34
|
DEFAULT_RETAIN_RECENT_TURNS,
|
|
34
35
|
resolveIntraTurnRetainTokens,
|
|
@@ -41,9 +42,10 @@ import {
|
|
|
41
42
|
StepTypes,
|
|
42
43
|
Providers,
|
|
43
44
|
} from '@/common';
|
|
45
|
+
import { renderCompactionSemanticIndex } from '@/summarization/semanticIndex';
|
|
44
46
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
45
|
-
import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
|
|
46
47
|
import { prepareToolsForPromptCache } from '@/llm/promptCacheTools';
|
|
48
|
+
import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
|
|
47
49
|
import { calculateMaxToolResultChars } from '@/utils/truncation';
|
|
48
50
|
import { makeIsDeferred } from '@/messages/anthropicToolCache';
|
|
49
51
|
import { createRemoveAllMessage } from '@/messages/reducer';
|
|
@@ -625,6 +627,7 @@ async function executeSummarizationWithFallback(params: {
|
|
|
625
627
|
summarizeConfig?: RunnableConfig;
|
|
626
628
|
stepId: string;
|
|
627
629
|
usePromptCache: boolean;
|
|
630
|
+
semanticIndex: RenderedCompactionSemanticIndex;
|
|
628
631
|
log: LogFn;
|
|
629
632
|
/** Carries the run's stream limits so the event cap covers summary streams. */
|
|
630
633
|
graph?: StreamLimitState & {
|
|
@@ -651,6 +654,7 @@ async function executeSummarizationWithFallback(params: {
|
|
|
651
654
|
summarizeConfig,
|
|
652
655
|
stepId,
|
|
653
656
|
usePromptCache,
|
|
657
|
+
semanticIndex,
|
|
654
658
|
log,
|
|
655
659
|
graph,
|
|
656
660
|
} = params;
|
|
@@ -693,6 +697,7 @@ async function executeSummarizationWithFallback(params: {
|
|
|
693
697
|
promptText: clientConfig.promptText,
|
|
694
698
|
updatePromptText: clientConfig.updatePromptText,
|
|
695
699
|
priorSummaryText,
|
|
700
|
+
semanticIndexAppendix: semanticIndex.appendix,
|
|
696
701
|
config: summarizeConfig,
|
|
697
702
|
stepId,
|
|
698
703
|
provider: clientConfig.provider,
|
|
@@ -704,20 +709,20 @@ async function executeSummarizationWithFallback(params: {
|
|
|
704
709
|
clientConfig.provider === Providers.OPENROUTER ||
|
|
705
710
|
clientConfig.provider === Providers.BEDROCK
|
|
706
711
|
? (
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
712
|
+
clientConfig.clientOptions as {
|
|
713
|
+
promptCacheTtl?: PromptCacheTtl;
|
|
714
|
+
}
|
|
710
715
|
).promptCacheTtl
|
|
711
716
|
: undefined,
|
|
712
717
|
bedrockModelId:
|
|
713
718
|
clientConfig.provider === Providers.BEDROCK
|
|
714
719
|
? resolveBedrockCompactionCacheModel(
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
720
|
+
clientConfig.clientOptions as
|
|
721
|
+
| {
|
|
722
|
+
applicationInferenceProfile?: string;
|
|
723
|
+
model?: string;
|
|
724
|
+
}
|
|
725
|
+
| undefined
|
|
721
726
|
)
|
|
722
727
|
: undefined,
|
|
723
728
|
log,
|
|
@@ -785,7 +790,8 @@ async function executeSummarizationWithFallback(params: {
|
|
|
785
790
|
buildSummarizationInstruction(
|
|
786
791
|
clientConfig.promptText,
|
|
787
792
|
clientConfig.updatePromptText,
|
|
788
|
-
priorSummaryText
|
|
793
|
+
priorSummaryText,
|
|
794
|
+
semanticIndex.appendix
|
|
789
795
|
)
|
|
790
796
|
),
|
|
791
797
|
],
|
|
@@ -1092,6 +1098,29 @@ export function createSummarizeNode({
|
|
|
1092
1098
|
return { summarizationRequest: undefined };
|
|
1093
1099
|
}
|
|
1094
1100
|
|
|
1101
|
+
/**
|
|
1102
|
+
* A summarizer that has already returned nothing several times in a row
|
|
1103
|
+
* keeps returning nothing, and every empty result leaves the message set
|
|
1104
|
+
* exactly as it was — so the next prune cycle re-triggers on identical
|
|
1105
|
+
* state. Stopping here bounds that loop instead of letting the run spend
|
|
1106
|
+
* its recursion budget dispatching empty summary steps.
|
|
1107
|
+
*/
|
|
1108
|
+
if (agentContext.summarizationExhausted) {
|
|
1109
|
+
emitAgentLog(
|
|
1110
|
+
config,
|
|
1111
|
+
'warn',
|
|
1112
|
+
'summarize',
|
|
1113
|
+
'Summarization skipped — consecutive attempts produced no usable summary',
|
|
1114
|
+
{
|
|
1115
|
+
failures: agentContext.summarizationFailures,
|
|
1116
|
+
reason: request.reason ?? 'trigger',
|
|
1117
|
+
},
|
|
1118
|
+
{ runId: graph.runId, agentId: request.agentId }
|
|
1119
|
+
);
|
|
1120
|
+
agentContext.markSummarizationTriggered(state.messages.length);
|
|
1121
|
+
return { summarizationRequest: undefined };
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1095
1124
|
const maxCtx = agentContext.maxContextTokens ?? 0;
|
|
1096
1125
|
if (maxCtx > 0 && agentContext.instructionTokens >= maxCtx) {
|
|
1097
1126
|
emitAgentLog(
|
|
@@ -1188,6 +1217,10 @@ export function createSummarizeNode({
|
|
|
1188
1217
|
agentContext,
|
|
1189
1218
|
agentContext.summarizationConfig
|
|
1190
1219
|
);
|
|
1220
|
+
const semanticIndex = renderCompactionSemanticIndex(
|
|
1221
|
+
agentContext.compactionSemanticIndex,
|
|
1222
|
+
messagesToRefine
|
|
1223
|
+
);
|
|
1191
1224
|
|
|
1192
1225
|
const stepKey = `summarize-${request.agentId}`;
|
|
1193
1226
|
const [stepId, stepIndex] = generateStepId(stepKey);
|
|
@@ -1229,6 +1262,8 @@ export function createSummarizeNode({
|
|
|
1229
1262
|
model: clientConfig.modelName,
|
|
1230
1263
|
messagesToRefineCount: messagesToRefine.length,
|
|
1231
1264
|
summaryVersion: agentContext.summaryVersion + 1,
|
|
1265
|
+
semanticIndexEntryCount: semanticIndex.entryCount,
|
|
1266
|
+
semanticIndexCharCount: semanticIndex.charCount,
|
|
1232
1267
|
} satisfies t.SummarizeStartEvent,
|
|
1233
1268
|
runnableConfig
|
|
1234
1269
|
);
|
|
@@ -1276,6 +1311,9 @@ export function createSummarizeNode({
|
|
|
1276
1311
|
isSelfSummarize: isSelfSummarizeModel,
|
|
1277
1312
|
hasPromptCache,
|
|
1278
1313
|
provider: clientConfig.provider,
|
|
1314
|
+
semanticIndexEntryCount: semanticIndex.entryCount,
|
|
1315
|
+
semanticIndexCharCount: semanticIndex.charCount,
|
|
1316
|
+
semanticIndexOmittedEntryCount: semanticIndex.omittedEntryCount,
|
|
1279
1317
|
});
|
|
1280
1318
|
|
|
1281
1319
|
const summarizeConfig: RunnableConfig | undefined = config
|
|
@@ -1291,6 +1329,10 @@ export function createSummarizeNode({
|
|
|
1291
1329
|
agentId: request.agentId,
|
|
1292
1330
|
summarization_provider: clientConfig.provider,
|
|
1293
1331
|
summarization_model: clientConfig.modelName,
|
|
1332
|
+
compaction_semantic_index_entries: semanticIndex.entryCount,
|
|
1333
|
+
compaction_semantic_index_chars: semanticIndex.charCount,
|
|
1334
|
+
compaction_semantic_index_omitted_entries:
|
|
1335
|
+
semanticIndex.omittedEntryCount,
|
|
1294
1336
|
/**
|
|
1295
1337
|
* Per-call model attribution for usage consumers (the subagent
|
|
1296
1338
|
* usage-capture handler): the summarizer's model can differ from
|
|
@@ -1340,6 +1382,7 @@ export function createSummarizeNode({
|
|
|
1340
1382
|
summarizeConfig,
|
|
1341
1383
|
stepId,
|
|
1342
1384
|
usePromptCache: isSelfSummarizeModel && hasPromptCache,
|
|
1385
|
+
semanticIndex,
|
|
1343
1386
|
log,
|
|
1344
1387
|
graph,
|
|
1345
1388
|
});
|
|
@@ -1365,6 +1408,7 @@ export function createSummarizeNode({
|
|
|
1365
1408
|
`Summarization failed during ${preservationReason}; keeping history rather than replacing it with a metadata stub`
|
|
1366
1409
|
);
|
|
1367
1410
|
agentContext.markSummarizationTriggered(state.messages.length);
|
|
1411
|
+
agentContext.recordSummarizationFailure();
|
|
1368
1412
|
/**
|
|
1369
1413
|
* The run step was already dispatched, so it has to be resolved here or
|
|
1370
1414
|
* consumers tracking step lifecycle keep an unfinished placeholder for
|
|
@@ -1393,7 +1437,22 @@ export function createSummarizeNode({
|
|
|
1393
1437
|
}
|
|
1394
1438
|
|
|
1395
1439
|
if (!rawText) {
|
|
1396
|
-
|
|
1440
|
+
/**
|
|
1441
|
+
* An empty summary compacts nothing, so the state the pruner sees next
|
|
1442
|
+
* is byte-identical to the one that just triggered. Resetting the guard
|
|
1443
|
+
* to `0` here made `shouldSkipSummarization` answer `false` forever,
|
|
1444
|
+
* and the agent node re-triggered on that unchanged state until the
|
|
1445
|
+
* graph hit its recursion cap — a loop of empty summary steps, each one
|
|
1446
|
+
* a billed model call. Recording the current count keeps the guard
|
|
1447
|
+
* honest; the failure tally bounds the retries once new messages do
|
|
1448
|
+
* arrive and legitimately lift it.
|
|
1449
|
+
*/
|
|
1450
|
+
agentContext.markSummarizationTriggered(state.messages.length);
|
|
1451
|
+
agentContext.recordSummarizationFailure();
|
|
1452
|
+
log('warn', 'Summarization produced empty output', {
|
|
1453
|
+
failures: agentContext.summarizationFailures,
|
|
1454
|
+
messagesToRefineCount: messagesToRefine.length,
|
|
1455
|
+
});
|
|
1397
1456
|
if (runnableConfig) {
|
|
1398
1457
|
await safeDispatchCustomEvent(
|
|
1399
1458
|
GraphEvents.ON_SUMMARIZE_COMPLETE,
|
|
@@ -1544,12 +1603,15 @@ function extractResponseText(response: { content: string | object }): string {
|
|
|
1544
1603
|
function buildSummarizationInstruction(
|
|
1545
1604
|
promptText: string,
|
|
1546
1605
|
updatePromptText: string | undefined,
|
|
1547
|
-
priorSummaryText: string
|
|
1606
|
+
priorSummaryText: string,
|
|
1607
|
+
semanticIndexAppendix = ''
|
|
1548
1608
|
): string {
|
|
1549
1609
|
const effectivePrompt = priorSummaryText
|
|
1550
1610
|
? (updatePromptText ?? promptText)
|
|
1551
1611
|
: promptText;
|
|
1552
|
-
const parts =
|
|
1612
|
+
const parts = semanticIndexAppendix
|
|
1613
|
+
? [semanticIndexAppendix, '\n\n', effectivePrompt]
|
|
1614
|
+
: [effectivePrompt];
|
|
1553
1615
|
if (priorSummaryText) {
|
|
1554
1616
|
parts.push(
|
|
1555
1617
|
`\n\n<previous-summary>\n${priorSummaryText}\n</previous-summary>`
|
|
@@ -1666,10 +1728,7 @@ export function applySummarizationHistoryCache(params: {
|
|
|
1666
1728
|
if (params.provider === Providers.BEDROCK) {
|
|
1667
1729
|
return addBedrockTailCacheControl(
|
|
1668
1730
|
[...params.messages],
|
|
1669
|
-
resolveBedrockPromptCacheTtl(
|
|
1670
|
-
params.promptCacheTtl,
|
|
1671
|
-
params.bedrockModelId
|
|
1672
|
-
)
|
|
1731
|
+
resolveBedrockPromptCacheTtl(params.promptCacheTtl, params.bedrockModelId)
|
|
1673
1732
|
);
|
|
1674
1733
|
}
|
|
1675
1734
|
if (
|
|
@@ -1685,9 +1744,7 @@ export function applySummarizationHistoryCache(params: {
|
|
|
1685
1744
|
}
|
|
1686
1745
|
|
|
1687
1746
|
export function resolveBedrockCompactionCacheModel(
|
|
1688
|
-
options:
|
|
1689
|
-
| { applicationInferenceProfile?: string; model?: string }
|
|
1690
|
-
| undefined
|
|
1747
|
+
options: { applicationInferenceProfile?: string; model?: string } | undefined
|
|
1691
1748
|
): string | undefined {
|
|
1692
1749
|
return options?.model;
|
|
1693
1750
|
}
|
|
@@ -1705,6 +1762,7 @@ async function summarizeWithCacheHit({
|
|
|
1705
1762
|
promptText,
|
|
1706
1763
|
updatePromptText,
|
|
1707
1764
|
priorSummaryText,
|
|
1765
|
+
semanticIndexAppendix,
|
|
1708
1766
|
config,
|
|
1709
1767
|
stepId,
|
|
1710
1768
|
provider,
|
|
@@ -1720,6 +1778,7 @@ async function summarizeWithCacheHit({
|
|
|
1720
1778
|
promptText: string;
|
|
1721
1779
|
updatePromptText?: string;
|
|
1722
1780
|
priorSummaryText: string;
|
|
1781
|
+
semanticIndexAppendix?: string;
|
|
1723
1782
|
config?: RunnableConfig;
|
|
1724
1783
|
stepId?: string;
|
|
1725
1784
|
provider: t.ProviderName;
|
|
@@ -1733,7 +1792,8 @@ async function summarizeWithCacheHit({
|
|
|
1733
1792
|
const instruction = buildSummarizationInstruction(
|
|
1734
1793
|
promptText,
|
|
1735
1794
|
updatePromptText,
|
|
1736
|
-
priorSummaryText
|
|
1795
|
+
priorSummaryText,
|
|
1796
|
+
semanticIndexAppendix
|
|
1737
1797
|
);
|
|
1738
1798
|
|
|
1739
1799
|
const cachedHistory = applySummarizationHistoryCache({
|
|
@@ -1743,10 +1803,7 @@ async function summarizeWithCacheHit({
|
|
|
1743
1803
|
promptCacheTtl,
|
|
1744
1804
|
bedrockModelId,
|
|
1745
1805
|
});
|
|
1746
|
-
const invokeMessages = [
|
|
1747
|
-
...cachedHistory,
|
|
1748
|
-
new HumanMessage(instruction),
|
|
1749
|
-
];
|
|
1806
|
+
const invokeMessages = [...cachedHistory, new HumanMessage(instruction)];
|
|
1750
1807
|
|
|
1751
1808
|
const result = await attemptInvoke(
|
|
1752
1809
|
{
|