@librechat/agents 3.7.4 → 3.7.6
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/Graph.cjs +16 -16
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/promptCacheTools.cjs +30 -0
- package/dist/cjs/llm/promptCacheTools.cjs.map +1 -0
- package/dist/cjs/summarization/node.cjs +29 -6
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-search.cjs +7 -1
- package/dist/cjs/tools/search/keenable-search.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +18 -18
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/promptCacheTools.mjs +30 -0
- package/dist/esm/llm/promptCacheTools.mjs.map +1 -0
- package/dist/esm/summarization/node.mjs +30 -7
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-search.mjs +7 -1
- package/dist/esm/tools/search/keenable-search.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +1 -0
- package/dist/types/llm/promptCacheTools.d.ts +7 -0
- package/dist/types/summarization/node.d.ts +13 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +32 -74
- package/src/llm/promptCacheTools.ts +58 -0
- package/src/summarization/node.ts +97 -12
- package/src/tools/search/keenable-search.ts +18 -1
|
@@ -5,6 +5,7 @@ import type { AgentContext } from '@/agents/AgentContext';
|
|
|
5
5
|
import type { HookRegistry } from '@/hooks';
|
|
6
6
|
import type { OnChunk } from '@/llm/invoke';
|
|
7
7
|
import type * as t from '@/types';
|
|
8
|
+
import { type PromptCacheTtl } from '@/messages/cache';
|
|
8
9
|
/** Structured checkpoint prompt for fresh summarization (no prior summary). */
|
|
9
10
|
export declare const DEFAULT_SUMMARIZATION_PROMPT = "Hold on, before you continue I need you to write me a checkpoint of everything so far. Your context window is filling up and this checkpoint replaces the messages above, so capture everything you need to pick right back up.\n\nDon't second-guess or fact-check anything you did, your tool results reflect exactly what happened. If a tool result appears truncated, that's just a display artifact from context management: the tool executed fully. Just record what you did and what you observed. Only the checkpoint, don't respond to me or continue the conversation.\n\n## Checkpoint\n\n## Goal\nWhat I asked you to do and any sub-goals you identified.\n\n## Constraints & Preferences\nAny rules, preferences, or configuration I established.\n\n## Progress\n### Done\n- What you completed and the outcomes\n\n### In Progress\n- What you're currently working on\n\n## Key Decisions\nDecisions you made and why.\n\n## Next Steps\nConcrete task actions remaining, in priority order.\n\n## Critical Context\nExact identifiers, names, error messages, URLs, and details you need to preserve verbatim.\n\nRules:\n- Record what you did and observed, don't judge or re-evaluate it\n- For each tool call: the tool name, key inputs, and the outcome\n- Preserve exact identifiers, names, errors, and references verbatim\n- Short declarative sentences\n- Skip empty sections";
|
|
10
11
|
/** Prompt for re-compaction when a prior summary exists. */
|
|
@@ -18,6 +19,7 @@ interface CreateSummarizeNodeParams {
|
|
|
18
19
|
runId?: string;
|
|
19
20
|
isMultiAgent: boolean;
|
|
20
21
|
hookRegistry?: HookRegistry;
|
|
22
|
+
getToolsForBinding?: (provider: t.ProviderName, clientOptions: t.ClientOptions | undefined) => t.GraphTools | undefined;
|
|
21
23
|
dispatchRunStep: (runStep: t.RunStep, config?: RunnableConfig) => Promise<void>;
|
|
22
24
|
dispatchRunStepCompleted: (stepId: string, result: t.StepCompleted, config?: RunnableConfig) => Promise<void>;
|
|
23
25
|
/**
|
|
@@ -58,4 +60,15 @@ export declare function createSummarizationChunkHandler({ stepId, config, provid
|
|
|
58
60
|
getBreakerController?: () => AbortController;
|
|
59
61
|
};
|
|
60
62
|
}): OnChunk | undefined;
|
|
63
|
+
export declare function applySummarizationHistoryCache(params: {
|
|
64
|
+
messages: BaseMessage[];
|
|
65
|
+
provider: t.ProviderName;
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
promptCacheTtl?: PromptCacheTtl;
|
|
68
|
+
bedrockModelId?: string;
|
|
69
|
+
}): BaseMessage[];
|
|
70
|
+
export declare function resolveBedrockCompactionCacheModel(options: {
|
|
71
|
+
applicationInferenceProfile?: string;
|
|
72
|
+
model?: string;
|
|
73
|
+
} | undefined): string | undefined;
|
|
61
74
|
export {};
|
package/package.json
CHANGED
package/src/graphs/Graph.ts
CHANGED
|
@@ -59,14 +59,12 @@ import {
|
|
|
59
59
|
addTailCacheControl,
|
|
60
60
|
resolvePromptCacheTtl,
|
|
61
61
|
resolveBedrockPromptCacheTtl,
|
|
62
|
-
supportsBedrockToolCache,
|
|
63
62
|
isSyntheticProviderContextMessage,
|
|
64
63
|
compactSyntheticProviderContextMessage,
|
|
65
64
|
getMessageId,
|
|
66
65
|
getMessageCreationContentMetadata,
|
|
67
66
|
splitAssistantTextContentByPhase,
|
|
68
67
|
makeIsDeferred,
|
|
69
|
-
partitionAndMarkAnthropicToolCache,
|
|
70
68
|
DEFAULT_RETAIN_RECENT_TURNS,
|
|
71
69
|
resolveIntraTurnRetainTokens,
|
|
72
70
|
splitAtRecencyBoundary,
|
|
@@ -149,14 +147,13 @@ import {
|
|
|
149
147
|
findCallback,
|
|
150
148
|
type CallbackEntry,
|
|
151
149
|
} from '@/utils/callbacks';
|
|
152
|
-
import { partitionAndMarkOpenRouterToolCache } from '@/llm/openrouter/toolCache';
|
|
153
150
|
import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
|
|
154
151
|
import { shouldTraceToolNodeForLangfuse } from '@/langfuseToolOutputTracing';
|
|
155
152
|
import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
|
|
156
153
|
import { SUBAGENT_REPLAY_CONTROLLER } from '@/tools/subagent/SubagentReplay';
|
|
157
154
|
import { applyGraphRuntimeConfig } from '@/graphs/applyGraphRuntimeConfig';
|
|
158
|
-
import { partitionAndMarkBedrockToolCache } from '@/llm/bedrock/toolCache';
|
|
159
155
|
import { createContextPressureMeter } from '@/llm/contextPressureMeter';
|
|
156
|
+
import { prepareToolsForPromptCache } from '@/llm/promptCacheTools';
|
|
160
157
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
161
158
|
import { prepareProviderRequest } from '@/llm/prepareProviderRequest';
|
|
162
159
|
import { createCloudflareCodingToolBundle } from '@/tools/cloudflare';
|
|
@@ -2789,6 +2786,27 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2789
2786
|
};
|
|
2790
2787
|
}
|
|
2791
2788
|
|
|
2789
|
+
private getPreparedToolsForBinding(
|
|
2790
|
+
agentContext: AgentContext,
|
|
2791
|
+
provider: t.ProviderName = agentContext.provider,
|
|
2792
|
+
clientOptions: t.ClientOptions | undefined = agentContext.clientOptions
|
|
2793
|
+
): t.GraphTools | undefined {
|
|
2794
|
+
const tools = resolveLocalToolsForBinding({
|
|
2795
|
+
tools: agentContext.getToolsForBinding(),
|
|
2796
|
+
toolExecution: this.toolExecution,
|
|
2797
|
+
toolRegistry: agentContext.toolRegistry,
|
|
2798
|
+
discoveredToolNames: new Set(agentContext.getDiscoveredTools()),
|
|
2799
|
+
});
|
|
2800
|
+
return prepareToolsForPromptCache({
|
|
2801
|
+
provider,
|
|
2802
|
+
clientOptions,
|
|
2803
|
+
tools,
|
|
2804
|
+
isDeferred: makeIsDeferred(
|
|
2805
|
+
agentContext.getEffectiveToolDefinitions()
|
|
2806
|
+
),
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2792
2810
|
createCallModel(agentId = 'default') {
|
|
2793
2811
|
return async (
|
|
2794
2812
|
state: t.AgentSubgraphState,
|
|
@@ -2846,13 +2864,6 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2846
2864
|
agentContext.markToolsAsDiscovered(discoveredNames);
|
|
2847
2865
|
}
|
|
2848
2866
|
|
|
2849
|
-
const rawToolsForBinding = resolveLocalToolsForBinding({
|
|
2850
|
-
tools: agentContext.getToolsForBinding(),
|
|
2851
|
-
toolExecution: this.toolExecution,
|
|
2852
|
-
toolRegistry: agentContext.toolRegistry,
|
|
2853
|
-
discoveredToolNames: new Set(agentContext.getDiscoveredTools()),
|
|
2854
|
-
});
|
|
2855
|
-
|
|
2856
2867
|
/**
|
|
2857
2868
|
* Anthropic prompt-cache breakpoint on the tool definitions.
|
|
2858
2869
|
*
|
|
@@ -2866,69 +2877,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2866
2877
|
* Discovered deferred tools that arrive across turns sit *after*
|
|
2867
2878
|
* the breakpoint and don't invalidate the prefix.
|
|
2868
2879
|
*/
|
|
2869
|
-
|
|
2870
|
-
const isDeferredTool = makeIsDeferred(
|
|
2871
|
-
agentContext.getEffectiveToolDefinitions()
|
|
2872
|
-
);
|
|
2873
|
-
if (
|
|
2874
|
-
agentContext.provider === Providers.ANTHROPIC &&
|
|
2875
|
-
(agentContext.clientOptions as t.AnthropicClientOptions | undefined)
|
|
2876
|
-
?.promptCache === true
|
|
2877
|
-
) {
|
|
2878
|
-
toolsForBinding =
|
|
2879
|
-
partitionAndMarkAnthropicToolCache(
|
|
2880
|
-
rawToolsForBinding,
|
|
2881
|
-
isDeferredTool,
|
|
2882
|
-
resolvePromptCacheTtl(
|
|
2883
|
-
(
|
|
2884
|
-
agentContext.clientOptions as
|
|
2885
|
-
| t.AnthropicClientOptions
|
|
2886
|
-
| undefined
|
|
2887
|
-
)?.promptCacheTtl
|
|
2888
|
-
)
|
|
2889
|
-
) ?? rawToolsForBinding;
|
|
2890
|
-
} else if (
|
|
2891
|
-
agentContext.provider === Providers.OPENROUTER &&
|
|
2892
|
-
(
|
|
2893
|
-
agentContext.clientOptions as
|
|
2894
|
-
| t.ProviderOptionsMap[Providers.OPENROUTER]
|
|
2895
|
-
| undefined
|
|
2896
|
-
)?.promptCache === true
|
|
2897
|
-
) {
|
|
2898
|
-
toolsForBinding =
|
|
2899
|
-
partitionAndMarkOpenRouterToolCache(
|
|
2900
|
-
rawToolsForBinding,
|
|
2901
|
-
isDeferredTool,
|
|
2902
|
-
resolvePromptCacheTtl(
|
|
2903
|
-
(
|
|
2904
|
-
agentContext.clientOptions as
|
|
2905
|
-
| t.ProviderOptionsMap[Providers.OPENROUTER]
|
|
2906
|
-
| undefined
|
|
2907
|
-
)?.promptCacheTtl
|
|
2908
|
-
)
|
|
2909
|
-
) ?? rawToolsForBinding;
|
|
2910
|
-
} else if (
|
|
2911
|
-
agentContext.provider === Providers.BEDROCK &&
|
|
2912
|
-
(
|
|
2913
|
-
agentContext.clientOptions as
|
|
2914
|
-
| t.BedrockAnthropicClientOptions
|
|
2915
|
-
| undefined
|
|
2916
|
-
)?.promptCache === true
|
|
2917
|
-
) {
|
|
2918
|
-
const bedrockModel = (
|
|
2919
|
-
agentContext.clientOptions as { model?: string } | undefined
|
|
2920
|
-
)?.model;
|
|
2921
|
-
// An omitted model falls back to LangChain's default Claude model (which
|
|
2922
|
-
// supports tool caching); only an explicit non-Claude model (e.g. Nova)
|
|
2923
|
-
// skips tool marking so its stray marker never leaks into toolConfig.
|
|
2924
|
-
if (bedrockModel == null || supportsBedrockToolCache(bedrockModel)) {
|
|
2925
|
-
toolsForBinding =
|
|
2926
|
-
partitionAndMarkBedrockToolCache(
|
|
2927
|
-
rawToolsForBinding,
|
|
2928
|
-
isDeferredTool
|
|
2929
|
-
) ?? rawToolsForBinding;
|
|
2930
|
-
}
|
|
2931
|
-
}
|
|
2880
|
+
const toolsForBinding = this.getPreparedToolsForBinding(agentContext);
|
|
2932
2881
|
|
|
2933
2882
|
let model =
|
|
2934
2883
|
this.overrideModel ??
|
|
@@ -4924,6 +4873,15 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4924
4873
|
runId: this.runId,
|
|
4925
4874
|
isMultiAgent: this.isMultiAgentGraph(),
|
|
4926
4875
|
hookRegistry: this.hookRegistry,
|
|
4876
|
+
getToolsForBinding: (
|
|
4877
|
+
provider: t.ProviderName,
|
|
4878
|
+
clientOptions: t.ClientOptions | undefined
|
|
4879
|
+
): t.GraphTools | undefined =>
|
|
4880
|
+
this.getPreparedToolsForBinding(
|
|
4881
|
+
agentContext,
|
|
4882
|
+
provider,
|
|
4883
|
+
clientOptions
|
|
4884
|
+
),
|
|
4927
4885
|
/**
|
|
4928
4886
|
* Live references (both maps are cleared in place, never
|
|
4929
4887
|
* replaced), so summarization streams share the run's event
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type * as t from '@/types';
|
|
2
|
+
import {
|
|
3
|
+
resolvePromptCacheTtl,
|
|
4
|
+
supportsBedrockToolCache,
|
|
5
|
+
} from '@/messages/cache';
|
|
6
|
+
import { partitionAndMarkAnthropicToolCache } from '@/messages/anthropicToolCache';
|
|
7
|
+
import { partitionAndMarkOpenRouterToolCache } from '@/llm/openrouter/toolCache';
|
|
8
|
+
import { partitionAndMarkBedrockToolCache } from '@/llm/bedrock/toolCache';
|
|
9
|
+
import { Providers } from '@/common';
|
|
10
|
+
|
|
11
|
+
export function prepareToolsForPromptCache(params: {
|
|
12
|
+
provider: t.ProviderName;
|
|
13
|
+
clientOptions?: t.ClientOptions;
|
|
14
|
+
tools?: t.GraphTools;
|
|
15
|
+
isDeferred: (toolName: string) => boolean;
|
|
16
|
+
}): t.GraphTools | undefined {
|
|
17
|
+
const { provider, clientOptions, tools, isDeferred } = params;
|
|
18
|
+
if (provider === Providers.ANTHROPIC) {
|
|
19
|
+
const options = clientOptions as t.AnthropicClientOptions | undefined;
|
|
20
|
+
if (options?.promptCache !== true) {
|
|
21
|
+
return tools;
|
|
22
|
+
}
|
|
23
|
+
return (
|
|
24
|
+
partitionAndMarkAnthropicToolCache(
|
|
25
|
+
tools,
|
|
26
|
+
isDeferred,
|
|
27
|
+
resolvePromptCacheTtl(options.promptCacheTtl)
|
|
28
|
+
) ?? tools
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
if (provider === Providers.OPENROUTER) {
|
|
32
|
+
const options = clientOptions as
|
|
33
|
+
| t.ProviderOptionsMap[Providers.OPENROUTER]
|
|
34
|
+
| undefined;
|
|
35
|
+
if (options?.promptCache !== true) {
|
|
36
|
+
return tools;
|
|
37
|
+
}
|
|
38
|
+
return (
|
|
39
|
+
partitionAndMarkOpenRouterToolCache(
|
|
40
|
+
tools,
|
|
41
|
+
isDeferred,
|
|
42
|
+
resolvePromptCacheTtl(options.promptCacheTtl)
|
|
43
|
+
) ?? tools
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (provider !== Providers.BEDROCK) {
|
|
47
|
+
return tools;
|
|
48
|
+
}
|
|
49
|
+
const options = clientOptions as t.BedrockAnthropicClientOptions | undefined;
|
|
50
|
+
if (options?.promptCache !== true) {
|
|
51
|
+
return tools;
|
|
52
|
+
}
|
|
53
|
+
const model = (options as { model?: string }).model;
|
|
54
|
+
if (model != null && !supportsBedrockToolCache(model)) {
|
|
55
|
+
return tools;
|
|
56
|
+
}
|
|
57
|
+
return partitionAndMarkBedrockToolCache(tools, isDeferred) ?? tools;
|
|
58
|
+
}
|
|
@@ -24,7 +24,9 @@ import {
|
|
|
24
24
|
} from '@/llm/streamLimits';
|
|
25
25
|
import {
|
|
26
26
|
addTailCacheControl,
|
|
27
|
+
addBedrockTailCacheControl,
|
|
27
28
|
resolvePromptCacheTtl,
|
|
29
|
+
resolveBedrockPromptCacheTtl,
|
|
28
30
|
type PromptCacheTtl,
|
|
29
31
|
} from '@/messages/cache';
|
|
30
32
|
import {
|
|
@@ -41,7 +43,9 @@ import {
|
|
|
41
43
|
} from '@/common';
|
|
42
44
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
43
45
|
import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
|
|
46
|
+
import { prepareToolsForPromptCache } from '@/llm/promptCacheTools';
|
|
44
47
|
import { calculateMaxToolResultChars } from '@/utils/truncation';
|
|
48
|
+
import { makeIsDeferred } from '@/messages/anthropicToolCache';
|
|
45
49
|
import { createRemoveAllMessage } from '@/messages/reducer';
|
|
46
50
|
import { getMaxOutputTokensKey } from '@/llm/request';
|
|
47
51
|
import { initializeModel } from '@/llm/init';
|
|
@@ -623,7 +627,13 @@ async function executeSummarizationWithFallback(params: {
|
|
|
623
627
|
usePromptCache: boolean;
|
|
624
628
|
log: LogFn;
|
|
625
629
|
/** Carries the run's stream limits so the event cap covers summary streams. */
|
|
626
|
-
graph?: StreamLimitState & {
|
|
630
|
+
graph?: StreamLimitState & {
|
|
631
|
+
getBreakerSignal?: () => AbortSignal;
|
|
632
|
+
getToolsForBinding?: (
|
|
633
|
+
provider: t.ProviderName,
|
|
634
|
+
clientOptions: t.ClientOptions | undefined
|
|
635
|
+
) => t.GraphTools | undefined;
|
|
636
|
+
};
|
|
627
637
|
}): Promise<{
|
|
628
638
|
text: string;
|
|
629
639
|
usage?: Partial<UsageMetadata>;
|
|
@@ -657,10 +667,24 @@ async function executeSummarizationWithFallback(params: {
|
|
|
657
667
|
* (e.g. an unrecognized summarization.provider) surfaces through the
|
|
658
668
|
* `log('error', ...)` path below rather than bubbling up silently.
|
|
659
669
|
*/
|
|
670
|
+
const summarizationTools = usePromptCache
|
|
671
|
+
? (graph?.getToolsForBinding?.(
|
|
672
|
+
clientConfig.provider as t.ProviderName,
|
|
673
|
+
clientConfig.clientOptions as t.ClientOptions
|
|
674
|
+
) ??
|
|
675
|
+
prepareToolsForPromptCache({
|
|
676
|
+
provider: clientConfig.provider as t.ProviderName,
|
|
677
|
+
clientOptions: clientConfig.clientOptions as t.ClientOptions,
|
|
678
|
+
tools: agentContext.getToolsForBinding(),
|
|
679
|
+
isDeferred: makeIsDeferred(
|
|
680
|
+
agentContext.getEffectiveToolDefinitions()
|
|
681
|
+
),
|
|
682
|
+
}))
|
|
683
|
+
: agentContext.getToolsForBinding();
|
|
660
684
|
const summarizationModel = initializeModel({
|
|
661
685
|
provider: clientConfig.provider,
|
|
662
686
|
clientOptions: clientConfig.clientOptions as t.ClientOptions,
|
|
663
|
-
tools:
|
|
687
|
+
tools: summarizationTools,
|
|
664
688
|
}) as t.ChatModel;
|
|
665
689
|
|
|
666
690
|
const result = await summarizeWithCacheHit({
|
|
@@ -677,13 +701,23 @@ async function executeSummarizationWithFallback(params: {
|
|
|
677
701
|
usePromptCache,
|
|
678
702
|
promptCacheTtl:
|
|
679
703
|
clientConfig.provider === Providers.ANTHROPIC ||
|
|
680
|
-
clientConfig.provider === Providers.OPENROUTER
|
|
681
|
-
|
|
682
|
-
|
|
704
|
+
clientConfig.provider === Providers.OPENROUTER ||
|
|
705
|
+
clientConfig.provider === Providers.BEDROCK
|
|
706
|
+
? (
|
|
683
707
|
clientConfig.clientOptions as {
|
|
684
708
|
promptCacheTtl?: PromptCacheTtl;
|
|
685
709
|
}
|
|
686
|
-
|
|
710
|
+
).promptCacheTtl
|
|
711
|
+
: undefined,
|
|
712
|
+
bedrockModelId:
|
|
713
|
+
clientConfig.provider === Providers.BEDROCK
|
|
714
|
+
? resolveBedrockCompactionCacheModel(
|
|
715
|
+
clientConfig.clientOptions as
|
|
716
|
+
| {
|
|
717
|
+
applicationInferenceProfile?: string;
|
|
718
|
+
model?: string;
|
|
719
|
+
}
|
|
720
|
+
| undefined
|
|
687
721
|
)
|
|
688
722
|
: undefined,
|
|
689
723
|
log,
|
|
@@ -900,6 +934,10 @@ interface CreateSummarizeNodeParams {
|
|
|
900
934
|
runId?: string;
|
|
901
935
|
isMultiAgent: boolean;
|
|
902
936
|
hookRegistry?: HookRegistry;
|
|
937
|
+
getToolsForBinding?: (
|
|
938
|
+
provider: t.ProviderName,
|
|
939
|
+
clientOptions: t.ClientOptions | undefined
|
|
940
|
+
) => t.GraphTools | undefined;
|
|
903
941
|
dispatchRunStep: (
|
|
904
942
|
runStep: t.RunStep,
|
|
905
943
|
config?: RunnableConfig
|
|
@@ -1221,7 +1259,7 @@ export function createSummarizeNode({
|
|
|
1221
1259
|
clientConfig.provider === (agentContext.provider as string);
|
|
1222
1260
|
const hasPromptCache =
|
|
1223
1261
|
isSelfSummarizeModel &&
|
|
1224
|
-
(
|
|
1262
|
+
(clientConfig.clientOptions as Record<string, unknown> | undefined)
|
|
1225
1263
|
?.promptCache === true;
|
|
1226
1264
|
|
|
1227
1265
|
const log: LogFn = (level, message, data) => {
|
|
@@ -1615,6 +1653,45 @@ function traceConfig(
|
|
|
1615
1653
|
};
|
|
1616
1654
|
}
|
|
1617
1655
|
|
|
1656
|
+
export function applySummarizationHistoryCache(params: {
|
|
1657
|
+
messages: BaseMessage[];
|
|
1658
|
+
provider: t.ProviderName;
|
|
1659
|
+
enabled: boolean;
|
|
1660
|
+
promptCacheTtl?: PromptCacheTtl;
|
|
1661
|
+
bedrockModelId?: string;
|
|
1662
|
+
}): BaseMessage[] {
|
|
1663
|
+
if (!params.enabled) {
|
|
1664
|
+
return params.messages;
|
|
1665
|
+
}
|
|
1666
|
+
if (params.provider === Providers.BEDROCK) {
|
|
1667
|
+
return addBedrockTailCacheControl(
|
|
1668
|
+
[...params.messages],
|
|
1669
|
+
resolveBedrockPromptCacheTtl(
|
|
1670
|
+
params.promptCacheTtl,
|
|
1671
|
+
params.bedrockModelId
|
|
1672
|
+
)
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
if (
|
|
1676
|
+
params.provider !== Providers.ANTHROPIC &&
|
|
1677
|
+
params.provider !== Providers.OPENROUTER
|
|
1678
|
+
) {
|
|
1679
|
+
return params.messages;
|
|
1680
|
+
}
|
|
1681
|
+
return addTailCacheControl(
|
|
1682
|
+
[...params.messages],
|
|
1683
|
+
resolvePromptCacheTtl(params.promptCacheTtl)
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
export function resolveBedrockCompactionCacheModel(
|
|
1688
|
+
options:
|
|
1689
|
+
| { applicationInferenceProfile?: string; model?: string }
|
|
1690
|
+
| undefined
|
|
1691
|
+
): string | undefined {
|
|
1692
|
+
return options?.model;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1618
1695
|
/**
|
|
1619
1696
|
* Cache-friendly compaction: sends raw conversation messages with the
|
|
1620
1697
|
* summarization instruction appended as the final HumanMessage. Bound tool
|
|
@@ -1635,6 +1712,7 @@ async function summarizeWithCacheHit({
|
|
|
1635
1712
|
graph,
|
|
1636
1713
|
usePromptCache,
|
|
1637
1714
|
promptCacheTtl,
|
|
1715
|
+
bedrockModelId,
|
|
1638
1716
|
log,
|
|
1639
1717
|
}: {
|
|
1640
1718
|
model: t.ChatModel;
|
|
@@ -1649,6 +1727,7 @@ async function summarizeWithCacheHit({
|
|
|
1649
1727
|
graph?: StreamLimitState & { getBreakerSignal?: () => AbortSignal };
|
|
1650
1728
|
usePromptCache?: boolean;
|
|
1651
1729
|
promptCacheTtl?: PromptCacheTtl;
|
|
1730
|
+
bedrockModelId?: string;
|
|
1652
1731
|
log?: LogFn;
|
|
1653
1732
|
}): Promise<{ text: string; usage?: Partial<UsageMetadata> }> {
|
|
1654
1733
|
const instruction = buildSummarizationInstruction(
|
|
@@ -1657,11 +1736,17 @@ async function summarizeWithCacheHit({
|
|
|
1657
1736
|
priorSummaryText
|
|
1658
1737
|
);
|
|
1659
1738
|
|
|
1660
|
-
const
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1739
|
+
const cachedHistory = applySummarizationHistoryCache({
|
|
1740
|
+
messages,
|
|
1741
|
+
provider,
|
|
1742
|
+
enabled: usePromptCache === true,
|
|
1743
|
+
promptCacheTtl,
|
|
1744
|
+
bedrockModelId,
|
|
1745
|
+
});
|
|
1746
|
+
const invokeMessages = [
|
|
1747
|
+
...cachedHistory,
|
|
1748
|
+
new HumanMessage(instruction),
|
|
1749
|
+
];
|
|
1665
1750
|
|
|
1666
1751
|
const result = await attemptInvoke(
|
|
1667
1752
|
{
|
|
@@ -16,6 +16,23 @@ const KEENABLE_DATE_RANGES: Record<DATE_RANGE, string> = {
|
|
|
16
16
|
[DATE_RANGE.PAST_YEAR]: '1y',
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/** Characters of page text kept per result. Keenable returns the whole page on
|
|
20
|
+
* every search result, an order of magnitude more than the other providers here
|
|
21
|
+
* return, which would crowd out the reranker and the LLM output budget. */
|
|
22
|
+
const SNIPPET_MAX_LENGTH = 500;
|
|
23
|
+
|
|
24
|
+
/** Keenable sends both `description` and `snippet` on every result: `snippet`
|
|
25
|
+
* carries the page text and `description` is the page's meta description, which
|
|
26
|
+
* is empty for most pages. Either field can arrive as an empty string, so the
|
|
27
|
+
* pick is on emptiness rather than nullishness: a `??` chain would keep an empty
|
|
28
|
+
* `snippet` over a `description` that does carry text. */
|
|
29
|
+
function toSnippet(result: t.KeenableSearchResult): string {
|
|
30
|
+
const snippet = (result.snippet ?? '').replace(/\s+/g, ' ').trim();
|
|
31
|
+
const description = (result.description ?? '').replace(/\s+/g, ' ').trim();
|
|
32
|
+
const text = snippet !== '' ? snippet : description;
|
|
33
|
+
return text.slice(0, SNIPPET_MAX_LENGTH);
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
export const createKeenableAPI = (
|
|
20
37
|
apiKey?: string,
|
|
21
38
|
apiUrl?: string,
|
|
@@ -84,7 +101,7 @@ export const createKeenableAPI = (
|
|
|
84
101
|
const organic: t.OrganicResult[] = rawResults.map((result) => ({
|
|
85
102
|
title: result.title ?? '',
|
|
86
103
|
link: result.url ?? '',
|
|
87
|
-
snippet: result
|
|
104
|
+
snippet: toSnippet(result),
|
|
88
105
|
date: result.published_at,
|
|
89
106
|
}));
|
|
90
107
|
|