@librechat/agents 3.8.0 → 3.8.2
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 +13 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +176 -55
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +16 -6
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/hitl/approvalReview.cjs +89 -0
- package/dist/cjs/hitl/approvalReview.cjs.map +1 -0
- package/dist/cjs/langfuse.cjs +42 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +42 -0
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +7 -1
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +6 -10
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +2 -7
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/contextPressureMeter.cjs +51 -10
- package/dist/cjs/llm/contextPressureMeter.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +2 -2
- package/dist/cjs/llm/openai/index.cjs +4 -3
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +5 -4
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +3 -2
- package/dist/cjs/llm/preempt.cjs.map +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +9 -7
- package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs +1 -1
- package/dist/cjs/main.cjs +14 -8
- package/dist/cjs/messages/alternation.cjs +1 -5
- package/dist/cjs/messages/alternation.cjs.map +1 -1
- package/dist/cjs/messages/budget.cjs +206 -7
- package/dist/cjs/messages/budget.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +3 -9
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +26 -38
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +132 -43
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +2 -0
- package/dist/cjs/messages/prune.cjs +14 -9
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/reasoningTypes.cjs +21 -0
- package/dist/cjs/messages/reasoningTypes.cjs.map +1 -0
- package/dist/cjs/messages/recency.cjs +15 -94
- package/dist/cjs/messages/recency.cjs.map +1 -1
- package/dist/cjs/messages/toolHistoryProjection.cjs +243 -0
- package/dist/cjs/messages/toolHistoryProjection.cjs.map +1 -0
- package/dist/cjs/messages/toolResultTypes.cjs +145 -4
- package/dist/cjs/messages/toolResultTypes.cjs.map +1 -1
- package/dist/cjs/run.cjs +22 -10
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +7 -5
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +3 -0
- package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
- package/dist/cjs/session/index.cjs +1 -1
- package/dist/cjs/session/sessionProjection.cjs +75 -0
- package/dist/cjs/session/sessionProjection.cjs.map +1 -0
- package/dist/cjs/stream.cjs +20 -19
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +19 -9
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/shared.cjs +9 -0
- package/dist/cjs/summarization/shared.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +256 -84
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +24 -9
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +2 -0
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/tools/toolBatchReplay.cjs +187 -0
- package/dist/cjs/tools/toolBatchReplay.cjs.map +1 -0
- package/dist/cjs/tools/toolOutputReferences.cjs +12 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/types/hitl.cjs +4 -0
- package/dist/cjs/types/hitl.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs +13 -0
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +105 -0
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +13 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +178 -57
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +16 -6
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/hitl/approvalReview.mjs +83 -0
- package/dist/esm/hitl/approvalReview.mjs.map +1 -0
- package/dist/esm/langfuse.mjs +43 -2
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +41 -1
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +7 -1
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +6 -10
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +2 -7
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/contextPressureMeter.mjs +52 -11
- package/dist/esm/llm/contextPressureMeter.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +2 -2
- package/dist/esm/llm/openai/index.mjs +2 -1
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +5 -4
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +2 -1
- package/dist/esm/llm/preempt.mjs.map +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +9 -7
- package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
- package/dist/esm/llm/providers.mjs +1 -1
- package/dist/esm/main.mjs +13 -10
- package/dist/esm/messages/alternation.mjs +2 -6
- package/dist/esm/messages/alternation.mjs.map +1 -1
- package/dist/esm/messages/budget.mjs +206 -8
- package/dist/esm/messages/budget.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +3 -9
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +24 -34
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +133 -44
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +2 -0
- package/dist/esm/messages/prune.mjs +14 -9
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/reasoningTypes.mjs +20 -0
- package/dist/esm/messages/reasoningTypes.mjs.map +1 -0
- package/dist/esm/messages/recency.mjs +16 -95
- package/dist/esm/messages/recency.mjs.map +1 -1
- package/dist/esm/messages/toolHistoryProjection.mjs +237 -0
- package/dist/esm/messages/toolHistoryProjection.mjs.map +1 -0
- package/dist/esm/messages/toolResultTypes.mjs +141 -4
- package/dist/esm/messages/toolResultTypes.mjs.map +1 -1
- package/dist/esm/run.mjs +23 -11
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +7 -5
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +3 -0
- package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
- package/dist/esm/session/index.mjs +1 -1
- package/dist/esm/session/sessionProjection.mjs +72 -0
- package/dist/esm/session/sessionProjection.mjs.map +1 -0
- package/dist/esm/stream.mjs +17 -16
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +20 -10
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/shared.mjs +9 -1
- package/dist/esm/summarization/shared.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +256 -84
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +24 -9
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/tools/toolBatchReplay.mjs +176 -0
- package/dist/esm/tools/toolBatchReplay.mjs.map +1 -0
- package/dist/esm/tools/toolOutputReferences.mjs +12 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/types/hitl.mjs +4 -1
- package/dist/esm/types/hitl.mjs.map +1 -1
- package/dist/esm/utils/events.mjs +13 -0
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +105 -1
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +13 -1
- package/dist/types/graphs/Graph.d.ts +27 -0
- package/dist/types/hitl/approvalReview.d.ts +32 -0
- package/dist/types/hooks/types.d.ts +4 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/langfuse.d.ts +5 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +2 -0
- package/dist/types/llm/contextPressureMeter.d.ts +2 -1
- package/dist/types/llm/prepareProviderRequest.d.ts +7 -1
- package/dist/types/messages/budget.d.ts +15 -10
- package/dist/types/messages/core.d.ts +8 -17
- package/dist/types/messages/format.d.ts +3 -2
- package/dist/types/messages/index.d.ts +1 -1
- package/dist/types/messages/prune.d.ts +1 -1
- package/dist/types/messages/reasoningTypes.d.ts +7 -0
- package/dist/types/messages/recency.d.ts +3 -0
- package/dist/types/messages/toolHistoryProjection.d.ts +65 -0
- package/dist/types/messages/toolResultTypes.d.ts +31 -1
- package/dist/types/session/sessionProjection.d.ts +10 -0
- package/dist/types/summarization/index.d.ts +2 -1
- package/dist/types/summarization/node.d.ts +1 -0
- package/dist/types/summarization/shared.d.ts +12 -0
- package/dist/types/tools/ToolNode.d.ts +12 -6
- package/dist/types/tools/subagent/SubagentReplay.d.ts +2 -0
- package/dist/types/tools/toolBatchReplay.d.ts +54 -0
- package/dist/types/tools/toolOutputReferences.d.ts +2 -0
- package/dist/types/types/graph.d.ts +20 -0
- package/dist/types/types/run.d.ts +4 -0
- package/dist/types/types/summarize.d.ts +4 -1
- package/dist/types/utils/tokens.d.ts +2 -1
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +34 -3
- package/src/graphs/Graph.ts +465 -147
- package/src/graphs/MultiAgentGraph.ts +28 -6
- package/src/hitl/approvalReview.ts +209 -0
- package/src/hooks/types.ts +4 -1
- package/src/index.ts +1 -0
- package/src/langfuse.ts +67 -9
- package/src/langfuseToolOutputTracing.ts +91 -0
- package/src/langfuseTraceShaping.ts +17 -4
- package/src/llm/anthropic/utils/message_inputs.ts +5 -10
- package/src/llm/bedrock/utils/message_inputs.ts +2 -8
- package/src/llm/contextPressureMeter.ts +80 -12
- package/src/llm/openai/utils/index.ts +5 -4
- package/src/llm/prepareProviderRequest.ts +21 -16
- package/src/messages/alternation.ts +2 -15
- package/src/messages/budget.ts +439 -23
- package/src/messages/cache.ts +8 -9
- package/src/messages/core.ts +65 -95
- package/src/messages/format.ts +262 -78
- package/src/messages/index.ts +1 -1
- package/src/messages/prune.ts +31 -12
- package/src/messages/reasoningTypes.ts +23 -0
- package/src/messages/recency.ts +35 -179
- package/src/messages/toolHistoryProjection.ts +460 -0
- package/src/messages/toolResultTypes.ts +331 -100
- package/src/run.ts +44 -22
- package/src/session/AgentSession.ts +33 -16
- package/src/session/JsonlSessionStore.ts +6 -0
- package/src/session/sessionProjection.ts +126 -0
- package/src/stream.ts +14 -19
- package/src/summarization/index.ts +2 -0
- package/src/summarization/node.ts +62 -13
- package/src/summarization/shared.ts +23 -0
- package/src/tools/ToolNode.ts +518 -184
- package/src/tools/subagent/SubagentExecutor.ts +35 -6
- package/src/tools/subagent/SubagentReplay.ts +2 -2
- package/src/tools/toolBatchReplay.ts +395 -0
- package/src/tools/toolOutputReferences.ts +16 -0
- package/src/types/graph.ts +20 -0
- package/src/types/run.ts +4 -0
- package/src/types/summarize.ts +4 -1
- package/src/utils/events.ts +19 -0
- package/src/utils/tokens.ts +183 -0
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import { calculateMaxToolResultChars, truncateToolResultContent } from "../utils/truncation.mjs";
|
|
2
1
|
import { CODE_EXECUTION_TOOLS } from "../common/enum.mjs";
|
|
3
2
|
import "../common/index.mjs";
|
|
3
|
+
import { calculateMaxToolResultChars, truncateToolResultContent } from "../utils/truncation.mjs";
|
|
4
4
|
import { attachRunStepResumeState } from "./runStepResume.mjs";
|
|
5
5
|
import { SUBAGENT_PARENT_BATCH_CONFIG_KEY, SUBAGENT_REPLAY_CONTROLLER, attachSubagentResumeManifest } from "./subagent/SubagentReplay.mjs";
|
|
6
6
|
import { composeAbortSignals } from "../utils/misc.mjs";
|
|
7
7
|
import { resolveLangfuseRuntimeScope, withLangfuseRuntimeScope } from "../langfuseRuntimeScope.mjs";
|
|
8
8
|
import { cloneToolMessageWithContent, compactToolContent, hasComputerCallOutputMarker, isComputerCallOutputContent, isComputerCallOutputMessage, serializeStructuredValueBounded, serializeToolContentBounded } from "../utils/toolContent.mjs";
|
|
9
9
|
import { stampSyntheticProviderMessage } from "../messages/provenance.mjs";
|
|
10
|
+
import { buildToolExecutionRequestPlan, coerceArgsForSchema, coerceRecordArgs, recordArgsEqual, resolveRuntimeSessionHint, stableStringify } from "./eagerEventExecution.mjs";
|
|
11
|
+
import { TOOL_APPROVAL_REVIEW_CONFIG_KEY, getReviewedToolApproval, getToolApprovalReviewEvidence, toolApprovalPayloadMatches, toolApprovalProposalMatches } from "../hitl/approvalReview.mjs";
|
|
10
12
|
import { TOOL_APPROVAL_EXECUTION_SCOPE_CONFIG_KEY } from "../hooks/types.mjs";
|
|
13
|
+
import { TOOL_BATCH_REPLAY_KEY, attachToolBatchReplayState, getToolBatchReplayOwner, getToolBatchReplayScope, getToolBatchReplayState, isChildToolApprovalOwner, restoreToolBatchReplayState } from "./toolBatchReplay.mjs";
|
|
11
14
|
import { executeHooks } from "../hooks/executeHooks.mjs";
|
|
12
15
|
import "../hooks/index.mjs";
|
|
13
16
|
import { convertInjectedMessages } from "../messages/injected.mjs";
|
|
14
17
|
import { safeDispatchCustomEvent } from "../utils/events.mjs";
|
|
15
18
|
import { RUN_BREAKER_SCOPE_CONFIG_KEY, StreamLimitExceededError } from "../llm/streamLimits.mjs";
|
|
16
|
-
import { buildToolExecutionRequestPlan, coerceArgsForSchema, coerceRecordArgs, recordArgsEqual, resolveRuntimeSessionHint } from "./eagerEventExecution.mjs";
|
|
17
19
|
import { INTENT_ARG, isIntentLabelProperty, outcomeFieldsFromResult, readOutcomeFields, resolveToolOutcome } from "./intentArg.mjs";
|
|
18
20
|
import { ToolOutputReferenceRegistry, buildReferenceKey } from "./toolOutputReferences.mjs";
|
|
19
21
|
import { PreparedSubagentError } from "./preparedSubagents.mjs";
|
|
@@ -28,10 +30,17 @@ import { RunnableLambda } from "@langchain/core/runnables";
|
|
|
28
30
|
import { AIMessage, HumanMessage, ToolMessage, isAIMessage, isBaseMessage } from "@langchain/core/messages";
|
|
29
31
|
import { Command, END, GraphInterrupt, Send, interrupt, isCommand, isGraphInterrupt } from "@langchain/langgraph";
|
|
30
32
|
import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
|
|
33
|
+
import { createHash } from "crypto";
|
|
31
34
|
//#region src/tools/ToolNode.ts
|
|
32
|
-
function
|
|
33
|
-
if (configurable == null || !("
|
|
34
|
-
const { [
|
|
35
|
+
function stripToolApprovalReviewConfig(configurable) {
|
|
36
|
+
if (configurable == null || !("__librechat_tool_approval_review" in configurable) && !("__librechat_tool_batch_replay" in configurable)) return configurable;
|
|
37
|
+
const { [TOOL_APPROVAL_REVIEW_CONFIG_KEY]: _review, [TOOL_BATCH_REPLAY_KEY]: _replay, ...rest } = configurable;
|
|
38
|
+
return rest;
|
|
39
|
+
}
|
|
40
|
+
function stripHostExecutionConfig(configurable) {
|
|
41
|
+
const withoutReview = stripToolApprovalReviewConfig(configurable);
|
|
42
|
+
if (withoutReview == null || !("lc_run_breaker_scope" in withoutReview)) return withoutReview;
|
|
43
|
+
const { [RUN_BREAKER_SCOPE_CONFIG_KEY]: _scope, ...rest } = withoutReview;
|
|
35
44
|
return rest;
|
|
36
45
|
}
|
|
37
46
|
function createToolApprovalReplayKey(config, agentId, toolUseId) {
|
|
@@ -60,6 +69,9 @@ function withSubagentReplayBatch(config, replayBatchKey) {
|
|
|
60
69
|
}
|
|
61
70
|
};
|
|
62
71
|
}
|
|
72
|
+
function directReplayKey(call, batchIndex) {
|
|
73
|
+
return call.id == null || call.id === "" ? JSON.stringify(["position", batchIndex]) : JSON.stringify(["id", call.id]);
|
|
74
|
+
}
|
|
63
75
|
function createToolErrorOwnership() {
|
|
64
76
|
return {
|
|
65
77
|
handlerOwned: /* @__PURE__ */ new Set(),
|
|
@@ -113,20 +125,14 @@ function describeOfferedShape(value) {
|
|
|
113
125
|
function findAssistantBatch(messages) {
|
|
114
126
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
115
127
|
const message = messages[i];
|
|
116
|
-
if (isAIMessage(message)) return {
|
|
117
|
-
message,
|
|
118
|
-
index: i,
|
|
119
|
-
messageCount: messages.length
|
|
120
|
-
};
|
|
128
|
+
if (isAIMessage(message)) return { message };
|
|
121
129
|
}
|
|
122
130
|
}
|
|
123
|
-
function getAssistantBatchReplayKey(batch,
|
|
131
|
+
function getAssistantBatchReplayKey(batch, threadId) {
|
|
124
132
|
return JSON.stringify([
|
|
125
|
-
runId ?? null,
|
|
126
133
|
threadId ?? null,
|
|
127
|
-
batch.message.id
|
|
128
|
-
batch.
|
|
129
|
-
batch.messageCount
|
|
134
|
+
batch.message.id == null || batch.message.id === "" ? null : batch.message.id,
|
|
135
|
+
createHash("sha256").update(stableStringify(batch.message.tool_calls ?? [])).digest("hex")
|
|
130
136
|
]);
|
|
131
137
|
}
|
|
132
138
|
function buildToolApprovalInterruptPayload(askEntries, hookSessionId) {
|
|
@@ -244,7 +250,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
244
250
|
toolUsageCount;
|
|
245
251
|
toolCallTurns = /* @__PURE__ */ new Map();
|
|
246
252
|
directPathTurns = /* @__PURE__ */ new Map();
|
|
247
|
-
|
|
253
|
+
settledDirectResultsByBatch = /* @__PURE__ */ new Map();
|
|
248
254
|
toolRegistry;
|
|
249
255
|
toolDefinitions;
|
|
250
256
|
localImplementationNames = /* @__PURE__ */ new Set();
|
|
@@ -279,16 +285,44 @@ var ToolNode = class extends RunnableCallable {
|
|
|
279
285
|
name: name ?? TOOL_NODE_RUN_NAME,
|
|
280
286
|
tags,
|
|
281
287
|
func: async (input, config) => {
|
|
288
|
+
const messages = Array.isArray(input) ? input : input.messages;
|
|
289
|
+
const assistantBatch = messages == null ? void 0 : findAssistantBatch(messages);
|
|
290
|
+
const activeReplayKey = assistantBatch == null || getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(assistantBatch, getToolBatchReplayScope(config));
|
|
291
|
+
const replayOwner = getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? "");
|
|
292
|
+
const reviewEvidence = getToolApprovalReviewEvidence(config);
|
|
293
|
+
if (reviewEvidence?.owner != null && reviewEvidence.owner !== replayOwner) {
|
|
294
|
+
const calls = this.isSendInput(input) ? [input.lg_tool_call] : assistantBatch?.message.tool_calls ?? [];
|
|
295
|
+
const trustedParentCallIds = new Set(calls.filter((call) => call.name === "subagent" && this.toolMap.get(call.name)?.[SUBAGENT_REPLAY_CONTROLLER] != null).map((call) => call.id ?? ""));
|
|
296
|
+
if (!(getToolBatchReplayState(config.configurable)?.records.some((record) => record.owner === replayOwner && record.batch === activeReplayKey) === true) || !isChildToolApprovalOwner(config, reviewEvidence.owner, trustedParentCallIds)) throw new Error("Tool approval execution owner changed before resume — failing closed");
|
|
297
|
+
}
|
|
298
|
+
const referenceReplay = {};
|
|
299
|
+
const restoredBatches = await restoreToolBatchReplayState(config, replayOwner);
|
|
300
|
+
if (restoredBatches.length > 0 && !restoredBatches.some(({ batch }) => batch === activeReplayKey)) throw new Error("Tool batch proposal changed before approval replay — failing closed");
|
|
301
|
+
if (activeReplayKey != null && getToolBatchReplayState(config.configurable) != null) this.settledDirectResultsByBatch.delete(activeReplayKey);
|
|
302
|
+
for (const { batch, results, turnState, referenceState } of restoredBatches) {
|
|
303
|
+
if (batch !== activeReplayKey) continue;
|
|
304
|
+
this.settledDirectResultsByBatch.set(batch, new Map(results));
|
|
305
|
+
if (turnState != null) this.restoreSubagentResumeState(turnState);
|
|
306
|
+
referenceReplay.state = referenceState;
|
|
307
|
+
}
|
|
282
308
|
restoreRunStepResumeState?.(input.runStepState, config);
|
|
283
309
|
let result;
|
|
284
310
|
try {
|
|
285
|
-
result = await this.run(input, config);
|
|
311
|
+
result = await this.run(input, config, referenceReplay);
|
|
286
312
|
} catch (error) {
|
|
287
|
-
if (!isGraphInterrupt(error)
|
|
288
|
-
const resumeState = createRunStepResumeState();
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
313
|
+
if (!isGraphInterrupt(error)) throw error;
|
|
314
|
+
const resumeState = createRunStepResumeState?.();
|
|
315
|
+
const activeResults = activeReplayKey == null ? void 0 : this.settledDirectResultsByBatch.get(activeReplayKey);
|
|
316
|
+
const activeBatches = activeReplayKey == null ? /* @__PURE__ */ new Map() : new Map([[activeReplayKey, activeResults ?? /* @__PURE__ */ new Map()]]);
|
|
317
|
+
const turnState = this.createSubagentResumeState();
|
|
318
|
+
const activeCallIds = new Set(assistantBatch?.message.tool_calls?.map((call) => call.id));
|
|
319
|
+
turnState.directPathTurns = turnState.directPathTurns.filter(({ toolCallId }) => activeCallIds.has(toolCallId));
|
|
320
|
+
throw new GraphInterrupt(await Promise.all(error.interrupts.map(async (pendingInterrupt) => {
|
|
321
|
+
const value = await attachToolBatchReplayState(pendingInterrupt.value, replayOwner, activeBatches, turnState, referenceReplay.state);
|
|
322
|
+
return {
|
|
323
|
+
...pendingInterrupt,
|
|
324
|
+
value: resumeState == null ? value : attachRunStepResumeState(value, resumeState)
|
|
325
|
+
};
|
|
292
326
|
})));
|
|
293
327
|
}
|
|
294
328
|
if (createRunStepResumeState == null) return result;
|
|
@@ -416,7 +450,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
416
450
|
}
|
|
417
451
|
clearDirectPathTurns() {
|
|
418
452
|
this.directPathTurns.clear();
|
|
419
|
-
this.
|
|
453
|
+
this.settledDirectResultsByBatch.clear();
|
|
420
454
|
}
|
|
421
455
|
getCallerCapabilityProjection() {
|
|
422
456
|
const discoveredToolNames = new Set(this.getDiscoveredToolNames?.() ?? []);
|
|
@@ -486,11 +520,16 @@ var ToolNode = class extends RunnableCallable {
|
|
|
486
520
|
}
|
|
487
521
|
invokeWithRuntime(tool, invokeParams, call, config, runInput) {
|
|
488
522
|
const lgConfig = config;
|
|
489
|
-
const
|
|
523
|
+
const isTrustedSubagentHop = call.name === "subagent" && tool[SUBAGENT_REPLAY_CONTROLLER] != null;
|
|
524
|
+
const toolConfig = {
|
|
490
525
|
...config,
|
|
526
|
+
configurable: isTrustedSubagentHop ? config.configurable : stripToolApprovalReviewConfig(config.configurable)
|
|
527
|
+
};
|
|
528
|
+
const runtime = {
|
|
529
|
+
...toolConfig,
|
|
491
530
|
state: runInput,
|
|
492
531
|
toolCallId: call.id ?? "",
|
|
493
|
-
config,
|
|
532
|
+
config: toolConfig,
|
|
494
533
|
context: lgConfig.context,
|
|
495
534
|
store: lgConfig.store ?? null,
|
|
496
535
|
writer: lgConfig.writer ?? config.configurable?.writer ?? null
|
|
@@ -576,6 +615,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
576
615
|
if (call.id != null && call.id !== "") this.toolCallTurns.set(call.id, next);
|
|
577
616
|
return next;
|
|
578
617
|
})();
|
|
618
|
+
this.recordToolUsageTurn(call.name, usageCount, call.id);
|
|
619
|
+
if (batchContext.replayBatchKey != null && call.id != null && call.id !== "") this.directPathTurns.set(call.id, usageCount);
|
|
579
620
|
let args = call.args;
|
|
580
621
|
if (resolveFn != null) {
|
|
581
622
|
const { resolved, unresolved } = resolveFn(runId, args);
|
|
@@ -724,6 +765,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
724
765
|
throw new PreparedSubagentError("Tool hooks changed after a subagent started.");
|
|
725
766
|
}
|
|
726
767
|
const replayController = this.toolMap.get(call.name)?.[SUBAGENT_REPLAY_CONTROLLER];
|
|
768
|
+
const isTrustedSubagentReviewHop = call.name === "subagent" && replayController != null;
|
|
727
769
|
const replayConfig = replayController == null ? config : withSubagentReplayBatch(config, batchContext.replayBatchKey);
|
|
728
770
|
const settledOutput = await replayController?.getSettledOutput(call, replayConfig);
|
|
729
771
|
if (settledOutput != null) {
|
|
@@ -754,9 +796,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
754
796
|
const approvalReplayKey = call.id == null || call.id === "" ? void 0 : createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", call.id);
|
|
755
797
|
const approvalReplaySessionId = getToolApprovalReplaySessionId(config, runId);
|
|
756
798
|
const pendingApproval = approvalReplayKey == null ? void 0 : hookRegistry?.getPendingToolApproval(approvalReplaySessionId, approvalReplayKey);
|
|
799
|
+
const approvalReviewEvidence = getToolApprovalReviewEvidence(config, getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? ""));
|
|
800
|
+
const reviewedApproval = getReviewedToolApproval(approvalReviewEvidence?.payload, call.id);
|
|
801
|
+
const approvalEvidenceAppliesToBatch = approvalReviewEvidence?.payload.action_requests.some((request) => batchContext.approvalScopeCallIds == null ? request.tool_call_id === call.id : batchContext.approvalScopeCallIds.has(request.tool_call_id)) === true;
|
|
757
802
|
const hasPostHook = hookRegistry?.hasHookFor("PostToolUse", runId) === true;
|
|
758
803
|
const hasFailureHook = hookRegistry?.hasHookFor("PostToolUseFailure", runId) === true;
|
|
759
|
-
if (
|
|
804
|
+
if (!hasPreHook && pendingApproval == null && reviewedApproval == null && approvalReviewEvidence == null && !hasPostHook && !hasFailureHook) {
|
|
760
805
|
const output = await this.runTool(call, replayConfig, batchContext);
|
|
761
806
|
return output instanceof ToolMessage ? persistOutput(output) : output;
|
|
762
807
|
}
|
|
@@ -774,18 +819,21 @@ var ToolNode = class extends RunnableCallable {
|
|
|
774
819
|
}
|
|
775
820
|
const turn = usageCount;
|
|
776
821
|
const stepId = this.toolCallStepIds?.get(call.id ?? "") ?? "";
|
|
777
|
-
let resolvedArgs = call.args;
|
|
778
822
|
const hookResolveOptions = { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) };
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
823
|
+
const resolveDirectArgs = (args) => {
|
|
824
|
+
if (batchContext.preBatchSnapshot != null) return batchContext.preBatchSnapshot.resolve(args, hookResolveOptions).resolved;
|
|
825
|
+
if (this.toolOutputRegistry != null) return this.toolOutputRegistry.resolve(registryRunId, args, hookResolveOptions).resolved;
|
|
826
|
+
return args;
|
|
827
|
+
};
|
|
828
|
+
const originalResolvedArgs = resolveDirectArgs(call.args);
|
|
829
|
+
let resolvedArgs = hasPreHook || pendingApproval != null ? originalResolvedArgs : reviewedApproval?.request.arguments ?? originalResolvedArgs;
|
|
786
830
|
let effectiveCall = call;
|
|
787
|
-
if (hasPreHook || pendingApproval != null) {
|
|
788
|
-
const preResult =
|
|
831
|
+
if (hasPreHook || pendingApproval != null || reviewedApproval != null || approvalReviewEvidence != null) {
|
|
832
|
+
const preResult = hookRegistry == null ? {
|
|
833
|
+
additionalContexts: [],
|
|
834
|
+
injectedMessages: [],
|
|
835
|
+
errors: []
|
|
836
|
+
} : await executeHooks({
|
|
789
837
|
registry: hookRegistry,
|
|
790
838
|
input: {
|
|
791
839
|
hook_event_name: "PreToolUse",
|
|
@@ -803,16 +851,31 @@ var ToolNode = class extends RunnableCallable {
|
|
|
803
851
|
matchQuery: call.name,
|
|
804
852
|
onceReplayKey: approvalReplayKey,
|
|
805
853
|
onceReplaySessionId: approvalReplaySessionId
|
|
806
|
-
}).catch(() => void 0
|
|
854
|
+
}).catch(() => approvalReviewEvidence == null ? void 0 : {
|
|
855
|
+
decision: "deny",
|
|
856
|
+
reason: "Approval policy could not be evaluated on resume",
|
|
857
|
+
additionalContexts: [],
|
|
858
|
+
injectedMessages: [],
|
|
859
|
+
errors: []
|
|
860
|
+
});
|
|
807
861
|
if (preResult != null) {
|
|
808
862
|
if (preResult.additionalContexts.length > 0) {
|
|
809
863
|
replayAdditionalContexts.push(...preResult.additionalContexts);
|
|
810
864
|
batchContext.additionalContextsSink?.push(...preResult.additionalContexts);
|
|
811
865
|
}
|
|
812
|
-
if (preResult.updatedInput != null)
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
866
|
+
if (preResult.updatedInput != null) {
|
|
867
|
+
resolvedArgs = resolveDirectArgs(preResult.updatedInput);
|
|
868
|
+
effectiveCall = {
|
|
869
|
+
...call,
|
|
870
|
+
args: resolvedArgs
|
|
871
|
+
};
|
|
872
|
+
} else if (reviewedApproval != null) {
|
|
873
|
+
resolvedArgs = reviewedApproval.request.arguments;
|
|
874
|
+
effectiveCall = {
|
|
875
|
+
...call,
|
|
876
|
+
args: resolvedArgs
|
|
877
|
+
};
|
|
878
|
+
}
|
|
816
879
|
if (preResult.decision === "deny") return persistOutput(this.blockDirectCall({
|
|
817
880
|
call,
|
|
818
881
|
resolvedArgs,
|
|
@@ -821,7 +884,15 @@ var ToolNode = class extends RunnableCallable {
|
|
|
821
884
|
runId,
|
|
822
885
|
threadId
|
|
823
886
|
}), effectiveCall.args);
|
|
824
|
-
if (preResult.decision
|
|
887
|
+
if (approvalEvidenceAppliesToBatch && reviewedApproval == null && !isTrustedSubagentReviewHop && preResult.decision !== "ask") return persistOutput(this.blockDirectCall({
|
|
888
|
+
call,
|
|
889
|
+
resolvedArgs,
|
|
890
|
+
reason: "Tool call was not included in the restored approval batch — failing closed",
|
|
891
|
+
hookRegistry,
|
|
892
|
+
runId,
|
|
893
|
+
threadId
|
|
894
|
+
}), resolvedArgs);
|
|
895
|
+
if (preResult.decision === "ask" || reviewedApproval != null) {
|
|
825
896
|
if (this.humanInTheLoop?.enabled !== true) {
|
|
826
897
|
const reason = this.resolveAskDecisionForDirectTool(preResult.reason, call.name);
|
|
827
898
|
return persistOutput(this.blockDirectCall({
|
|
@@ -842,26 +913,41 @@ var ToolNode = class extends RunnableCallable {
|
|
|
842
913
|
runId,
|
|
843
914
|
threadId
|
|
844
915
|
}), effectiveCall.args);
|
|
916
|
+
const allowedDecisions = preResult.decision === "ask" ? preResult.allowedDecisions : reviewedApproval?.reviewConfig.allowed_decisions;
|
|
917
|
+
const askReason = preResult.decision === "ask" ? preResult.reason : reviewedApproval?.request.description;
|
|
918
|
+
if (effectiveCall === call) effectiveCall = {
|
|
919
|
+
...call,
|
|
920
|
+
args: resolvedArgs
|
|
921
|
+
};
|
|
845
922
|
const payload = buildToolApprovalInterruptPayload([{
|
|
846
923
|
entry: {
|
|
847
924
|
call: effectiveCall,
|
|
848
925
|
args: effectiveCall.args,
|
|
849
926
|
stepId
|
|
850
927
|
},
|
|
851
|
-
reason:
|
|
852
|
-
allowedDecisions
|
|
928
|
+
reason: askReason,
|
|
929
|
+
allowedDecisions
|
|
853
930
|
}], runId);
|
|
854
931
|
const resumeValue = AsyncLocalStorageProviderSingleton.runWithConfig(config, () => interrupt(payload));
|
|
855
|
-
hookRegistry
|
|
932
|
+
hookRegistry?.clearPendingToolApproval(approvalReplaySessionId, approvalReplayKey);
|
|
933
|
+
const currentApproval = getReviewedToolApproval(payload, toolCallId);
|
|
934
|
+
if (reviewedApproval != null && (currentApproval == null || !toolApprovalProposalMatches(currentApproval, reviewedApproval))) return persistOutput(this.blockDirectCall({
|
|
935
|
+
call,
|
|
936
|
+
resolvedArgs,
|
|
937
|
+
reason: "Reviewed tool proposal changed before resume; retry approval",
|
|
938
|
+
hookRegistry,
|
|
939
|
+
runId,
|
|
940
|
+
threadId
|
|
941
|
+
}), effectiveCall.args);
|
|
856
942
|
const decision = normalizeApprovalDecisions([toolCallId], resumeValue).get(toolCallId) ?? {
|
|
857
943
|
type: "reject",
|
|
858
944
|
reason: "No decision provided for tool approval"
|
|
859
945
|
};
|
|
860
946
|
const declaredType = decision.type;
|
|
861
|
-
if (
|
|
947
|
+
if (allowedDecisions != null && (typeof declaredType !== "string" || !allowedDecisions.includes(declaredType))) return persistOutput(this.blockDirectCall({
|
|
862
948
|
call,
|
|
863
949
|
resolvedArgs,
|
|
864
|
-
reason: `Decision "${typeof declaredType === "string" ? declaredType : "<missing>"}" not in allowedDecisions [${
|
|
950
|
+
reason: `Decision "${typeof declaredType === "string" ? declaredType : "<missing>"}" not in allowedDecisions [${allowedDecisions.join(", ")}] — failing closed`,
|
|
865
951
|
hookRegistry,
|
|
866
952
|
runId,
|
|
867
953
|
threadId
|
|
@@ -869,7 +955,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
869
955
|
if (decision.type === "reject") return persistOutput(this.blockDirectCall({
|
|
870
956
|
call,
|
|
871
957
|
resolvedArgs,
|
|
872
|
-
reason: decision.reason ??
|
|
958
|
+
reason: decision.reason ?? askReason ?? "Rejected by user",
|
|
873
959
|
hookRegistry,
|
|
874
960
|
runId,
|
|
875
961
|
threadId
|
|
@@ -997,7 +1083,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
997
1083
|
}
|
|
998
1084
|
blockDirectCall(args) {
|
|
999
1085
|
const { call, resolvedArgs, reason, hookRegistry, runId, threadId } = args;
|
|
1000
|
-
if (hookRegistry
|
|
1086
|
+
if (hookRegistry?.hasHookFor("PermissionDenied", runId) === true) executeHooks({
|
|
1001
1087
|
registry: hookRegistry,
|
|
1002
1088
|
input: {
|
|
1003
1089
|
hook_event_name: "PermissionDenied",
|
|
@@ -1125,7 +1211,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1125
1211
|
resolvedArgs = pre.resolved;
|
|
1126
1212
|
if (pre.unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, pre.unresolved);
|
|
1127
1213
|
} else if (registry != null) {
|
|
1128
|
-
const
|
|
1214
|
+
const options = { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) };
|
|
1215
|
+
const { resolved, unresolved } = preBatchSnapshot != null ? preBatchSnapshot.resolve(originalArgs, options) : registry.resolve(registryRunId, originalArgs, options);
|
|
1129
1216
|
resolvedArgs = resolved;
|
|
1130
1217
|
if (unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, unresolved);
|
|
1131
1218
|
}
|
|
@@ -1147,8 +1234,9 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1147
1234
|
});
|
|
1148
1235
|
const hookRegistry = this.hookRegistry;
|
|
1149
1236
|
const approvalReplaySessionId = getToolApprovalReplaySessionId(config, runId);
|
|
1237
|
+
const approvalReviewEvidence = getToolApprovalReviewEvidence(config, getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? ""));
|
|
1150
1238
|
const hasPendingApproval = preToolCalls.some((entry) => entry.call.id != null && hookRegistry?.getPendingToolApproval(approvalReplaySessionId, createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", entry.call.id)) != null);
|
|
1151
|
-
if (hookRegistry
|
|
1239
|
+
if (hookRegistry?.hasHookFor("PreToolUse", runId) === true || hasPendingApproval || approvalReviewEvidence != null) {
|
|
1152
1240
|
const preemptedEagerRecords = /* @__PURE__ */ new Map();
|
|
1153
1241
|
if (this.eagerEventToolExecutions != null) for (const entry of preToolCalls) {
|
|
1154
1242
|
const callId = entry.call.id;
|
|
@@ -1159,7 +1247,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1159
1247
|
this.eagerEventToolExecutions.delete(callId);
|
|
1160
1248
|
}
|
|
1161
1249
|
}
|
|
1162
|
-
const preResults = await Promise.all(preToolCalls.map((entry) => {
|
|
1250
|
+
const preResults = hookRegistry == null ? preToolCalls.map(() => HOOK_FALLBACK) : await Promise.all(preToolCalls.map((entry) => {
|
|
1163
1251
|
const toolUseId = entry.call.id;
|
|
1164
1252
|
const approvalReplayKey = toolUseId == null ? void 0 : createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", toolUseId);
|
|
1165
1253
|
return executeHooks({
|
|
@@ -1212,7 +1300,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1212
1300
|
const flushDeferredBlockedSideEffects = async () => {
|
|
1213
1301
|
for (const item of deferredBlockedSideEffects) {
|
|
1214
1302
|
await this.dispatchStepCompleted(item.callId, item.toolName, item.args, item.contentString, config);
|
|
1215
|
-
if (hookRegistry
|
|
1303
|
+
if (hookRegistry?.hasHookFor("PermissionDenied", runId) === true) executeHooks({
|
|
1216
1304
|
registry: hookRegistry,
|
|
1217
1305
|
input: {
|
|
1218
1306
|
hook_event_name: "PermissionDenied",
|
|
@@ -1256,6 +1344,13 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1256
1344
|
continue;
|
|
1257
1345
|
}
|
|
1258
1346
|
if (hookResult.updatedInput != null) applyInputOverride(entry, hookResult.updatedInput);
|
|
1347
|
+
else {
|
|
1348
|
+
const reviewed = getReviewedToolApproval(approvalReviewEvidence?.payload, entry.call.id);
|
|
1349
|
+
if (reviewed != null) {
|
|
1350
|
+
entry.args = this.coerceEventToolArgs(entry.call.name, reviewed.request.arguments);
|
|
1351
|
+
if (entry.call.id != null) unresolvedByCallId.delete(entry.call.id);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1259
1354
|
askEntries.push({
|
|
1260
1355
|
entry,
|
|
1261
1356
|
reason: hookResult.reason,
|
|
@@ -1264,6 +1359,19 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1264
1359
|
continue;
|
|
1265
1360
|
}
|
|
1266
1361
|
if (hookResult.updatedInput != null) applyInputOverride(entry, hookResult.updatedInput);
|
|
1362
|
+
const reviewedApproval = getReviewedToolApproval(approvalReviewEvidence?.payload, entry.call.id);
|
|
1363
|
+
if (reviewedApproval != null) {
|
|
1364
|
+
if (hookResult.updatedInput == null) {
|
|
1365
|
+
entry.args = this.coerceEventToolArgs(entry.call.name, reviewedApproval.request.arguments);
|
|
1366
|
+
if (entry.call.id != null) unresolvedByCallId.delete(entry.call.id);
|
|
1367
|
+
}
|
|
1368
|
+
askEntries.push({
|
|
1369
|
+
entry,
|
|
1370
|
+
reason: reviewedApproval.request.description,
|
|
1371
|
+
allowedDecisions: reviewedApproval.reviewConfig.allowed_decisions
|
|
1372
|
+
});
|
|
1373
|
+
continue;
|
|
1374
|
+
}
|
|
1267
1375
|
if (entry.call.id != null) {
|
|
1268
1376
|
const preempted = preemptedEagerRecords.get(entry.call.id);
|
|
1269
1377
|
if (preempted != null) this.eagerEventToolExecutions?.set(entry.call.id, preempted);
|
|
@@ -1273,9 +1381,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1273
1381
|
if (askEntries.length > 0) {
|
|
1274
1382
|
const payload = buildToolApprovalInterruptPayload(askEntries, runId);
|
|
1275
1383
|
const resumeValue = AsyncLocalStorageProviderSingleton.runWithConfig(config, () => interrupt(payload));
|
|
1276
|
-
for (const { entry } of askEntries) hookRegistry
|
|
1277
|
-
const
|
|
1278
|
-
for (const { entry
|
|
1384
|
+
for (const { entry } of askEntries) hookRegistry?.clearPendingToolApproval(approvalReplaySessionId, createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", entry.call.id));
|
|
1385
|
+
const proposalMatches = approvalReviewEvidence == null || toolApprovalPayloadMatches(payload, approvalReviewEvidence.payload);
|
|
1386
|
+
if (!proposalMatches) for (const { entry } of askEntries) blockEntry(entry, "Reviewed tool proposal changed before resume; retry approval");
|
|
1387
|
+
const decisionEntries = proposalMatches ? askEntries : [];
|
|
1388
|
+
const decisionByCallId = normalizeApprovalDecisions(decisionEntries.map(({ entry }) => entry.call.id), resumeValue);
|
|
1389
|
+
for (const { entry, reason: askReason, allowedDecisions } of decisionEntries) {
|
|
1279
1390
|
const decision = decisionByCallId.get(entry.call.id) ?? {
|
|
1280
1391
|
type: "reject",
|
|
1281
1392
|
reason: "No decision provided for tool approval"
|
|
@@ -1401,7 +1512,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1401
1512
|
userId: config.configurable?.user_id,
|
|
1402
1513
|
agentId: this.executingAgentId,
|
|
1403
1514
|
callerCapabilityProjection: this.getCallerCapabilityProjectionSnapshot(),
|
|
1404
|
-
configurable:
|
|
1515
|
+
configurable: stripHostExecutionConfig(config.configurable),
|
|
1405
1516
|
metadata: config.metadata,
|
|
1406
1517
|
signal: config.signal,
|
|
1407
1518
|
resolve: (results) => {
|
|
@@ -1659,15 +1770,39 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1659
1770
|
return this.dispatchStepCompleted(result.toolCallId, request.name, request.args, output, config, request.turn, resolveToolOutcome(request.args, outcomeFieldsFromResult(result), { isError: result.status === "error" }));
|
|
1660
1771
|
}
|
|
1661
1772
|
async runDirectBatchInterruptSafe(directCalls, batchIndices, config, baseContext) {
|
|
1662
|
-
const settledBatchResults = baseContext.replayBatchKey == null ? void 0 : this.
|
|
1773
|
+
const settledBatchResults = baseContext.replayBatchKey == null ? void 0 : this.settledDirectResultsByBatch.get(baseContext.replayBatchKey) ?? /* @__PURE__ */ new Map();
|
|
1774
|
+
const cacheResult = (call, position, result) => {
|
|
1775
|
+
if (baseContext.replayBatchKey == null || settledBatchResults == null) return;
|
|
1776
|
+
settledBatchResults.set(directReplayKey(call, baseContext.replayCallPositions?.get(call) ?? batchIndices[position]), result);
|
|
1777
|
+
this.settledDirectResultsByBatch.set(baseContext.replayBatchKey, settledBatchResults);
|
|
1778
|
+
};
|
|
1663
1779
|
const restoreResult = (call, result) => {
|
|
1664
1780
|
baseContext.additionalContextsSink?.push(...result.additionalContexts);
|
|
1781
|
+
const turn = result.turn;
|
|
1782
|
+
if (turn != null) this.recordToolUsageTurn(call.name, turn, call.id);
|
|
1783
|
+
const refMeta = isBaseMessage(result.output) ? result.output.additional_kwargs : void 0;
|
|
1784
|
+
if (refMeta?._refKey != null && result.referenceContent != null) {
|
|
1785
|
+
this.toolOutputRegistry?.set(baseContext.batchScopeId, refMeta._refKey, result.referenceContent);
|
|
1786
|
+
if (isBaseMessage(result.output)) result = {
|
|
1787
|
+
...result,
|
|
1788
|
+
output: new ToolMessage({
|
|
1789
|
+
...result.output,
|
|
1790
|
+
additional_kwargs: {
|
|
1791
|
+
...result.output.additional_kwargs,
|
|
1792
|
+
_refScope: baseContext.batchScopeId
|
|
1793
|
+
}
|
|
1794
|
+
})
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1665
1797
|
if (call.id != null && result.resolvedArgs != null && baseContext.resolvedArgsByCallId != null) baseContext.resolvedArgsByCallId.set(call.id, result.resolvedArgs);
|
|
1666
1798
|
return result;
|
|
1667
1799
|
};
|
|
1668
1800
|
const runOne = async (call, position) => {
|
|
1669
|
-
const cachedResult =
|
|
1670
|
-
if (cachedResult != null)
|
|
1801
|
+
const cachedResult = settledBatchResults?.get(directReplayKey(call, baseContext.replayCallPositions?.get(call) ?? batchIndices[position]));
|
|
1802
|
+
if (cachedResult != null) {
|
|
1803
|
+
if (cachedResult.proposal.name !== call.name || !recordArgsEqual(cachedResult.proposal.args, call.args)) throw new Error("Cannot change an already completed tool call during approval replay");
|
|
1804
|
+
return restoreResult(call, cachedResult);
|
|
1805
|
+
}
|
|
1671
1806
|
const additionalContexts = [];
|
|
1672
1807
|
const output = await this.runDirectToolWithLifecycleHooks(call, config, {
|
|
1673
1808
|
...baseContext,
|
|
@@ -1675,14 +1810,32 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1675
1810
|
additionalContextsSink: additionalContexts
|
|
1676
1811
|
});
|
|
1677
1812
|
const resolvedArgs = call.id == null ? void 0 : baseContext.resolvedArgsByCallId?.get(call.id);
|
|
1678
|
-
|
|
1813
|
+
const result = {
|
|
1814
|
+
proposal: structuredClone({
|
|
1815
|
+
name: call.name,
|
|
1816
|
+
args: call.args
|
|
1817
|
+
}),
|
|
1818
|
+
turn: call.id == null ? void 0 : this.toolCallTurns.get(call.id) ?? this.directPathTurns.get(call.id),
|
|
1679
1819
|
output,
|
|
1680
1820
|
additionalContexts,
|
|
1681
1821
|
...resolvedArgs == null ? {} : { resolvedArgs }
|
|
1682
|
-
}
|
|
1822
|
+
};
|
|
1823
|
+
const refMeta = isBaseMessage(output) ? output.additional_kwargs : void 0;
|
|
1824
|
+
if (refMeta?._refKey != null) result.referenceContent = this.toolOutputRegistry?.get(refMeta._refScope, refMeta._refKey);
|
|
1825
|
+
cacheResult(call, position, result);
|
|
1826
|
+
return restoreResult(call, result);
|
|
1683
1827
|
};
|
|
1684
1828
|
const interrupting = this.interruptingToolNames;
|
|
1685
|
-
if (!(interrupting != null && directCalls.some((call) => interrupting.has(call.name))))
|
|
1829
|
+
if (!(interrupting != null && directCalls.some((call) => interrupting.has(call.name)))) {
|
|
1830
|
+
const results = await Promise.allSettled(directCalls.map((call, i) => runOne(call, i)));
|
|
1831
|
+
this.throwIfBreakerTripped(config);
|
|
1832
|
+
const failed = results.find((result) => result.status === "rejected" && !isGraphInterrupt(result.reason)) ?? results.find((result) => result.status === "rejected");
|
|
1833
|
+
if (failed?.status === "rejected") throw failed.reason;
|
|
1834
|
+
return results.map((result) => {
|
|
1835
|
+
if (result.status === "rejected") throw result.reason;
|
|
1836
|
+
return result.value.output;
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1686
1839
|
const outputs = new Array(directCalls.length);
|
|
1687
1840
|
const interruptingPositions = [];
|
|
1688
1841
|
const regularPositions = [];
|
|
@@ -1703,12 +1856,6 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1703
1856
|
}
|
|
1704
1857
|
const position = interruptingPositions[i];
|
|
1705
1858
|
outputs[position] = result.value.output;
|
|
1706
|
-
const callId = directCalls[position].id;
|
|
1707
|
-
if (baseContext.replayBatchKey != null && typeof callId === "string" && callId !== "") {
|
|
1708
|
-
const batchResults = this.settledInterruptingResults.get(baseContext.replayBatchKey) ?? /* @__PURE__ */ new Map();
|
|
1709
|
-
batchResults.set(callId, result.value);
|
|
1710
|
-
this.settledInterruptingResults.set(baseContext.replayBatchKey, batchResults);
|
|
1711
|
-
}
|
|
1712
1859
|
}
|
|
1713
1860
|
if (hasInterruptingError) {
|
|
1714
1861
|
if (isGraphInterrupt(interruptingError)) {
|
|
@@ -1750,7 +1897,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1750
1897
|
const outputs = [...toolMessages, ...injected];
|
|
1751
1898
|
return Array.isArray(input) ? outputs : { messages: outputs };
|
|
1752
1899
|
}
|
|
1753
|
-
async run(input, config) {
|
|
1900
|
+
async run(input, config, referenceReplay = {}) {
|
|
1754
1901
|
const breakerSignal = this.getBreakerSignal?.();
|
|
1755
1902
|
const composedSignal = composeAbortSignals(config.signal, breakerSignal);
|
|
1756
1903
|
const batchRunScope = this.getRunScope?.();
|
|
@@ -1766,10 +1913,11 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1766
1913
|
this.toolCallTurns.clear();
|
|
1767
1914
|
const resolvedArgsByCallId = /* @__PURE__ */ new Map();
|
|
1768
1915
|
const errorOwnership = createToolErrorOwnership();
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1771
|
-
const
|
|
1772
|
-
|
|
1916
|
+
const batchScopeId = config.configurable?.run_id ?? `\0anon-${this.anonBatchCounter++}`;
|
|
1917
|
+
const resumedReferenceState = referenceReplay.state;
|
|
1918
|
+
const replayInputSnapshot = resumedReferenceState == null ? void 0 : this.toolOutputRegistry?.resumeBatch(batchScopeId, resumedReferenceState);
|
|
1919
|
+
referenceReplay.state = resumedReferenceState ?? this.toolOutputRegistry?.snapshotState(batchScopeId);
|
|
1920
|
+
const turn = resumedReferenceState?.turnCounter ?? this.toolOutputRegistry?.nextTurn(batchScopeId) ?? 0;
|
|
1773
1921
|
let outputs;
|
|
1774
1922
|
let replayBatchKey;
|
|
1775
1923
|
let promotedAiMessage;
|
|
@@ -1779,17 +1927,19 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1779
1927
|
if (this.eventDrivenMode && !isLocalTool) return this.executeViaEvent([input.lg_tool_call], config, input, {
|
|
1780
1928
|
batchIndices: [0],
|
|
1781
1929
|
turn,
|
|
1782
|
-
batchScopeId
|
|
1930
|
+
batchScopeId,
|
|
1931
|
+
preBatchSnapshot: replayInputSnapshot
|
|
1783
1932
|
});
|
|
1784
1933
|
const directAdditionalContexts = [];
|
|
1785
1934
|
const { lg_tool_call: _sendToolCall, ...sendState } = input;
|
|
1786
1935
|
const sendMessages = sendState.messages;
|
|
1787
1936
|
const sendAssistantBatch = Array.isArray(sendMessages) ? findAssistantBatch(sendMessages) : void 0;
|
|
1788
|
-
const sendReplayBatchKey = sendAssistantBatch == null ? void 0 : getAssistantBatchReplayKey(sendAssistantBatch,
|
|
1937
|
+
const sendReplayBatchKey = sendAssistantBatch == null || getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(sendAssistantBatch, getToolBatchReplayScope(config));
|
|
1789
1938
|
const sendOutput = await this.runDirectToolWithLifecycleHooks(input.lg_tool_call, config, {
|
|
1790
1939
|
batchIndex: 0,
|
|
1791
1940
|
turn,
|
|
1792
1941
|
batchScopeId,
|
|
1942
|
+
preBatchSnapshot: replayInputSnapshot,
|
|
1793
1943
|
resolvedArgsByCallId,
|
|
1794
1944
|
errorOwnership,
|
|
1795
1945
|
additionalContextsSink: directAdditionalContexts,
|
|
@@ -1813,14 +1963,15 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1813
1963
|
const assistantBatch = findAssistantBatch(messages);
|
|
1814
1964
|
if (assistantBatch == null) throw new Error("ToolNode only accepts AIMessages as input.");
|
|
1815
1965
|
const aiMessage = assistantBatch.message;
|
|
1816
|
-
replayBatchKey = getAssistantBatchReplayKey(assistantBatch,
|
|
1966
|
+
replayBatchKey = getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(assistantBatch, getToolBatchReplayScope(config));
|
|
1817
1967
|
if (this.loadRuntimeTools) {
|
|
1818
1968
|
const { tools, toolMap } = this.loadRuntimeTools(aiMessage.tool_calls ?? []);
|
|
1819
1969
|
this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));
|
|
1820
1970
|
this.applyToolExecutionOverrides();
|
|
1821
1971
|
}
|
|
1972
|
+
const replayCallPositions = new Map((aiMessage.tool_calls ?? []).map((call, i) => [call, i]));
|
|
1822
1973
|
const filteredCalls = aiMessage.tool_calls?.filter((call) => {
|
|
1823
|
-
return (call.id == null || !toolMessageIds.has(call.id)) && !(call.id?.startsWith("srvtoolu_") ?? false);
|
|
1974
|
+
return (call.id == null || call.id === "" || !toolMessageIds.has(call.id)) && !(call.id?.startsWith("srvtoolu_") ?? false);
|
|
1824
1975
|
}) ?? [];
|
|
1825
1976
|
const attributableInvalidCalls = !(!Array.isArray(input) && typeof aiMessage.id === "string" && aiMessage.id.length > 0) ? [] : (aiMessage.invalid_tool_calls ?? []).filter((call) => call.id != null && call.id !== "" && !toolMessageIds.has(call.id) && !call.id.startsWith("srvtoolu_"));
|
|
1826
1977
|
invalidCallResults = attributableInvalidCalls.map((call) => new ToolMessage({
|
|
@@ -1862,14 +2013,16 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1862
2013
|
if (directEntries.length === 0 && invalidCallResults.length === 0) return this.executeViaEvent(filteredCalls, config, input, {
|
|
1863
2014
|
batchIndices: eventEntries.map((entry) => entry.batchIndex),
|
|
1864
2015
|
turn,
|
|
1865
|
-
batchScopeId
|
|
2016
|
+
batchScopeId,
|
|
2017
|
+
preBatchSnapshot: replayInputSnapshot
|
|
1866
2018
|
});
|
|
1867
2019
|
const directCalls = directEntries.map((e) => e.call);
|
|
1868
2020
|
const directIndices = directEntries.map((e) => e.batchIndex);
|
|
1869
2021
|
const eventCalls = eventEntries.map((e) => e.call);
|
|
1870
2022
|
const eventIndices = eventEntries.map((e) => e.batchIndex);
|
|
2023
|
+
const approvalScopeCallIds = new Set(filteredCalls.flatMap((call) => call.id == null ? [] : [call.id]));
|
|
1871
2024
|
const preResolvedEventArgs = /* @__PURE__ */ new Map();
|
|
1872
|
-
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2025
|
+
const preBatchSnapshot = replayInputSnapshot ?? this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
1873
2026
|
if (preBatchSnapshot != null) {
|
|
1874
2027
|
for (const entry of eventEntries) if (entry.call.id != null) {
|
|
1875
2028
|
const { resolved, unresolved } = preBatchSnapshot.resolve(entry.call.args, { substituteIntentKey: this.toolDeclaresBusinessIntent(entry.call.name) });
|
|
@@ -1888,9 +2041,25 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1888
2041
|
preBatchSnapshot,
|
|
1889
2042
|
additionalContextsSink: directAdditionalContexts,
|
|
1890
2043
|
replayBatchKey,
|
|
2044
|
+
replayCallPositions,
|
|
2045
|
+
approvalScopeCallIds,
|
|
1891
2046
|
runInput: input
|
|
1892
2047
|
}) : [];
|
|
1893
|
-
|
|
2048
|
+
const settledDirectResults = replayBatchKey == null ? void 0 : this.settledDirectResultsByBatch.get(replayBatchKey);
|
|
2049
|
+
const unhandledDirectCalls = [];
|
|
2050
|
+
const unhandledDirectOutputs = [];
|
|
2051
|
+
for (let i = 0; i < directCalls.length; i++) {
|
|
2052
|
+
if ((settledDirectResults?.get(directReplayKey(directCalls[i], replayCallPositions.get(directCalls[i]))))?.completionHandled === true) continue;
|
|
2053
|
+
unhandledDirectCalls.push(directCalls[i]);
|
|
2054
|
+
unhandledDirectOutputs.push(directOutputs[i]);
|
|
2055
|
+
}
|
|
2056
|
+
if (unhandledDirectCalls.length > 0) {
|
|
2057
|
+
await this.handleRunToolCompletions(unhandledDirectCalls, unhandledDirectOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
2058
|
+
for (let i = 0; i < directCalls.length; i++) {
|
|
2059
|
+
const settled = settledDirectResults?.get(directReplayKey(directCalls[i], replayCallPositions.get(directCalls[i])));
|
|
2060
|
+
if (settled != null) settled.completionHandled = true;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
1894
2063
|
const eventResult = eventCalls.length > 0 ? await this.dispatchToolEvents(eventCalls, config, {
|
|
1895
2064
|
batchIndices: eventIndices,
|
|
1896
2065
|
turn,
|
|
@@ -1917,8 +2086,9 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1917
2086
|
...eventResult.injected
|
|
1918
2087
|
];
|
|
1919
2088
|
} else {
|
|
1920
|
-
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2089
|
+
const preBatchSnapshot = replayInputSnapshot ?? this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
1921
2090
|
const directAdditionalContexts = [];
|
|
2091
|
+
const approvalScopeCallIds = new Set(filteredCalls.flatMap((call) => call.id == null ? [] : [call.id]));
|
|
1922
2092
|
const toolOutputs = await this.runDirectBatchInterruptSafe(filteredCalls, filteredCalls.map((_call, i) => i), config, {
|
|
1923
2093
|
turn,
|
|
1924
2094
|
batchScopeId,
|
|
@@ -1927,6 +2097,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1927
2097
|
preBatchSnapshot,
|
|
1928
2098
|
additionalContextsSink: directAdditionalContexts,
|
|
1929
2099
|
replayBatchKey,
|
|
2100
|
+
replayCallPositions,
|
|
2101
|
+
approvalScopeCallIds,
|
|
1930
2102
|
runInput: input
|
|
1931
2103
|
});
|
|
1932
2104
|
await this.handleRunToolCompletions(filteredCalls, toolOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
@@ -1955,7 +2127,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1955
2127
|
}
|
|
1956
2128
|
}
|
|
1957
2129
|
if (!outputs.some(isCommand)) {
|
|
1958
|
-
if (replayBatchKey != null) this.
|
|
2130
|
+
if (replayBatchKey != null) this.settledDirectResultsByBatch.delete(replayBatchKey);
|
|
1959
2131
|
return Array.isArray(input) ? outputs : { messages: outputs };
|
|
1960
2132
|
}
|
|
1961
2133
|
if (promotedAiMessage != null) outputs = outputs.map((output) => isCommand(output) ? patchCommandUpdateForPromotedInvalidCalls(output, promotedAiMessage, invalidCallResults) : output);
|
|
@@ -2005,7 +2177,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2005
2177
|
combinedOutputs.push(parallelCommand);
|
|
2006
2178
|
} else if (handoffCommands.length === 1) combinedOutputs.push(handoffCommands[0]);
|
|
2007
2179
|
if (parentCommand) combinedOutputs.push(parentCommand);
|
|
2008
|
-
if (replayBatchKey != null) this.
|
|
2180
|
+
if (replayBatchKey != null) this.settledDirectResultsByBatch.delete(replayBatchKey);
|
|
2009
2181
|
return combinedOutputs;
|
|
2010
2182
|
}
|
|
2011
2183
|
isSendInput(input) {
|