@librechat/agents 3.7.8 → 3.7.10
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 +3 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +2 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +40 -6
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +8 -0
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs +2 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +43 -3
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +2 -6
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/request.cjs +6 -0
- package/dist/cjs/llm/request.cjs.map +1 -1
- package/dist/cjs/main.cjs +19 -11
- package/dist/cjs/messages/format.cjs +95 -18
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/run.cjs +201 -46
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
- package/dist/cjs/summarization/index.cjs +1 -0
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +24 -85
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/semanticIndex.cjs +7 -3
- package/dist/cjs/summarization/semanticIndex.cjs.map +1 -1
- package/dist/cjs/summarization/shared.cjs +83 -0
- package/dist/cjs/summarization/shared.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +5 -5
- package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs.map +1 -1
- package/dist/cjs/tools/search/metrics.cjs +234 -0
- package/dist/cjs/tools/search/metrics.cjs.map +1 -0
- package/dist/cjs/tools/search/rerankers.cjs +80 -68
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +95 -45
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +77 -49
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +8 -12
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +8 -1
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +3 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +2 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +40 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/executeHooks.mjs +8 -1
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs +2 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +43 -3
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +2 -6
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/request.mjs +6 -1
- package/dist/esm/llm/request.mjs.map +1 -1
- package/dist/esm/main.mjs +13 -12
- package/dist/esm/messages/format.mjs +96 -19
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/run.mjs +201 -46
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +1 -1
- package/dist/esm/summarization/index.mjs +1 -0
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +21 -82
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/semanticIndex.mjs +7 -4
- package/dist/esm/summarization/semanticIndex.mjs.map +1 -1
- package/dist/esm/summarization/shared.mjs +79 -0
- package/dist/esm/summarization/shared.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +5 -5
- package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs.map +1 -1
- package/dist/esm/tools/search/metrics.mjs +234 -0
- package/dist/esm/tools/search/metrics.mjs.map +1 -0
- package/dist/esm/tools/search/rerankers.mjs +80 -68
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +96 -46
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +77 -49
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +8 -12
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +8 -2
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/common/constants.d.ts +7 -0
- package/dist/types/graphs/Graph.d.ts +9 -0
- package/dist/types/hooks/executeHooks.d.ts +5 -2
- package/dist/types/hooks/index.d.ts +7 -2
- package/dist/types/hooks/types.d.ts +45 -7
- package/dist/types/langfuse.d.ts +3 -1
- package/dist/types/llm/request.d.ts +10 -0
- package/dist/types/messages/format.d.ts +8 -2
- package/dist/types/run.d.ts +2 -1
- package/dist/types/summarization/index.d.ts +6 -0
- package/dist/types/summarization/node.d.ts +0 -4
- package/dist/types/summarization/semanticIndex.d.ts +2 -0
- package/dist/types/summarization/shared.d.ts +25 -0
- package/dist/types/tools/search/metrics.d.ts +15 -0
- package/dist/types/tools/search/rerankers.d.ts +30 -5
- package/dist/types/tools/search/tool.d.ts +7 -1
- package/dist/types/tools/search/types.d.ts +88 -4
- package/dist/types/tools/search/utils.d.ts +2 -10
- package/dist/types/types/run.d.ts +8 -0
- package/dist/types/types/stream.d.ts +6 -0
- package/dist/types/types/summarize.d.ts +6 -0
- package/dist/types/utils/tokens.d.ts +9 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +2 -5
- package/src/common/constants.ts +8 -0
- package/src/graphs/Graph.ts +45 -0
- package/src/hooks/HookRegistry.ts +3 -1
- package/src/hooks/executeHooks.ts +20 -2
- package/src/hooks/index.ts +12 -1
- package/src/hooks/types.ts +47 -4
- package/src/langfuse.ts +70 -0
- package/src/llm/invoke.ts +13 -29
- package/src/llm/request.ts +24 -0
- package/src/messages/format.ts +213 -27
- package/src/run.ts +366 -186
- package/src/summarization/index.ts +11 -0
- package/src/summarization/node.ts +117 -130
- package/src/summarization/semanticIndex.ts +16 -7
- package/src/summarization/shared.ts +130 -0
- package/src/tools/runStepResume.ts +9 -0
- package/src/tools/search/metrics.ts +400 -0
- package/src/tools/search/rerankers.ts +160 -97
- package/src/tools/search/search.ts +139 -56
- package/src/tools/search/tool.ts +126 -62
- package/src/tools/search/types.ts +104 -4
- package/src/tools/search/utils.ts +2 -10
- package/src/tools/subagent/SubagentExecutor.ts +4 -27
- package/src/types/run.ts +8 -0
- package/src/types/stream.ts +6 -0
- package/src/types/summarize.ts +7 -0
- package/src/utils/tokens.ts +31 -8
|
@@ -6,10 +6,6 @@ import type { HookRegistry } from '@/hooks';
|
|
|
6
6
|
import type { OnChunk } from '@/llm/invoke';
|
|
7
7
|
import type * as t from '@/types';
|
|
8
8
|
import { type PromptCacheTtl } from '@/messages/cache';
|
|
9
|
-
/** Structured checkpoint prompt for fresh summarization (no prior summary). */
|
|
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";
|
|
11
|
-
/** Prompt for re-compaction when a prior summary exists. */
|
|
12
|
-
export declare const DEFAULT_UPDATE_SUMMARIZATION_PROMPT = "Hold on again, update your checkpoint. Merge the new messages into your existing checkpoint and give me a single consolidated replacement.\n\nKeep it roughly the same length as your last checkpoint. Compress older details to make room for what's new, don't just append. Give recent actions more detail, compress older items to one-liners.\n\nDon't fact-check or second-guess anything, your tool results are ground truth. If a tool result appears truncated, that's just a display artifact: the tool executed fully. Only the checkpoint, don't respond to me or continue the conversation.\n\nRules:\n- Merge new progress into existing sections, don't duplicate headers\n- Compress older completed items into one-line entries\n- Move items from \"In Progress\" to \"Done\" when you completed them\n- Update \"Next Steps\" to reflect current task priorities.\n- For each new tool call: the tool name, key inputs, and the outcome\n- Preserve exact identifiers, names, errors, and references verbatim\n- Skip empty sections";
|
|
13
9
|
interface CreateSummarizeNodeParams {
|
|
14
10
|
agentContext: AgentContext;
|
|
15
11
|
graph: {
|
|
@@ -3,6 +3,8 @@ import type { CompactionSemanticIndex } from '@/types';
|
|
|
3
3
|
export { COMPACTION_SEMANTIC_INDEX_LIMITS } from '@/common';
|
|
4
4
|
/** Records producer-side omissions without retaining the discarded entries. */
|
|
5
5
|
export declare function setCompactionSemanticIndexProvidedEntryCount(index: CompactionSemanticIndex, providedEntryCount: number): void;
|
|
6
|
+
/** Reads producer-side cardinality without exposing snapshot bookkeeping. */
|
|
7
|
+
export declare function getCompactionSemanticIndexProvidedEntryCount(index: CompactionSemanticIndex): number;
|
|
6
8
|
export type RenderedCompactionSemanticIndex = {
|
|
7
9
|
appendix: string;
|
|
8
10
|
providedEntryCount: number;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarization primitives shared by the in-run summarize node and by callers
|
|
3
|
+
* that compact a conversation outside a run. Kept apart from `node.ts` so the
|
|
4
|
+
* package can export them without exporting the graph node itself.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Wraps a persisted summary in the carrier it is re-injected as, ahead of the
|
|
8
|
+
* messages that survived compaction.
|
|
9
|
+
*
|
|
10
|
+
* A stored summary costs what this returns, not what its body costs, so a
|
|
11
|
+
* caller budgeting for one measures this rather than adding a remembered
|
|
12
|
+
* constant to the bare text. The wrapper alone is ~48 tokens on `o200k_base`
|
|
13
|
+
* and more on Anthropic: too much to leave out of a context calculation, and
|
|
14
|
+
* too easy to get wrong from memory once the instruction is edited.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildSummaryCarrierText(summaryText: string): string;
|
|
17
|
+
/** Structured checkpoint prompt for fresh summarization (no prior summary). */
|
|
18
|
+
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";
|
|
19
|
+
/** Prompt for re-compaction when a prior summary exists. */
|
|
20
|
+
export declare const DEFAULT_UPDATE_SUMMARIZATION_PROMPT = "Hold on again, update your checkpoint. Merge the new messages into your existing checkpoint and give me a single consolidated replacement.\n\nKeep it roughly the same length as your last checkpoint. Compress older details to make room for what's new, don't just append. Give recent actions more detail, compress older items to one-liners.\n\nDon't fact-check or second-guess anything, your tool results are ground truth. If a tool result appears truncated, that's just a display artifact: the tool executed fully. Only the checkpoint, don't respond to me or continue the conversation.\n\nRules:\n- Merge new progress into existing sections, don't duplicate headers\n- Compress older completed items into one-line entries\n- Move items from \"In Progress\" to \"Done\" when you completed them\n- Update \"Next Steps\" to reflect current task priorities.\n- For each new tool call: the tool name, key inputs, and the outcome\n- Preserve exact identifiers, names, errors, and references verbatim\n- Skip empty sections";
|
|
21
|
+
export declare function separateSummarizationParameters(parameters: Record<string, unknown>): {
|
|
22
|
+
llmParams: Record<string, unknown>;
|
|
23
|
+
maxSummaryTokens?: number;
|
|
24
|
+
};
|
|
25
|
+
export declare function buildSummarizationInstruction(promptText: string, updatePromptText: string | undefined, priorSummaryText?: string, semanticIndexAppendix?: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type * as t from './types';
|
|
2
|
+
export declare const classifyFailure: (message?: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Creates the counter set for one `web_search` call.
|
|
5
|
+
*
|
|
6
|
+
* The pipeline reranks once per scraped source and scrapes once per link, so
|
|
7
|
+
* logging at those points scales the log with the result count. Every phase
|
|
8
|
+
* records into fixed-width counters instead and {@link t.SearchMetrics.flush}
|
|
9
|
+
* emits one line per phase, at the highest severity that phase reached.
|
|
10
|
+
*
|
|
11
|
+
* @param autoFlush emit on every record, for a caller with no enclosing search
|
|
12
|
+
* to fold into (a reranker used directly). Recording is synchronous, so the
|
|
13
|
+
* record/flush/reset cycle can never interleave with a concurrent call.
|
|
14
|
+
*/
|
|
15
|
+
export declare const createSearchMetrics: (logger: t.Logger, autoFlush?: boolean) => t.SearchMetrics;
|
|
@@ -2,11 +2,33 @@ import type * as t from './types';
|
|
|
2
2
|
export declare abstract class BaseReranker {
|
|
3
3
|
protected apiKey: string | undefined;
|
|
4
4
|
protected logger: t.Logger;
|
|
5
|
+
/** Public so a caller that fails before reaching `rerank` can still
|
|
6
|
+
* attribute the attempt to the configured reranker. */
|
|
7
|
+
abstract readonly provider: string;
|
|
8
|
+
private ownMetrics?;
|
|
5
9
|
constructor(logger?: t.Logger);
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* A search reranks once per scraped source, so nothing here logs per call:
|
|
12
|
+
* every exit records one observation through `metrics` and the enclosing
|
|
13
|
+
* search emits a single summary. `metrics` is optional only for direct use
|
|
14
|
+
* of a reranker, which falls back to an auto-flushing collector.
|
|
15
|
+
*/
|
|
16
|
+
abstract rerank(query: string, documents: string[], topK?: number, metrics?: t.SearchMetrics): Promise<t.Highlight[]>;
|
|
7
17
|
protected getDefaultRanking(documents: string[], topK: number): t.Highlight[];
|
|
18
|
+
/** A direct caller has no enclosing search to fold into, so one
|
|
19
|
+
* auto-flushing collector per instance emits that call's summary on its
|
|
20
|
+
* own; record and flush run synchronously, so concurrent calls on the same
|
|
21
|
+
* instance cannot share a total. */
|
|
22
|
+
private localMetrics;
|
|
23
|
+
/** Opens the per-call state every exit path records against. */
|
|
24
|
+
protected beginRerank(documents: string[], topK: number, metrics?: t.SearchMetrics): t.RerankRun;
|
|
25
|
+
private record;
|
|
26
|
+
protected complete(run: t.RerankRun, highlights: t.Highlight[]): t.Highlight[];
|
|
27
|
+
/** Records the call as a fallback and returns the candidates' input order. */
|
|
28
|
+
protected fallback(run: t.RerankRun, reason: t.RerankFallback, error?: t.SafeErrorLog): t.Highlight[];
|
|
8
29
|
}
|
|
9
30
|
export declare class JinaReranker extends BaseReranker {
|
|
31
|
+
readonly provider = "jina";
|
|
10
32
|
private apiUrl;
|
|
11
33
|
private timeout;
|
|
12
34
|
private httpAgent?;
|
|
@@ -17,9 +39,10 @@ export declare class JinaReranker extends BaseReranker {
|
|
|
17
39
|
timeout?: number;
|
|
18
40
|
logger?: t.Logger;
|
|
19
41
|
} & t.HttpAgentConfig);
|
|
20
|
-
rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
|
|
42
|
+
rerank(query: string, documents: string[], topK?: number, metrics?: t.SearchMetrics): Promise<t.Highlight[]>;
|
|
21
43
|
}
|
|
22
44
|
export declare class CohereReranker extends BaseReranker {
|
|
45
|
+
readonly provider = "cohere";
|
|
23
46
|
private timeout;
|
|
24
47
|
private httpAgent?;
|
|
25
48
|
private httpsAgent?;
|
|
@@ -28,7 +51,7 @@ export declare class CohereReranker extends BaseReranker {
|
|
|
28
51
|
timeout?: number;
|
|
29
52
|
logger?: t.Logger;
|
|
30
53
|
} & t.HttpAgentConfig);
|
|
31
|
-
rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
|
|
54
|
+
rerank(query: string, documents: string[], topK?: number, metrics?: t.SearchMetrics): Promise<t.Highlight[]>;
|
|
32
55
|
}
|
|
33
56
|
/**
|
|
34
57
|
* Calls the public `danny-avila/rag_api` `/v1/rerank` endpoint (the
|
|
@@ -40,6 +63,7 @@ export declare class CohereReranker extends BaseReranker {
|
|
|
40
63
|
* to the candidates' original order via {@link BaseReranker.getDefaultRanking}.
|
|
41
64
|
*/
|
|
42
65
|
export declare class RagApiReranker extends BaseReranker {
|
|
66
|
+
readonly provider = "rag-api";
|
|
43
67
|
private baseUrl?;
|
|
44
68
|
private tokenSupplier?;
|
|
45
69
|
private profile;
|
|
@@ -53,11 +77,12 @@ export declare class RagApiReranker extends BaseReranker {
|
|
|
53
77
|
timeout?: number;
|
|
54
78
|
logger?: t.Logger;
|
|
55
79
|
} & t.HttpAgentConfig);
|
|
56
|
-
rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
|
|
80
|
+
rerank(query: string, documents: string[], topK?: number, metrics?: t.SearchMetrics): Promise<t.Highlight[]>;
|
|
57
81
|
}
|
|
58
82
|
export declare class InfinityReranker extends BaseReranker {
|
|
83
|
+
readonly provider = "infinity";
|
|
59
84
|
constructor(logger?: t.Logger);
|
|
60
|
-
rerank(query: string, documents: string[], topK?: number): Promise<t.Highlight[]>;
|
|
85
|
+
rerank(query: string, documents: string[], topK?: number, metrics?: t.SearchMetrics): Promise<t.Highlight[]>;
|
|
61
86
|
}
|
|
62
87
|
/**
|
|
63
88
|
* Creates the appropriate reranker based on type and configuration
|
|
@@ -24,7 +24,7 @@ export declare function resolveSearchOutcome(data: t.SearchResultData, query: st
|
|
|
24
24
|
* Executes parallel searches and merges the results,
|
|
25
25
|
* deduplicating top stories by link
|
|
26
26
|
*/
|
|
27
|
-
export declare function executeParallelSearches({ searchAPI, query, date, country, safeSearch, images, videos, news, logger, }: {
|
|
27
|
+
export declare function executeParallelSearches({ searchAPI, query, date, country, safeSearch, images, videos, news, logger, provider, metrics, }: {
|
|
28
28
|
searchAPI: ReturnType<typeof createSearchAPI>;
|
|
29
29
|
query: string;
|
|
30
30
|
date?: DATE_RANGE;
|
|
@@ -34,5 +34,11 @@ export declare function executeParallelSearches({ searchAPI, query, date, countr
|
|
|
34
34
|
videos: boolean;
|
|
35
35
|
news: boolean;
|
|
36
36
|
logger: t.Logger;
|
|
37
|
+
/** Labels the provider in the run summary. Optional so the pre-existing
|
|
38
|
+
* call contract still holds for callers outside this package. */
|
|
39
|
+
provider?: string;
|
|
40
|
+
/** Collector owned by the caller. Without one, this call opens and flushes
|
|
41
|
+
* its own, so a direct caller still gets the single summary line. */
|
|
42
|
+
metrics?: t.SearchMetrics;
|
|
37
43
|
}): Promise<t.SearchResult>;
|
|
38
44
|
export declare const createSearchTool: (config?: t.SearchToolConfig) => DynamicStructuredTool;
|
|
@@ -291,7 +291,9 @@ export interface JinaRerankerResult {
|
|
|
291
291
|
}
|
|
292
292
|
export interface JinaRerankerResponse {
|
|
293
293
|
model: string;
|
|
294
|
-
|
|
294
|
+
/** Telemetry only, and absent from some Jina-compatible endpoints — never
|
|
295
|
+
* dereference it on a path that would discard a usable ranking. */
|
|
296
|
+
usage?: {
|
|
295
297
|
total_tokens: number;
|
|
296
298
|
};
|
|
297
299
|
results: JinaRerankerResult[];
|
|
@@ -303,12 +305,13 @@ export interface CohereRerankerResult {
|
|
|
303
305
|
export interface CohereRerankerResponse {
|
|
304
306
|
results: CohereRerankerResult[];
|
|
305
307
|
id: string;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
+
/** Telemetry only; see {@link JinaRerankerResponse.usage}. */
|
|
309
|
+
meta?: {
|
|
310
|
+
api_version?: {
|
|
308
311
|
version: string;
|
|
309
312
|
is_experimental: boolean;
|
|
310
313
|
};
|
|
311
|
-
billed_units
|
|
314
|
+
billed_units?: {
|
|
312
315
|
search_units: number;
|
|
313
316
|
};
|
|
314
317
|
};
|
|
@@ -343,6 +346,81 @@ export interface RagApiRerankResponse {
|
|
|
343
346
|
}
|
|
344
347
|
export type SafeSearchLevel = 0 | 1 | 2;
|
|
345
348
|
export type Logger = WinstonLogger;
|
|
349
|
+
/** Compact, redacted view of a thrown error, safe to hand to a logger. */
|
|
350
|
+
export interface SafeErrorLog {
|
|
351
|
+
message: string;
|
|
352
|
+
name?: string;
|
|
353
|
+
code?: string;
|
|
354
|
+
status?: number;
|
|
355
|
+
method?: string;
|
|
356
|
+
url?: string;
|
|
357
|
+
responseDataSummary?: string;
|
|
358
|
+
value?: string;
|
|
359
|
+
}
|
|
360
|
+
/** Why a rerank returned the candidates' original order instead of a ranking. */
|
|
361
|
+
export type RerankFallback = 'no_api_key' | 'no_base_url' | 'no_token_supplier' | 'bad_response' | 'invalid_results' | 'chunk_error' | 'placeholder' | 'error';
|
|
362
|
+
/** One provider query. `results` is the row count that query contributed. */
|
|
363
|
+
export interface SearchObservation {
|
|
364
|
+
provider: string;
|
|
365
|
+
type: string;
|
|
366
|
+
results: number;
|
|
367
|
+
durationMs: number;
|
|
368
|
+
error?: string;
|
|
369
|
+
/** The query rejected rather than reporting failure in its response. Those
|
|
370
|
+
* were logged at error level before they were aggregated, so the summary
|
|
371
|
+
* has to carry the distinction to keep that severity. */
|
|
372
|
+
thrown?: boolean;
|
|
373
|
+
}
|
|
374
|
+
/** One scraped link. A failure carries `error`; a success carries the sizes
|
|
375
|
+
* the scrape produced, so the summary can report both without a second pass. */
|
|
376
|
+
export interface ScrapeObservation {
|
|
377
|
+
url: string;
|
|
378
|
+
chars?: number;
|
|
379
|
+
highlights?: number;
|
|
380
|
+
error?: string;
|
|
381
|
+
}
|
|
382
|
+
/** One reranker round trip. A search reranks once per scraped source, so
|
|
383
|
+
* these fold into a single summary rather than logging per source. */
|
|
384
|
+
export interface RerankObservation {
|
|
385
|
+
provider: string;
|
|
386
|
+
chunks: number;
|
|
387
|
+
results: number;
|
|
388
|
+
durationMs: number;
|
|
389
|
+
model?: string;
|
|
390
|
+
/** Provider-reported usage: Jina tokens, Cohere billed search units. */
|
|
391
|
+
units?: number;
|
|
392
|
+
/** Chunks a provider candidate cap dropped before submission. */
|
|
393
|
+
dropped?: number;
|
|
394
|
+
/** Set only when a provider cap reduced the requested result count, so a
|
|
395
|
+
* search returning fewer highlights than configured says why. */
|
|
396
|
+
topK?: number;
|
|
397
|
+
topKLimit?: number;
|
|
398
|
+
reason?: RerankFallback;
|
|
399
|
+
error?: SafeErrorLog;
|
|
400
|
+
}
|
|
401
|
+
/** Per-rerank state threaded from the start of a call to whichever exit it
|
|
402
|
+
* takes, so every path records exactly one observation. */
|
|
403
|
+
export interface RerankRun {
|
|
404
|
+
metrics: SearchMetrics;
|
|
405
|
+
documents: string[];
|
|
406
|
+
topK: number;
|
|
407
|
+
startedAt: number;
|
|
408
|
+
model?: string;
|
|
409
|
+
units?: number;
|
|
410
|
+
dropped?: number;
|
|
411
|
+
topKLimit?: number;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Fold-as-you-go counters for one `web_search` call. Recording is O(1) and
|
|
415
|
+
* allocation-free past a bounded reason map; {@link SearchMetrics.flush}
|
|
416
|
+
* emits at most one line per phase that actually ran.
|
|
417
|
+
*/
|
|
418
|
+
export interface SearchMetrics {
|
|
419
|
+
recordSearch(observation: SearchObservation): void;
|
|
420
|
+
recordScrape(observation: ScrapeObservation): void;
|
|
421
|
+
recordRerank(observation: RerankObservation): void;
|
|
422
|
+
flush(): void;
|
|
423
|
+
}
|
|
346
424
|
export interface SearchToolConfig extends SearchConfig, ProcessSourcesConfig, FirecrawlConfig {
|
|
347
425
|
tavilyScraperOptions?: TavilyScraperConfig;
|
|
348
426
|
crwScraperOptions?: CrwScraperConfig;
|
|
@@ -572,6 +650,9 @@ export interface FirecrawlScraperConfig extends BaseSearchProviderConfig {
|
|
|
572
650
|
onlyMainContent?: boolean;
|
|
573
651
|
changeTrackingOptions?: object;
|
|
574
652
|
}
|
|
653
|
+
/** Result kind a parallel sub-search covers; `web` is the untyped main
|
|
654
|
+
* search, which every provider serves without a `type` parameter. */
|
|
655
|
+
export type SubSearchType = 'web' | 'images' | 'videos' | 'news';
|
|
575
656
|
export type GetSourcesParams = {
|
|
576
657
|
query: string;
|
|
577
658
|
date?: DATE_RANGE;
|
|
@@ -870,6 +951,9 @@ export type ProcessSourcesFields = {
|
|
|
870
951
|
news: boolean;
|
|
871
952
|
proMode: boolean;
|
|
872
953
|
onGetHighlights: SearchToolConfig['onGetHighlights'];
|
|
954
|
+
/** Collector owned by the caller; when omitted, one is created and flushed
|
|
955
|
+
* for this call so a direct `processSources` still summarizes itself. */
|
|
956
|
+
metrics?: SearchMetrics;
|
|
873
957
|
};
|
|
874
958
|
export interface SearchToolSchema {
|
|
875
959
|
type: 'object';
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
+
import type { SafeErrorLog } from './types';
|
|
1
2
|
import type * as t from './types';
|
|
2
|
-
export
|
|
3
|
-
message: string;
|
|
4
|
-
name?: string;
|
|
5
|
-
code?: string;
|
|
6
|
-
status?: number;
|
|
7
|
-
method?: string;
|
|
8
|
-
url?: string;
|
|
9
|
-
responseDataSummary?: string;
|
|
10
|
-
value?: string;
|
|
11
|
-
}
|
|
3
|
+
export type { SafeErrorLog } from './types';
|
|
12
4
|
/**
|
|
13
5
|
* Creates a default logger that maps to console methods
|
|
14
6
|
* Uses a singleton pattern to avoid creating multiple instances
|
|
@@ -233,6 +233,14 @@ export type RunConfig = {
|
|
|
233
233
|
* block to prevent leaks.
|
|
234
234
|
*/
|
|
235
235
|
hooks?: HookRegistry;
|
|
236
|
+
/**
|
|
237
|
+
* Maximum number of times a `Stop` hook may keep this Run warm by returning
|
|
238
|
+
* `decision: 'block'` with messages to inject. Defaults to
|
|
239
|
+
* `DEFAULT_MAX_STOP_CONTINUATIONS`; non-finite values use the default and
|
|
240
|
+
* values at or below zero disable terminal continuation while preserving the
|
|
241
|
+
* final Stop notification.
|
|
242
|
+
*/
|
|
243
|
+
maxStopContinuations?: number;
|
|
236
244
|
/**
|
|
237
245
|
* Opt-in cooperative preemption for this run. Requires a `hooks` registry
|
|
238
246
|
* with a `PreemptBoundary` matcher — the seal only stops the stream, the
|
|
@@ -87,6 +87,12 @@ export interface RunStepResumeState {
|
|
|
87
87
|
version: 1;
|
|
88
88
|
revision: number;
|
|
89
89
|
nextIndex: number;
|
|
90
|
+
/** Warm terminal continuations already admitted for this execution. */
|
|
91
|
+
stopContinuationCount?: number;
|
|
92
|
+
/** Identifies the fresh execution that owns this continuation lifecycle. */
|
|
93
|
+
stopContinuationExecutionId?: string;
|
|
94
|
+
/** Distinguishes LangGraph event keys when a warm continuation restarts steps. */
|
|
95
|
+
streamSegment?: number;
|
|
90
96
|
toolCallSteps: Array<{
|
|
91
97
|
toolCallId: string;
|
|
92
98
|
stepId: string;
|
|
@@ -62,6 +62,12 @@ export type CompactionReasoningSemanticIndexEntry = CompactionSemanticIndexEntry
|
|
|
62
62
|
*/
|
|
63
63
|
export type CompactionSemanticIndexEntry = CompactionToolSemanticIndexEntry | CompactionActivitySemanticIndexEntry | CompactionReasoningSemanticIndexEntry;
|
|
64
64
|
export type CompactionSemanticIndex = readonly CompactionSemanticIndexEntry[];
|
|
65
|
+
/** Serializable continuation state for a bounded compaction semantic index. */
|
|
66
|
+
export type CompactionSemanticIndexSnapshot = {
|
|
67
|
+
entries: CompactionSemanticIndex;
|
|
68
|
+
/** Cumulative entries supplied before validation and bounded retention. */
|
|
69
|
+
providedEntryCount: number;
|
|
70
|
+
};
|
|
65
71
|
export type SummarizationConfig = {
|
|
66
72
|
provider?: ProviderName;
|
|
67
73
|
model?: string;
|
|
@@ -69,6 +69,15 @@ export declare function getTokenCountForMessage(message: BaseMessage, getTokenCo
|
|
|
69
69
|
* computed as a single rounded product of the summed raw counts.
|
|
70
70
|
*/
|
|
71
71
|
export declare function apportionTokenCounts(rawCounts: Record<string, number>, multiplier: number, targetTotal: number): Record<string, number>;
|
|
72
|
+
/**
|
|
73
|
+
* Encoding a counter measures in, for counters built here.
|
|
74
|
+
*
|
|
75
|
+
* `undefined` for a counter the host supplied itself: unknown, not wrong. A
|
|
76
|
+
* caller that needs a count in a specific encoding can therefore tell "counts
|
|
77
|
+
* in the encoding I need" from "counts in a different one" without treating
|
|
78
|
+
* every foreign counter as suspect.
|
|
79
|
+
*/
|
|
80
|
+
export declare function encodingOfTokenCounter(tokenCounter: (message: BaseMessage) => number): EncodingName | undefined;
|
|
72
81
|
/**
|
|
73
82
|
* Creates a token counter function using the specified encoding.
|
|
74
83
|
* Lazily loads the encoding data on first use via dynamic import.
|
package/package.json
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
import { isTokenCounterCacheCompatible } from '@/llm/tokenCounterCacheCompatibility';
|
|
53
53
|
import { snapshotCompactionSemanticIndex } from '@/summarization/semanticIndex';
|
|
54
54
|
import { createExactTokenCountCache } from '@/llm/contextPressureMeter';
|
|
55
|
+
import { buildSummaryCarrierText } from '@/summarization/shared';
|
|
55
56
|
import { createSchemaOnlyTools } from '@/tools/schema';
|
|
56
57
|
import { apportionTokenCounts } from '@/utils/tokens';
|
|
57
58
|
import { isThinkingEnabled } from '@/llm/request';
|
|
@@ -967,11 +968,7 @@ export class AgentContext {
|
|
|
967
968
|
private buildSummaryHumanMessage(
|
|
968
969
|
promptCacheProvider: PromptCacheProvider | undefined
|
|
969
970
|
): HumanMessage {
|
|
970
|
-
const wrappedSummary =
|
|
971
|
-
'<summary>\n' +
|
|
972
|
-
(this.summaryText as string) +
|
|
973
|
-
'\n</summary>\n\n' +
|
|
974
|
-
'This is your own checkpoint: you wrote it to preserve context after compaction. Pick up where you left off based on the summary above. Do not repeat prior tasks, information or acknowledge this checkpoint message directly.';
|
|
971
|
+
const wrappedSummary = buildSummaryCarrierText(this.summaryText as string);
|
|
975
972
|
|
|
976
973
|
if (promptCacheProvider !== Providers.ANTHROPIC) {
|
|
977
974
|
return new HumanMessage(wrappedSummary);
|
package/src/common/constants.ts
CHANGED
|
@@ -20,6 +20,14 @@ export const DEFAULT_TOOL_TOKEN_MULTIPLIER = 1.4;
|
|
|
20
20
|
*/
|
|
21
21
|
export const DEFAULT_MAX_SEALS = 8;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Default ceiling on Stop-hook continuations within one Run. A blocking Stop
|
|
25
|
+
* hook can keep a naturally terminal run warm by injecting another user turn;
|
|
26
|
+
* the ceiling prevents a faulty hook or continuously arriving input from
|
|
27
|
+
* keeping one processStream call alive forever.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_MAX_STOP_CONTINUATIONS = 8;
|
|
30
|
+
|
|
23
31
|
/**
|
|
24
32
|
* Per-hook timeout for `PreemptBoundary`, deliberately far above
|
|
25
33
|
* `DEFAULT_HOOK_TIMEOUT_MS`. A host drain has already popped its queue and
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -771,6 +771,9 @@ export abstract class Graph<
|
|
|
771
771
|
contentData: t.RunStep[] = [];
|
|
772
772
|
protected nextContentIndex = 0;
|
|
773
773
|
protected runStepStateRevision = 0;
|
|
774
|
+
protected stopContinuationCount = 0;
|
|
775
|
+
protected stopContinuationExecutionId = '';
|
|
776
|
+
protected streamSegment = 0;
|
|
774
777
|
stepKeyIds: Map<string, string[]> = new Map<string, string[]>();
|
|
775
778
|
contentIndexMap: Map<string, number> = new Map();
|
|
776
779
|
toolCallStepIds: Map<string, string> = new Map();
|
|
@@ -900,6 +903,9 @@ export abstract class Graph<
|
|
|
900
903
|
this.contentData = [];
|
|
901
904
|
this.nextContentIndex = 0;
|
|
902
905
|
this.runStepStateRevision = 0;
|
|
906
|
+
this.stopContinuationCount = 0;
|
|
907
|
+
this.stopContinuationExecutionId = '';
|
|
908
|
+
this.streamSegment = 0;
|
|
903
909
|
this.contentIndexMap = new Map();
|
|
904
910
|
this.stepKeyIds = new Map();
|
|
905
911
|
this.toolCallStepIds.clear();
|
|
@@ -1537,6 +1543,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1537
1543
|
this.cachedRunMessages = undefined;
|
|
1538
1544
|
this.cachedDiscoveredTools = undefined;
|
|
1539
1545
|
this.config = resetIfNotEmpty(this.config, undefined);
|
|
1546
|
+
this.stopContinuationCount = 0;
|
|
1547
|
+
this.stopContinuationExecutionId = '';
|
|
1548
|
+
this.streamSegment = 0;
|
|
1540
1549
|
if (keepContent !== true) {
|
|
1541
1550
|
this.contentData = resetIfNotEmpty(this.contentData, []);
|
|
1542
1551
|
this.nextContentIndex = 0;
|
|
@@ -1835,6 +1844,13 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1835
1844
|
version: 1,
|
|
1836
1845
|
revision: this.runStepStateRevision,
|
|
1837
1846
|
nextIndex: this.nextContentIndex,
|
|
1847
|
+
stopContinuationCount: this.stopContinuationCount,
|
|
1848
|
+
...(this.stopContinuationExecutionId === ''
|
|
1849
|
+
? {}
|
|
1850
|
+
: {
|
|
1851
|
+
stopContinuationExecutionId: this.stopContinuationExecutionId,
|
|
1852
|
+
}),
|
|
1853
|
+
streamSegment: this.streamSegment,
|
|
1838
1854
|
toolCallSteps: [...this.toolCallStepIds].map(([toolCallId, stepId]) => ({
|
|
1839
1855
|
toolCallId,
|
|
1840
1856
|
stepId,
|
|
@@ -1854,6 +1870,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1854
1870
|
|
|
1855
1871
|
this.nextContentIndex = state.nextIndex;
|
|
1856
1872
|
this.runStepStateRevision = state.revision;
|
|
1873
|
+
this.stopContinuationCount = state.stopContinuationCount ?? 0;
|
|
1874
|
+
this.stopContinuationExecutionId =
|
|
1875
|
+
state.stopContinuationExecutionId ?? '';
|
|
1876
|
+
this.streamSegment = state.streamSegment ?? 0;
|
|
1857
1877
|
for (const { toolCallId, stepId } of state.toolCallSteps) {
|
|
1858
1878
|
this.toolCallStepIds.set(toolCallId, stepId);
|
|
1859
1879
|
}
|
|
@@ -1888,6 +1908,30 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1888
1908
|
return undefined;
|
|
1889
1909
|
}
|
|
1890
1910
|
|
|
1911
|
+
getStopContinuationCount(): number {
|
|
1912
|
+
return this.stopContinuationCount;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
setStopContinuationCount(count: number): void {
|
|
1916
|
+
this.stopContinuationCount = count;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
getStopContinuationExecutionId(): string {
|
|
1920
|
+
return this.stopContinuationExecutionId;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
startStopContinuationExecution(executionId: string): void {
|
|
1924
|
+
this.stopContinuationExecutionId = executionId;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
getStreamSegment(): number {
|
|
1928
|
+
return this.streamSegment;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
advanceStreamSegment(): void {
|
|
1932
|
+
this.streamSegment += 1;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1891
1935
|
/**
|
|
1892
1936
|
* Derives the same lane key `dispatchRunStep` stamps as `runStep.agentId`.
|
|
1893
1937
|
* The multi-agent check gates the lookup because `getAgentContext` signals
|
|
@@ -2336,6 +2380,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2336
2380
|
metadata.langgraph_node as string,
|
|
2337
2381
|
metadata.langgraph_step as number,
|
|
2338
2382
|
checkpointNs,
|
|
2383
|
+
this.streamSegment,
|
|
2339
2384
|
];
|
|
2340
2385
|
|
|
2341
2386
|
return keyList;
|
|
@@ -43,7 +43,9 @@ type MatcherBucket = Partial<Record<HookEvent, HookMatcher<HookEvent>[]>>;
|
|
|
43
43
|
/**
|
|
44
44
|
* Events whose hooks can change a tool call's input or output. Presence of
|
|
45
45
|
* any of these disables eager tool execution and early completion emission;
|
|
46
|
-
*
|
|
46
|
+
* hooks that cannot rewrite a tool result (`PostToolBatch`, `Stop`, telemetry
|
|
47
|
+
* hooks) do not. A Stop hook may continue the Run, but only after every tool
|
|
48
|
+
* result in the terminal graph segment is already authoritative.
|
|
47
49
|
*/
|
|
48
50
|
const RESULT_ALTERING_HOOK_EVENTS = [
|
|
49
51
|
'PreToolUse',
|
|
@@ -313,6 +313,9 @@ function applyAggregatedResult(
|
|
|
313
313
|
target.additionalContexts.push(...source.additionalContexts);
|
|
314
314
|
target.injectedMessages.push(...source.injectedMessages);
|
|
315
315
|
target.errors.push(...source.errors);
|
|
316
|
+
if (source.hasHookFailures === true) {
|
|
317
|
+
target.hasHookFailures = true;
|
|
318
|
+
}
|
|
316
319
|
if (source.decision != null) {
|
|
317
320
|
applyToolDecision(target, source.decision, source.reason);
|
|
318
321
|
}
|
|
@@ -347,6 +350,19 @@ function combineAggregatedResults(
|
|
|
347
350
|
return combined;
|
|
348
351
|
}
|
|
349
352
|
|
|
353
|
+
/** Deterministically fold results from serialized hook phases. */
|
|
354
|
+
export function mergeAggregatedHookResults(
|
|
355
|
+
...results: Array<AggregatedHookResult | undefined>
|
|
356
|
+
): AggregatedHookResult | undefined {
|
|
357
|
+
let combined: AggregatedHookResult | undefined;
|
|
358
|
+
for (const result of results) {
|
|
359
|
+
if (result != null) {
|
|
360
|
+
combined = combineAggregatedResults(combined, result);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return combined;
|
|
364
|
+
}
|
|
365
|
+
|
|
350
366
|
function createPendingApprovalReplay(
|
|
351
367
|
approvalResult: AggregatedHookResult,
|
|
352
368
|
pendingApproval: AggregatedHookResult | undefined,
|
|
@@ -377,6 +393,7 @@ function fold(outcomes: readonly HookOutcome[]): {
|
|
|
377
393
|
for (const outcome of outcomes) {
|
|
378
394
|
const isOnceMatcher = outcome.matcher.once === true;
|
|
379
395
|
if (outcome.error !== null) {
|
|
396
|
+
aggregated.hasHookFailures = true;
|
|
380
397
|
if (outcome.matcher.internal !== true) {
|
|
381
398
|
aggregated.errors.push(outcome.error);
|
|
382
399
|
}
|
|
@@ -455,8 +472,9 @@ function fold(outcomes: readonly HookOutcome[]): {
|
|
|
455
472
|
* ## Internal matchers
|
|
456
473
|
*
|
|
457
474
|
* A matcher with `internal: true` is excluded from both the `errors` array
|
|
458
|
-
* and the logger output.
|
|
459
|
-
*
|
|
475
|
+
* and the logger output. `hasHookFailures` still records that the call was
|
|
476
|
+
* not fully successful, so fail-closed infrastructure boundaries can reject
|
|
477
|
+
* without exposing the suppressed diagnostic.
|
|
460
478
|
*
|
|
461
479
|
* ## Once semantics — atomic at-most-once
|
|
462
480
|
*
|
package/src/hooks/index.ts
CHANGED
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
// `StandardGraph.createCallModel` (PreemptBoundary).
|
|
10
10
|
export { HookRegistry } from './HookRegistry';
|
|
11
11
|
export type { HookHaltSignal } from './HookRegistry';
|
|
12
|
-
export {
|
|
12
|
+
export {
|
|
13
|
+
executeHooks,
|
|
14
|
+
mergeAggregatedHookResults,
|
|
15
|
+
DEFAULT_HOOK_TIMEOUT_MS,
|
|
16
|
+
} from './executeHooks';
|
|
13
17
|
/**
|
|
14
18
|
* Feature probe for hosts: hook outputs support `injectedMessages`
|
|
15
19
|
* (per-message graph-state injection at the `PostToolBatch` boundary).
|
|
@@ -28,6 +32,11 @@ export const HOOK_INJECTED_MESSAGES_CAPABLE = true;
|
|
|
28
32
|
* the user as a dead button rather than as an unsupported feature.
|
|
29
33
|
*/
|
|
30
34
|
export const HOOK_PREEMPT_BOUNDARY_CAPABLE = true;
|
|
35
|
+
/**
|
|
36
|
+
* Feature probe for hosts: a blocking `Stop` hook can inject queued messages
|
|
37
|
+
* and continue within the same `Run.processStream` lifecycle.
|
|
38
|
+
*/
|
|
39
|
+
export const HOOK_STOP_CONTINUATION_CAPABLE = true;
|
|
31
40
|
export {
|
|
32
41
|
matchesQuery,
|
|
33
42
|
hasNestedQuantifier,
|
|
@@ -71,6 +80,7 @@ export type {
|
|
|
71
80
|
SubagentStartHookInput,
|
|
72
81
|
SubagentStopHookInput,
|
|
73
82
|
StopHookInput,
|
|
83
|
+
StopFinalizeHookInput,
|
|
74
84
|
StopFailureHookInput,
|
|
75
85
|
PreCompactHookInput,
|
|
76
86
|
PostCompactHookInput,
|
|
@@ -85,6 +95,7 @@ export type {
|
|
|
85
95
|
SubagentStartHookOutput,
|
|
86
96
|
SubagentStopHookOutput,
|
|
87
97
|
StopHookOutput,
|
|
98
|
+
StopFinalizeHookOutput,
|
|
88
99
|
StopFailureHookOutput,
|
|
89
100
|
PreCompactHookOutput,
|
|
90
101
|
PostCompactHookOutput,
|