@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
|
-
const require_truncation = require("../utils/truncation.cjs");
|
|
2
1
|
const require_enum = require("../common/enum.cjs");
|
|
3
2
|
require("../common/index.cjs");
|
|
3
|
+
const require_truncation = require("../utils/truncation.cjs");
|
|
4
4
|
const require_runStepResume = require("./runStepResume.cjs");
|
|
5
5
|
const require_SubagentReplay = require("./subagent/SubagentReplay.cjs");
|
|
6
6
|
const require_misc = require("../utils/misc.cjs");
|
|
7
7
|
const require_langfuseRuntimeScope = require("../langfuseRuntimeScope.cjs");
|
|
8
8
|
const require_toolContent = require("../utils/toolContent.cjs");
|
|
9
9
|
const require_provenance = require("../messages/provenance.cjs");
|
|
10
|
+
const require_eagerEventExecution = require("./eagerEventExecution.cjs");
|
|
11
|
+
const require_approvalReview = require("../hitl/approvalReview.cjs");
|
|
10
12
|
const require_types = require("../hooks/types.cjs");
|
|
13
|
+
const require_toolBatchReplay = require("./toolBatchReplay.cjs");
|
|
11
14
|
const require_executeHooks = require("../hooks/executeHooks.cjs");
|
|
12
15
|
require("../hooks/index.cjs");
|
|
13
16
|
const require_injected = require("../messages/injected.cjs");
|
|
14
17
|
const require_events = require("../utils/events.cjs");
|
|
15
18
|
const require_streamLimits = require("../llm/streamLimits.cjs");
|
|
16
|
-
const require_eagerEventExecution = require("./eagerEventExecution.cjs");
|
|
17
19
|
const require_intentArg = require("./intentArg.cjs");
|
|
18
20
|
const require_toolOutputReferences = require("./toolOutputReferences.cjs");
|
|
19
21
|
const require_preparedSubagents = require("./preparedSubagents.cjs");
|
|
@@ -28,10 +30,17 @@ let _langchain_core_runnables = require("@langchain/core/runnables");
|
|
|
28
30
|
let _langchain_core_messages = require("@langchain/core/messages");
|
|
29
31
|
let _langchain_langgraph = require("@langchain/langgraph");
|
|
30
32
|
let _langchain_core_singletons = require("@langchain/core/singletons");
|
|
33
|
+
let crypto = require("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 { [require_approvalReview.TOOL_APPROVAL_REVIEW_CONFIG_KEY]: _review, [require_toolBatchReplay.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 { [require_streamLimits.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 ((0, _langchain_core_messages.isAIMessage)(message)) return {
|
|
117
|
-
message,
|
|
118
|
-
index: i,
|
|
119
|
-
messageCount: messages.length
|
|
120
|
-
};
|
|
128
|
+
if ((0, _langchain_core_messages.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
|
+
(0, crypto.createHash)("sha256").update(require_eagerEventExecution.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 require_run.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 require_run.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 || require_toolBatchReplay.getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(assistantBatch, require_toolBatchReplay.getToolBatchReplayScope(config));
|
|
291
|
+
const replayOwner = require_toolBatchReplay.getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? "");
|
|
292
|
+
const reviewEvidence = require_approvalReview.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)?.[require_SubagentReplay.SUBAGENT_REPLAY_CONTROLLER] != null).map((call) => call.id ?? ""));
|
|
296
|
+
if (!(require_toolBatchReplay.getToolBatchReplayState(config.configurable)?.records.some((record) => record.owner === replayOwner && record.batch === activeReplayKey) === true) || !require_toolBatchReplay.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 require_toolBatchReplay.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 && require_toolBatchReplay.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 (!(0, _langchain_langgraph.isGraphInterrupt)(error)
|
|
288
|
-
const resumeState = createRunStepResumeState();
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
313
|
+
if (!(0, _langchain_langgraph.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 _langchain_langgraph.GraphInterrupt(await Promise.all(error.interrupts.map(async (pendingInterrupt) => {
|
|
321
|
+
const value = await require_toolBatchReplay.attachToolBatchReplayState(pendingInterrupt.value, replayOwner, activeBatches, turnState, referenceReplay.state);
|
|
322
|
+
return {
|
|
323
|
+
...pendingInterrupt,
|
|
324
|
+
value: resumeState == null ? value : require_runStepResume.attachRunStepResumeState(value, resumeState)
|
|
325
|
+
};
|
|
292
326
|
})));
|
|
293
327
|
}
|
|
294
328
|
if (createRunStepResumeState == null) return result;
|
|
@@ -416,7 +450,7 @@ var ToolNode = class extends require_run.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 require_run.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[require_SubagentReplay.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 require_run.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 require_run.RunnableCallable {
|
|
|
724
765
|
throw new require_preparedSubagents.PreparedSubagentError("Tool hooks changed after a subagent started.");
|
|
725
766
|
}
|
|
726
767
|
const replayController = this.toolMap.get(call.name)?.[require_SubagentReplay.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 require_run.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 = require_approvalReview.getToolApprovalReviewEvidence(config, require_toolBatchReplay.getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? ""));
|
|
800
|
+
const reviewedApproval = require_approvalReview.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 _langchain_core_messages.ToolMessage ? persistOutput(output) : output;
|
|
762
807
|
}
|
|
@@ -774,18 +819,21 @@ var ToolNode = class extends require_run.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 require_executeHooks.executeHooks({
|
|
789
837
|
registry: hookRegistry,
|
|
790
838
|
input: {
|
|
791
839
|
hook_event_name: "PreToolUse",
|
|
@@ -803,16 +851,31 @@ var ToolNode = class extends require_run.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 require_run.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 require_run.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 = _langchain_core_singletons.AsyncLocalStorageProviderSingleton.runWithConfig(config, () => (0, _langchain_langgraph.interrupt)(payload));
|
|
855
|
-
hookRegistry
|
|
932
|
+
hookRegistry?.clearPendingToolApproval(approvalReplaySessionId, approvalReplayKey);
|
|
933
|
+
const currentApproval = require_approvalReview.getReviewedToolApproval(payload, toolCallId);
|
|
934
|
+
if (reviewedApproval != null && (currentApproval == null || !require_approvalReview.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 require_run.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 require_run.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) require_executeHooks.executeHooks({
|
|
1001
1087
|
registry: hookRegistry,
|
|
1002
1088
|
input: {
|
|
1003
1089
|
hook_event_name: "PermissionDenied",
|
|
@@ -1126,7 +1212,8 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1126
1212
|
resolvedArgs = pre.resolved;
|
|
1127
1213
|
if (pre.unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, pre.unresolved);
|
|
1128
1214
|
} else if (registry != null) {
|
|
1129
|
-
const
|
|
1215
|
+
const options = { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) };
|
|
1216
|
+
const { resolved, unresolved } = preBatchSnapshot != null ? preBatchSnapshot.resolve(originalArgs, options) : registry.resolve(registryRunId, originalArgs, options);
|
|
1130
1217
|
resolvedArgs = resolved;
|
|
1131
1218
|
if (unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, unresolved);
|
|
1132
1219
|
}
|
|
@@ -1148,8 +1235,9 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1148
1235
|
});
|
|
1149
1236
|
const hookRegistry = this.hookRegistry;
|
|
1150
1237
|
const approvalReplaySessionId = getToolApprovalReplaySessionId(config, runId);
|
|
1238
|
+
const approvalReviewEvidence = require_approvalReview.getToolApprovalReviewEvidence(config, require_toolBatchReplay.getToolBatchReplayOwner(config, this.executingAgentId ?? this.agentId ?? ""));
|
|
1151
1239
|
const hasPendingApproval = preToolCalls.some((entry) => entry.call.id != null && hookRegistry?.getPendingToolApproval(approvalReplaySessionId, createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", entry.call.id)) != null);
|
|
1152
|
-
if (hookRegistry
|
|
1240
|
+
if (hookRegistry?.hasHookFor("PreToolUse", runId) === true || hasPendingApproval || approvalReviewEvidence != null) {
|
|
1153
1241
|
const preemptedEagerRecords = /* @__PURE__ */ new Map();
|
|
1154
1242
|
if (this.eagerEventToolExecutions != null) for (const entry of preToolCalls) {
|
|
1155
1243
|
const callId = entry.call.id;
|
|
@@ -1160,7 +1248,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1160
1248
|
this.eagerEventToolExecutions.delete(callId);
|
|
1161
1249
|
}
|
|
1162
1250
|
}
|
|
1163
|
-
const preResults = await Promise.all(preToolCalls.map((entry) => {
|
|
1251
|
+
const preResults = hookRegistry == null ? preToolCalls.map(() => HOOK_FALLBACK) : await Promise.all(preToolCalls.map((entry) => {
|
|
1164
1252
|
const toolUseId = entry.call.id;
|
|
1165
1253
|
const approvalReplayKey = toolUseId == null ? void 0 : createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", toolUseId);
|
|
1166
1254
|
return require_executeHooks.executeHooks({
|
|
@@ -1213,7 +1301,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1213
1301
|
const flushDeferredBlockedSideEffects = async () => {
|
|
1214
1302
|
for (const item of deferredBlockedSideEffects) {
|
|
1215
1303
|
await this.dispatchStepCompleted(item.callId, item.toolName, item.args, item.contentString, config);
|
|
1216
|
-
if (hookRegistry
|
|
1304
|
+
if (hookRegistry?.hasHookFor("PermissionDenied", runId) === true) require_executeHooks.executeHooks({
|
|
1217
1305
|
registry: hookRegistry,
|
|
1218
1306
|
input: {
|
|
1219
1307
|
hook_event_name: "PermissionDenied",
|
|
@@ -1257,6 +1345,13 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1257
1345
|
continue;
|
|
1258
1346
|
}
|
|
1259
1347
|
if (hookResult.updatedInput != null) applyInputOverride(entry, hookResult.updatedInput);
|
|
1348
|
+
else {
|
|
1349
|
+
const reviewed = require_approvalReview.getReviewedToolApproval(approvalReviewEvidence?.payload, entry.call.id);
|
|
1350
|
+
if (reviewed != null) {
|
|
1351
|
+
entry.args = this.coerceEventToolArgs(entry.call.name, reviewed.request.arguments);
|
|
1352
|
+
if (entry.call.id != null) unresolvedByCallId.delete(entry.call.id);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1260
1355
|
askEntries.push({
|
|
1261
1356
|
entry,
|
|
1262
1357
|
reason: hookResult.reason,
|
|
@@ -1265,6 +1360,19 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1265
1360
|
continue;
|
|
1266
1361
|
}
|
|
1267
1362
|
if (hookResult.updatedInput != null) applyInputOverride(entry, hookResult.updatedInput);
|
|
1363
|
+
const reviewedApproval = require_approvalReview.getReviewedToolApproval(approvalReviewEvidence?.payload, entry.call.id);
|
|
1364
|
+
if (reviewedApproval != null) {
|
|
1365
|
+
if (hookResult.updatedInput == null) {
|
|
1366
|
+
entry.args = this.coerceEventToolArgs(entry.call.name, reviewedApproval.request.arguments);
|
|
1367
|
+
if (entry.call.id != null) unresolvedByCallId.delete(entry.call.id);
|
|
1368
|
+
}
|
|
1369
|
+
askEntries.push({
|
|
1370
|
+
entry,
|
|
1371
|
+
reason: reviewedApproval.request.description,
|
|
1372
|
+
allowedDecisions: reviewedApproval.reviewConfig.allowed_decisions
|
|
1373
|
+
});
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1268
1376
|
if (entry.call.id != null) {
|
|
1269
1377
|
const preempted = preemptedEagerRecords.get(entry.call.id);
|
|
1270
1378
|
if (preempted != null) this.eagerEventToolExecutions?.set(entry.call.id, preempted);
|
|
@@ -1274,9 +1382,12 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1274
1382
|
if (askEntries.length > 0) {
|
|
1275
1383
|
const payload = buildToolApprovalInterruptPayload(askEntries, runId);
|
|
1276
1384
|
const resumeValue = _langchain_core_singletons.AsyncLocalStorageProviderSingleton.runWithConfig(config, () => (0, _langchain_langgraph.interrupt)(payload));
|
|
1277
|
-
for (const { entry } of askEntries) hookRegistry
|
|
1278
|
-
const
|
|
1279
|
-
for (const { entry
|
|
1385
|
+
for (const { entry } of askEntries) hookRegistry?.clearPendingToolApproval(approvalReplaySessionId, createToolApprovalReplayKey(config, this.executingAgentId ?? this.agentId ?? "", entry.call.id));
|
|
1386
|
+
const proposalMatches = approvalReviewEvidence == null || require_approvalReview.toolApprovalPayloadMatches(payload, approvalReviewEvidence.payload);
|
|
1387
|
+
if (!proposalMatches) for (const { entry } of askEntries) blockEntry(entry, "Reviewed tool proposal changed before resume; retry approval");
|
|
1388
|
+
const decisionEntries = proposalMatches ? askEntries : [];
|
|
1389
|
+
const decisionByCallId = normalizeApprovalDecisions(decisionEntries.map(({ entry }) => entry.call.id), resumeValue);
|
|
1390
|
+
for (const { entry, reason: askReason, allowedDecisions } of decisionEntries) {
|
|
1280
1391
|
const decision = decisionByCallId.get(entry.call.id) ?? {
|
|
1281
1392
|
type: "reject",
|
|
1282
1393
|
reason: "No decision provided for tool approval"
|
|
@@ -1402,7 +1513,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1402
1513
|
userId: config.configurable?.user_id,
|
|
1403
1514
|
agentId: this.executingAgentId,
|
|
1404
1515
|
callerCapabilityProjection: this.getCallerCapabilityProjectionSnapshot(),
|
|
1405
|
-
configurable:
|
|
1516
|
+
configurable: stripHostExecutionConfig(config.configurable),
|
|
1406
1517
|
metadata: config.metadata,
|
|
1407
1518
|
signal: config.signal,
|
|
1408
1519
|
resolve: (results) => {
|
|
@@ -1661,15 +1772,39 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1661
1772
|
return this.dispatchStepCompleted(result.toolCallId, request.name, request.args, output, config, request.turn, require_intentArg.resolveToolOutcome(request.args, require_intentArg.outcomeFieldsFromResult(result), { isError: result.status === "error" }));
|
|
1662
1773
|
}
|
|
1663
1774
|
async runDirectBatchInterruptSafe(directCalls, batchIndices, config, baseContext) {
|
|
1664
|
-
const settledBatchResults = baseContext.replayBatchKey == null ? void 0 : this.
|
|
1775
|
+
const settledBatchResults = baseContext.replayBatchKey == null ? void 0 : this.settledDirectResultsByBatch.get(baseContext.replayBatchKey) ?? /* @__PURE__ */ new Map();
|
|
1776
|
+
const cacheResult = (call, position, result) => {
|
|
1777
|
+
if (baseContext.replayBatchKey == null || settledBatchResults == null) return;
|
|
1778
|
+
settledBatchResults.set(directReplayKey(call, baseContext.replayCallPositions?.get(call) ?? batchIndices[position]), result);
|
|
1779
|
+
this.settledDirectResultsByBatch.set(baseContext.replayBatchKey, settledBatchResults);
|
|
1780
|
+
};
|
|
1665
1781
|
const restoreResult = (call, result) => {
|
|
1666
1782
|
baseContext.additionalContextsSink?.push(...result.additionalContexts);
|
|
1783
|
+
const turn = result.turn;
|
|
1784
|
+
if (turn != null) this.recordToolUsageTurn(call.name, turn, call.id);
|
|
1785
|
+
const refMeta = (0, _langchain_core_messages.isBaseMessage)(result.output) ? result.output.additional_kwargs : void 0;
|
|
1786
|
+
if (refMeta?._refKey != null && result.referenceContent != null) {
|
|
1787
|
+
this.toolOutputRegistry?.set(baseContext.batchScopeId, refMeta._refKey, result.referenceContent);
|
|
1788
|
+
if ((0, _langchain_core_messages.isBaseMessage)(result.output)) result = {
|
|
1789
|
+
...result,
|
|
1790
|
+
output: new _langchain_core_messages.ToolMessage({
|
|
1791
|
+
...result.output,
|
|
1792
|
+
additional_kwargs: {
|
|
1793
|
+
...result.output.additional_kwargs,
|
|
1794
|
+
_refScope: baseContext.batchScopeId
|
|
1795
|
+
}
|
|
1796
|
+
})
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1667
1799
|
if (call.id != null && result.resolvedArgs != null && baseContext.resolvedArgsByCallId != null) baseContext.resolvedArgsByCallId.set(call.id, result.resolvedArgs);
|
|
1668
1800
|
return result;
|
|
1669
1801
|
};
|
|
1670
1802
|
const runOne = async (call, position) => {
|
|
1671
|
-
const cachedResult =
|
|
1672
|
-
if (cachedResult != null)
|
|
1803
|
+
const cachedResult = settledBatchResults?.get(directReplayKey(call, baseContext.replayCallPositions?.get(call) ?? batchIndices[position]));
|
|
1804
|
+
if (cachedResult != null) {
|
|
1805
|
+
if (cachedResult.proposal.name !== call.name || !require_eagerEventExecution.recordArgsEqual(cachedResult.proposal.args, call.args)) throw new Error("Cannot change an already completed tool call during approval replay");
|
|
1806
|
+
return restoreResult(call, cachedResult);
|
|
1807
|
+
}
|
|
1673
1808
|
const additionalContexts = [];
|
|
1674
1809
|
const output = await this.runDirectToolWithLifecycleHooks(call, config, {
|
|
1675
1810
|
...baseContext,
|
|
@@ -1677,14 +1812,32 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1677
1812
|
additionalContextsSink: additionalContexts
|
|
1678
1813
|
});
|
|
1679
1814
|
const resolvedArgs = call.id == null ? void 0 : baseContext.resolvedArgsByCallId?.get(call.id);
|
|
1680
|
-
|
|
1815
|
+
const result = {
|
|
1816
|
+
proposal: structuredClone({
|
|
1817
|
+
name: call.name,
|
|
1818
|
+
args: call.args
|
|
1819
|
+
}),
|
|
1820
|
+
turn: call.id == null ? void 0 : this.toolCallTurns.get(call.id) ?? this.directPathTurns.get(call.id),
|
|
1681
1821
|
output,
|
|
1682
1822
|
additionalContexts,
|
|
1683
1823
|
...resolvedArgs == null ? {} : { resolvedArgs }
|
|
1684
|
-
}
|
|
1824
|
+
};
|
|
1825
|
+
const refMeta = (0, _langchain_core_messages.isBaseMessage)(output) ? output.additional_kwargs : void 0;
|
|
1826
|
+
if (refMeta?._refKey != null) result.referenceContent = this.toolOutputRegistry?.get(refMeta._refScope, refMeta._refKey);
|
|
1827
|
+
cacheResult(call, position, result);
|
|
1828
|
+
return restoreResult(call, result);
|
|
1685
1829
|
};
|
|
1686
1830
|
const interrupting = this.interruptingToolNames;
|
|
1687
|
-
if (!(interrupting != null && directCalls.some((call) => interrupting.has(call.name))))
|
|
1831
|
+
if (!(interrupting != null && directCalls.some((call) => interrupting.has(call.name)))) {
|
|
1832
|
+
const results = await Promise.allSettled(directCalls.map((call, i) => runOne(call, i)));
|
|
1833
|
+
this.throwIfBreakerTripped(config);
|
|
1834
|
+
const failed = results.find((result) => result.status === "rejected" && !(0, _langchain_langgraph.isGraphInterrupt)(result.reason)) ?? results.find((result) => result.status === "rejected");
|
|
1835
|
+
if (failed?.status === "rejected") throw failed.reason;
|
|
1836
|
+
return results.map((result) => {
|
|
1837
|
+
if (result.status === "rejected") throw result.reason;
|
|
1838
|
+
return result.value.output;
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1688
1841
|
const outputs = new Array(directCalls.length);
|
|
1689
1842
|
const interruptingPositions = [];
|
|
1690
1843
|
const regularPositions = [];
|
|
@@ -1705,12 +1858,6 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1705
1858
|
}
|
|
1706
1859
|
const position = interruptingPositions[i];
|
|
1707
1860
|
outputs[position] = result.value.output;
|
|
1708
|
-
const callId = directCalls[position].id;
|
|
1709
|
-
if (baseContext.replayBatchKey != null && typeof callId === "string" && callId !== "") {
|
|
1710
|
-
const batchResults = this.settledInterruptingResults.get(baseContext.replayBatchKey) ?? /* @__PURE__ */ new Map();
|
|
1711
|
-
batchResults.set(callId, result.value);
|
|
1712
|
-
this.settledInterruptingResults.set(baseContext.replayBatchKey, batchResults);
|
|
1713
|
-
}
|
|
1714
1861
|
}
|
|
1715
1862
|
if (hasInterruptingError) {
|
|
1716
1863
|
if ((0, _langchain_langgraph.isGraphInterrupt)(interruptingError)) {
|
|
@@ -1752,7 +1899,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1752
1899
|
const outputs = [...toolMessages, ...injected];
|
|
1753
1900
|
return Array.isArray(input) ? outputs : { messages: outputs };
|
|
1754
1901
|
}
|
|
1755
|
-
async run(input, config) {
|
|
1902
|
+
async run(input, config, referenceReplay = {}) {
|
|
1756
1903
|
const breakerSignal = this.getBreakerSignal?.();
|
|
1757
1904
|
const composedSignal = require_misc.composeAbortSignals(config.signal, breakerSignal);
|
|
1758
1905
|
const batchRunScope = this.getRunScope?.();
|
|
@@ -1768,10 +1915,11 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1768
1915
|
this.toolCallTurns.clear();
|
|
1769
1916
|
const resolvedArgsByCallId = /* @__PURE__ */ new Map();
|
|
1770
1917
|
const errorOwnership = createToolErrorOwnership();
|
|
1771
|
-
const
|
|
1772
|
-
const
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1918
|
+
const batchScopeId = config.configurable?.run_id ?? `\0anon-${this.anonBatchCounter++}`;
|
|
1919
|
+
const resumedReferenceState = referenceReplay.state;
|
|
1920
|
+
const replayInputSnapshot = resumedReferenceState == null ? void 0 : this.toolOutputRegistry?.resumeBatch(batchScopeId, resumedReferenceState);
|
|
1921
|
+
referenceReplay.state = resumedReferenceState ?? this.toolOutputRegistry?.snapshotState(batchScopeId);
|
|
1922
|
+
const turn = resumedReferenceState?.turnCounter ?? this.toolOutputRegistry?.nextTurn(batchScopeId) ?? 0;
|
|
1775
1923
|
let outputs;
|
|
1776
1924
|
let replayBatchKey;
|
|
1777
1925
|
let promotedAiMessage;
|
|
@@ -1781,17 +1929,19 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1781
1929
|
if (this.eventDrivenMode && !isLocalTool) return this.executeViaEvent([input.lg_tool_call], config, input, {
|
|
1782
1930
|
batchIndices: [0],
|
|
1783
1931
|
turn,
|
|
1784
|
-
batchScopeId
|
|
1932
|
+
batchScopeId,
|
|
1933
|
+
preBatchSnapshot: replayInputSnapshot
|
|
1785
1934
|
});
|
|
1786
1935
|
const directAdditionalContexts = [];
|
|
1787
1936
|
const { lg_tool_call: _sendToolCall, ...sendState } = input;
|
|
1788
1937
|
const sendMessages = sendState.messages;
|
|
1789
1938
|
const sendAssistantBatch = Array.isArray(sendMessages) ? findAssistantBatch(sendMessages) : void 0;
|
|
1790
|
-
const sendReplayBatchKey = sendAssistantBatch == null ? void 0 : getAssistantBatchReplayKey(sendAssistantBatch,
|
|
1939
|
+
const sendReplayBatchKey = sendAssistantBatch == null || require_toolBatchReplay.getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(sendAssistantBatch, require_toolBatchReplay.getToolBatchReplayScope(config));
|
|
1791
1940
|
const sendOutput = await this.runDirectToolWithLifecycleHooks(input.lg_tool_call, config, {
|
|
1792
1941
|
batchIndex: 0,
|
|
1793
1942
|
turn,
|
|
1794
1943
|
batchScopeId,
|
|
1944
|
+
preBatchSnapshot: replayInputSnapshot,
|
|
1795
1945
|
resolvedArgsByCallId,
|
|
1796
1946
|
errorOwnership,
|
|
1797
1947
|
additionalContextsSink: directAdditionalContexts,
|
|
@@ -1815,14 +1965,15 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1815
1965
|
const assistantBatch = findAssistantBatch(messages);
|
|
1816
1966
|
if (assistantBatch == null) throw new Error("ToolNode only accepts AIMessages as input.");
|
|
1817
1967
|
const aiMessage = assistantBatch.message;
|
|
1818
|
-
replayBatchKey = getAssistantBatchReplayKey(assistantBatch,
|
|
1968
|
+
replayBatchKey = require_toolBatchReplay.getToolBatchReplayScope(config) == null ? void 0 : getAssistantBatchReplayKey(assistantBatch, require_toolBatchReplay.getToolBatchReplayScope(config));
|
|
1819
1969
|
if (this.loadRuntimeTools) {
|
|
1820
1970
|
const { tools, toolMap } = this.loadRuntimeTools(aiMessage.tool_calls ?? []);
|
|
1821
1971
|
this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));
|
|
1822
1972
|
this.applyToolExecutionOverrides();
|
|
1823
1973
|
}
|
|
1974
|
+
const replayCallPositions = new Map((aiMessage.tool_calls ?? []).map((call, i) => [call, i]));
|
|
1824
1975
|
const filteredCalls = aiMessage.tool_calls?.filter((call) => {
|
|
1825
|
-
return (call.id == null || !toolMessageIds.has(call.id)) && !(call.id?.startsWith("srvtoolu_") ?? false);
|
|
1976
|
+
return (call.id == null || call.id === "" || !toolMessageIds.has(call.id)) && !(call.id?.startsWith("srvtoolu_") ?? false);
|
|
1826
1977
|
}) ?? [];
|
|
1827
1978
|
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_"));
|
|
1828
1979
|
invalidCallResults = attributableInvalidCalls.map((call) => new _langchain_core_messages.ToolMessage({
|
|
@@ -1864,14 +2015,16 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1864
2015
|
if (directEntries.length === 0 && invalidCallResults.length === 0) return this.executeViaEvent(filteredCalls, config, input, {
|
|
1865
2016
|
batchIndices: eventEntries.map((entry) => entry.batchIndex),
|
|
1866
2017
|
turn,
|
|
1867
|
-
batchScopeId
|
|
2018
|
+
batchScopeId,
|
|
2019
|
+
preBatchSnapshot: replayInputSnapshot
|
|
1868
2020
|
});
|
|
1869
2021
|
const directCalls = directEntries.map((e) => e.call);
|
|
1870
2022
|
const directIndices = directEntries.map((e) => e.batchIndex);
|
|
1871
2023
|
const eventCalls = eventEntries.map((e) => e.call);
|
|
1872
2024
|
const eventIndices = eventEntries.map((e) => e.batchIndex);
|
|
2025
|
+
const approvalScopeCallIds = new Set(filteredCalls.flatMap((call) => call.id == null ? [] : [call.id]));
|
|
1873
2026
|
const preResolvedEventArgs = /* @__PURE__ */ new Map();
|
|
1874
|
-
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2027
|
+
const preBatchSnapshot = replayInputSnapshot ?? this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
1875
2028
|
if (preBatchSnapshot != null) {
|
|
1876
2029
|
for (const entry of eventEntries) if (entry.call.id != null) {
|
|
1877
2030
|
const { resolved, unresolved } = preBatchSnapshot.resolve(entry.call.args, { substituteIntentKey: this.toolDeclaresBusinessIntent(entry.call.name) });
|
|
@@ -1890,9 +2043,25 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1890
2043
|
preBatchSnapshot,
|
|
1891
2044
|
additionalContextsSink: directAdditionalContexts,
|
|
1892
2045
|
replayBatchKey,
|
|
2046
|
+
replayCallPositions,
|
|
2047
|
+
approvalScopeCallIds,
|
|
1893
2048
|
runInput: input
|
|
1894
2049
|
}) : [];
|
|
1895
|
-
|
|
2050
|
+
const settledDirectResults = replayBatchKey == null ? void 0 : this.settledDirectResultsByBatch.get(replayBatchKey);
|
|
2051
|
+
const unhandledDirectCalls = [];
|
|
2052
|
+
const unhandledDirectOutputs = [];
|
|
2053
|
+
for (let i = 0; i < directCalls.length; i++) {
|
|
2054
|
+
if ((settledDirectResults?.get(directReplayKey(directCalls[i], replayCallPositions.get(directCalls[i]))))?.completionHandled === true) continue;
|
|
2055
|
+
unhandledDirectCalls.push(directCalls[i]);
|
|
2056
|
+
unhandledDirectOutputs.push(directOutputs[i]);
|
|
2057
|
+
}
|
|
2058
|
+
if (unhandledDirectCalls.length > 0) {
|
|
2059
|
+
await this.handleRunToolCompletions(unhandledDirectCalls, unhandledDirectOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
2060
|
+
for (let i = 0; i < directCalls.length; i++) {
|
|
2061
|
+
const settled = settledDirectResults?.get(directReplayKey(directCalls[i], replayCallPositions.get(directCalls[i])));
|
|
2062
|
+
if (settled != null) settled.completionHandled = true;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
1896
2065
|
const eventResult = eventCalls.length > 0 ? await this.dispatchToolEvents(eventCalls, config, {
|
|
1897
2066
|
batchIndices: eventIndices,
|
|
1898
2067
|
turn,
|
|
@@ -1919,8 +2088,9 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1919
2088
|
...eventResult.injected
|
|
1920
2089
|
];
|
|
1921
2090
|
} else {
|
|
1922
|
-
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2091
|
+
const preBatchSnapshot = replayInputSnapshot ?? this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
1923
2092
|
const directAdditionalContexts = [];
|
|
2093
|
+
const approvalScopeCallIds = new Set(filteredCalls.flatMap((call) => call.id == null ? [] : [call.id]));
|
|
1924
2094
|
const toolOutputs = await this.runDirectBatchInterruptSafe(filteredCalls, filteredCalls.map((_call, i) => i), config, {
|
|
1925
2095
|
turn,
|
|
1926
2096
|
batchScopeId,
|
|
@@ -1929,6 +2099,8 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1929
2099
|
preBatchSnapshot,
|
|
1930
2100
|
additionalContextsSink: directAdditionalContexts,
|
|
1931
2101
|
replayBatchKey,
|
|
2102
|
+
replayCallPositions,
|
|
2103
|
+
approvalScopeCallIds,
|
|
1932
2104
|
runInput: input
|
|
1933
2105
|
});
|
|
1934
2106
|
await this.handleRunToolCompletions(filteredCalls, toolOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
@@ -1957,7 +2129,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
1957
2129
|
}
|
|
1958
2130
|
}
|
|
1959
2131
|
if (!outputs.some(_langchain_langgraph.isCommand)) {
|
|
1960
|
-
if (replayBatchKey != null) this.
|
|
2132
|
+
if (replayBatchKey != null) this.settledDirectResultsByBatch.delete(replayBatchKey);
|
|
1961
2133
|
return Array.isArray(input) ? outputs : { messages: outputs };
|
|
1962
2134
|
}
|
|
1963
2135
|
if (promotedAiMessage != null) outputs = outputs.map((output) => (0, _langchain_langgraph.isCommand)(output) ? patchCommandUpdateForPromotedInvalidCalls(output, promotedAiMessage, invalidCallResults) : output);
|
|
@@ -2007,7 +2179,7 @@ var ToolNode = class extends require_run.RunnableCallable {
|
|
|
2007
2179
|
combinedOutputs.push(parallelCommand);
|
|
2008
2180
|
} else if (handoffCommands.length === 1) combinedOutputs.push(handoffCommands[0]);
|
|
2009
2181
|
if (parentCommand) combinedOutputs.push(parentCommand);
|
|
2010
|
-
if (replayBatchKey != null) this.
|
|
2182
|
+
if (replayBatchKey != null) this.settledDirectResultsByBatch.delete(replayBatchKey);
|
|
2011
2183
|
return combinedOutputs;
|
|
2012
2184
|
}
|
|
2013
2185
|
isSendInput(input) {
|