@librechat/agents 3.3.4 → 3.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/common/constants.cjs +21 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +456 -7
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs +25 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
- package/dist/cjs/hooks/index.cjs +12 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +8 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +1 -3
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +268 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +51 -6
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +132 -0
- package/dist/cjs/llm/preempt.cjs.map +1 -0
- package/dist/cjs/main.cjs +31 -3
- package/dist/cjs/messages/alternation.cjs +92 -0
- package/dist/cjs/messages/alternation.cjs.map +1 -0
- package/dist/cjs/messages/format.cjs +72 -0
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/handoffCue.cjs +63 -0
- package/dist/cjs/messages/handoffCue.cjs.map +1 -0
- package/dist/cjs/messages/index.cjs +3 -0
- package/dist/cjs/messages/injected.cjs +60 -0
- package/dist/cjs/messages/injected.cjs.map +1 -0
- package/dist/cjs/run.cjs +80 -7
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
- package/dist/cjs/session/handlers.cjs +18 -9
- package/dist/cjs/session/handlers.cjs.map +1 -1
- package/dist/cjs/stream.cjs +34 -8
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +3 -1
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -0
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +19 -16
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +2 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ReadFile.cjs +8 -4
- package/dist/cjs/tools/ReadFile.cjs.map +1 -1
- package/dist/cjs/tools/SkillTool.cjs +2 -0
- package/dist/cjs/tools/SkillTool.cjs.map +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +3 -0
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +91 -50
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +5 -1
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/intentArg.cjs +230 -0
- package/dist/cjs/tools/intentArg.cjs.map +1 -0
- package/dist/cjs/tools/local/CompileCheckTool.cjs +3 -2
- package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +13 -12
- package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +2 -2
- package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs +90 -0
- package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -0
- package/dist/cjs/tools/search/schema.cjs +2 -0
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +40 -2
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +41 -7
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/esm/common/constants.mjs +19 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +455 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/hooks/HookRegistry.mjs +25 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
- package/dist/esm/hooks/index.mjs +12 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +9 -1
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +1 -3
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +270 -6
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +51 -6
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +131 -0
- package/dist/esm/llm/preempt.mjs.map +1 -0
- package/dist/esm/main.mjs +11 -7
- package/dist/esm/messages/alternation.mjs +91 -0
- package/dist/esm/messages/alternation.mjs.map +1 -0
- package/dist/esm/messages/format.mjs +72 -0
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/handoffCue.mjs +61 -0
- package/dist/esm/messages/handoffCue.mjs.map +1 -0
- package/dist/esm/messages/index.mjs +3 -0
- package/dist/esm/messages/injected.mjs +60 -0
- package/dist/esm/messages/injected.mjs.map +1 -0
- package/dist/esm/run.mjs +80 -7
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +1 -1
- package/dist/esm/session/handlers.mjs +19 -10
- package/dist/esm/session/handlers.mjs.map +1 -1
- package/dist/esm/stream.mjs +33 -9
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -1
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -0
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +19 -16
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +2 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ReadFile.mjs +8 -4
- package/dist/esm/tools/ReadFile.mjs.map +1 -1
- package/dist/esm/tools/SkillTool.mjs +2 -0
- package/dist/esm/tools/SkillTool.mjs.map +1 -1
- package/dist/esm/tools/SubagentTool.mjs +3 -0
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +91 -51
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +5 -1
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/intentArg.mjs +220 -0
- package/dist/esm/tools/intentArg.mjs.map +1 -0
- package/dist/esm/tools/local/CompileCheckTool.mjs +3 -2
- package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +13 -12
- package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +2 -2
- package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-scraper.mjs +88 -0
- package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -0
- package/dist/esm/tools/search/schema.mjs +2 -0
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +40 -3
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +41 -7
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/types/common/constants.d.ts +18 -0
- package/dist/types/graphs/Graph.d.ts +138 -1
- package/dist/types/hooks/HookRegistry.d.ts +15 -0
- package/dist/types/hooks/index.d.ts +12 -1
- package/dist/types/hooks/types.d.ts +45 -6
- package/dist/types/index.d.ts +2 -1
- package/dist/types/llm/invoke.d.ts +7 -0
- package/dist/types/llm/openai/index.d.ts +0 -11
- package/dist/types/llm/preempt.d.ts +40 -0
- package/dist/types/messages/alternation.d.ts +23 -0
- package/dist/types/messages/handoffCue.d.ts +40 -0
- package/dist/types/messages/index.d.ts +3 -0
- package/dist/types/messages/injected.d.ts +3 -0
- package/dist/types/run.d.ts +7 -0
- package/dist/types/stream.d.ts +14 -0
- package/dist/types/tools/BashExecutor.d.ts +18 -0
- package/dist/types/tools/CodeExecutor.d.ts +18 -0
- package/dist/types/tools/ReadFile.d.ts +18 -0
- package/dist/types/tools/SkillTool.d.ts +18 -0
- package/dist/types/tools/SubagentTool.d.ts +9 -0
- package/dist/types/tools/ToolNode.d.ts +37 -12
- package/dist/types/tools/ToolSearch.d.ts +18 -0
- package/dist/types/tools/intentArg.d.ts +119 -0
- package/dist/types/tools/ptcTimeout.d.ts +2 -0
- package/dist/types/tools/search/keenable-scraper.d.ts +15 -0
- package/dist/types/tools/search/schema.d.ts +18 -0
- package/dist/types/tools/search/tool.d.ts +18 -0
- package/dist/types/tools/search/types.d.ts +31 -2
- package/dist/types/tools/toolOutputReferences.d.ts +12 -2
- package/dist/types/types/graph.d.ts +8 -1
- package/dist/types/types/run.d.ts +65 -0
- package/dist/types/types/stream.d.ts +12 -25
- package/dist/types/types/tools.d.ts +27 -2
- package/package.json +1 -1
- package/src/{splitStream.test.ts → aggregator.test.ts} +59 -666
- package/src/common/constants.ts +21 -0
- package/src/events.ts +15 -1
- package/src/graphs/Graph.ts +568 -3
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +18 -7
- package/src/graphs/__tests__/Graph.preemptSignal.test.ts +126 -0
- package/src/hooks/HookRegistry.ts +40 -0
- package/src/hooks/__tests__/preemptBoundary.test.ts +152 -0
- package/src/hooks/index.ts +16 -2
- package/src/hooks/types.ts +47 -3
- package/src/index.ts +2 -1
- package/src/langfuse.ts +26 -1
- package/src/llm/bedrock/utils/message_inputs.test.ts +82 -0
- package/src/llm/bedrock/utils/message_inputs.ts +14 -11
- package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
- package/src/llm/invoke.alternation.test.ts +87 -0
- package/src/llm/invoke.handoffCue.test.ts +112 -0
- package/src/llm/invoke.ts +417 -8
- package/src/llm/openai/index.ts +74 -10
- package/src/llm/openai/llm.spec.ts +105 -0
- package/src/llm/preempt.test.ts +323 -0
- package/src/llm/preempt.ts +178 -0
- package/src/messages/alternation.test.ts +212 -0
- package/src/messages/alternation.ts +112 -0
- package/src/messages/format.ts +91 -0
- package/src/messages/formatAgentMessages.steer.test.ts +267 -0
- package/src/messages/handoffCue.test.ts +96 -0
- package/src/messages/handoffCue.ts +78 -0
- package/src/messages/index.ts +3 -0
- package/src/messages/injected.test.ts +90 -0
- package/src/messages/injected.ts +74 -0
- package/src/run.ts +91 -6
- package/src/scripts/preempt-probe.ts +330 -0
- package/src/scripts/preempt-scenarios.ts +388 -0
- package/src/session/handlers.ts +32 -12
- package/src/specs/handoffCue.test.ts +165 -0
- package/src/specs/langfuse-callbacks.test.ts +352 -2
- package/src/specs/preemptSeal.test.ts +309 -0
- package/src/stream.dispatch.test.ts +63 -0
- package/src/stream.ts +48 -9
- package/src/tools/BashExecutor.ts +6 -0
- package/src/tools/BashProgrammaticToolCalling.ts +2 -0
- package/src/tools/CodeExecutor.ts +6 -0
- package/src/tools/ProgrammaticToolCalling.ts +2 -0
- package/src/tools/ReadFile.ts +2 -0
- package/src/tools/SkillTool.ts +2 -0
- package/src/tools/SubagentTool.ts +3 -0
- package/src/tools/ToolNode.ts +193 -74
- package/src/tools/ToolSearch.ts +3 -0
- package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +174 -0
- package/src/tools/__tests__/intentArg.test.ts +281 -0
- package/src/tools/__tests__/intentCoverage.test.ts +139 -0
- package/src/tools/__tests__/toolOutputReferences.test.ts +83 -0
- package/src/tools/intentArg.ts +323 -0
- package/src/tools/local/CompileCheckTool.ts +4 -3
- package/src/tools/local/LocalCodingTools.ts +14 -13
- package/src/tools/ptcTimeout.ts +2 -0
- package/src/tools/search/keenable-scraper.test.ts +153 -0
- package/src/tools/search/keenable-scraper.ts +137 -0
- package/src/tools/search/outcome.test.ts +90 -0
- package/src/tools/search/schema.ts +3 -0
- package/src/tools/search/tool.ts +60 -3
- package/src/tools/search/types.ts +50 -3
- package/src/tools/subagent/SubagentExecutor.ts +2 -1
- package/src/tools/toolOutputReferences.ts +77 -9
- package/src/types/graph.ts +12 -1
- package/src/types/run.ts +67 -0
- package/src/types/stream.ts +12 -41
- package/src/types/tools.ts +24 -2
- package/dist/cjs/splitStream.cjs +0 -151
- package/dist/cjs/splitStream.cjs.map +0 -1
- package/dist/esm/splitStream.mjs +0 -150
- package/dist/esm/splitStream.mjs.map +0 -1
- package/dist/types/mockStream.d.ts +0 -32
- package/dist/types/splitStream.d.ts +0 -37
- package/src/mockStream.ts +0 -99
- package/src/splitStream.ts +0 -234
|
@@ -3,9 +3,10 @@ import { CODE_EXECUTION_TOOLS } from "../common/enum.mjs";
|
|
|
3
3
|
import "../common/index.mjs";
|
|
4
4
|
import { calculateMaxToolResultChars, truncateToolResultContent } from "../utils/truncation.mjs";
|
|
5
5
|
import { cloneToolMessageWithContent, compactToolContent, hasComputerCallOutputMarker, isComputerCallOutputContent, isComputerCallOutputMessage, serializeStructuredValueBounded, serializeToolContentBounded } from "../utils/toolContent.mjs";
|
|
6
|
-
import { toLangChainContent } from "../messages/langchain.mjs";
|
|
7
6
|
import { safeDispatchCustomEvent } from "../utils/events.mjs";
|
|
7
|
+
import { convertInjectedMessages } from "../messages/injected.mjs";
|
|
8
8
|
import { buildToolExecutionRequestPlan, recordArgsEqual, resolveRuntimeSessionHint } from "./eagerEventExecution.mjs";
|
|
9
|
+
import { INTENT_ARG, isIntentLabelProperty, outcomeFieldsFromResult, readOutcomeFields, resolveToolOutcome } from "./intentArg.mjs";
|
|
9
10
|
import { ToolOutputReferenceRegistry, buildReferenceKey } from "./toolOutputReferences.mjs";
|
|
10
11
|
import { RunnableCallable } from "../utils/run.mjs";
|
|
11
12
|
import "../utils/index.mjs";
|
|
@@ -19,6 +20,12 @@ import { Command, END, Send, interrupt, isCommand, isGraphInterrupt } from "@lan
|
|
|
19
20
|
import { nanoid } from "nanoid";
|
|
20
21
|
import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
|
|
21
22
|
//#region src/tools/ToolNode.ts
|
|
23
|
+
function createToolErrorOwnership() {
|
|
24
|
+
return {
|
|
25
|
+
handlerOwned: /* @__PURE__ */ new Set(),
|
|
26
|
+
undispatched: /* @__PURE__ */ new Set()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
22
29
|
/**
|
|
23
30
|
* Produces the provider preview and, when requested, the exact registry prefix
|
|
24
31
|
* in one bounded traversal. String outputs already exist in memory when a tool
|
|
@@ -251,12 +258,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
251
258
|
toolCallStepIds;
|
|
252
259
|
errorHandler;
|
|
253
260
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
261
|
+
* Fallback error-completion ownership for calls that reach `runTool`
|
|
262
|
+
* outside a batch context (direct `runTool` use in tests / embedders).
|
|
263
|
+
* Batch-scoped ownership is threaded via `RunToolBatchContext` instead —
|
|
264
|
+
* see {@link ToolErrorOwnership} for why per-invocation scoping matters.
|
|
258
265
|
*/
|
|
259
|
-
|
|
266
|
+
looseErrorOwnership = createToolErrorOwnership();
|
|
260
267
|
toolUsageCount;
|
|
261
268
|
/** Maps toolCallId → turn captured in runTool, used by handleRunToolCompletions */
|
|
262
269
|
toolCallTurns = /* @__PURE__ */ new Map();
|
|
@@ -543,8 +550,9 @@ var ToolNode = class extends RunnableCallable {
|
|
|
543
550
|
const tool = this.toolMap.get(call.name);
|
|
544
551
|
const registry = this.toolOutputRegistry;
|
|
545
552
|
let resolveFn;
|
|
546
|
-
|
|
547
|
-
|
|
553
|
+
const resolveOptions = { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) };
|
|
554
|
+
if (preBatchSnapshot != null) resolveFn = (_runId, args) => preBatchSnapshot.resolve(args, resolveOptions);
|
|
555
|
+
else if (registry != null) resolveFn = (runIdArg, args) => registry.resolve(runIdArg, args, resolveOptions);
|
|
548
556
|
/**
|
|
549
557
|
* Precompute the reference key once per call — captured locally
|
|
550
558
|
* so concurrent `invoke()` calls on the same ToolNode cannot race
|
|
@@ -737,12 +745,14 @@ var ToolNode = class extends RunnableCallable {
|
|
|
737
745
|
if (!this.handleToolErrors) throw e;
|
|
738
746
|
if (isGraphInterrupt(e)) throw e;
|
|
739
747
|
if (this.errorHandler) try {
|
|
740
|
-
|
|
748
|
+
const dispatched = await this.errorHandler({
|
|
741
749
|
error: e,
|
|
742
750
|
id: call.id,
|
|
743
751
|
name: call.name,
|
|
744
752
|
input: call.args
|
|
745
|
-
}, config.metadata)
|
|
753
|
+
}, config.metadata);
|
|
754
|
+
const ownership = batchContext.errorOwnership ?? this.looseErrorOwnership;
|
|
755
|
+
if (call.id != null && call.id !== "") if (dispatched === false)
|
|
746
756
|
/**
|
|
747
757
|
* The handler could not dispatch the error completion (typically
|
|
748
758
|
* a resume pass, where a fast-failing tool errors before the
|
|
@@ -750,8 +760,10 @@ var ToolNode = class extends RunnableCallable {
|
|
|
750
760
|
* output loop dispatches the completion itself instead of
|
|
751
761
|
* assuming the handler covered it.
|
|
752
762
|
*/
|
|
753
|
-
|
|
763
|
+
ownership.undispatched.add(call.id);
|
|
764
|
+
else ownership.handlerOwned.add(call.id);
|
|
754
765
|
} catch (handlerError) {
|
|
766
|
+
if (call.id != null && call.id !== "") (batchContext.errorOwnership ?? this.looseErrorOwnership).handlerOwned.add(call.id);
|
|
755
767
|
console.error("Error in errorHandler:", {
|
|
756
768
|
toolName: call.name,
|
|
757
769
|
toolCallId: call.id,
|
|
@@ -852,11 +864,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
852
864
|
const turn = usageCount;
|
|
853
865
|
const stepId = this.toolCallStepIds?.get(call.id ?? "") ?? "";
|
|
854
866
|
let resolvedArgs = call.args;
|
|
867
|
+
const hookResolveOptions = { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) };
|
|
855
868
|
if (batchContext.preBatchSnapshot != null) {
|
|
856
|
-
const { resolved } = batchContext.preBatchSnapshot.resolve(call.args);
|
|
869
|
+
const { resolved } = batchContext.preBatchSnapshot.resolve(call.args, hookResolveOptions);
|
|
857
870
|
resolvedArgs = resolved;
|
|
858
871
|
} else if (this.toolOutputRegistry != null) {
|
|
859
|
-
const { resolved } = this.toolOutputRegistry.resolve(registryRunId, call.args);
|
|
872
|
+
const { resolved } = this.toolOutputRegistry.resolve(registryRunId, call.args, hookResolveOptions);
|
|
860
873
|
resolvedArgs = resolved;
|
|
861
874
|
}
|
|
862
875
|
let effectiveCall = call;
|
|
@@ -968,6 +981,16 @@ var ToolNode = class extends RunnableCallable {
|
|
|
968
981
|
}
|
|
969
982
|
}
|
|
970
983
|
}
|
|
984
|
+
/**
|
|
985
|
+
* A hook (`PreToolUse.updatedInput`) or HITL `edit` decision rewrote the
|
|
986
|
+
* args: expose the EFFECTIVE args to downstream completion handling
|
|
987
|
+
* (`handleRunToolCompletions` reads this sink), so the emitted
|
|
988
|
+
* `tool_call.args` — and any intent/outcome label resolved from them —
|
|
989
|
+
* reflect what the tool actually ran with. `runTool`'s own placeholder
|
|
990
|
+
* substitution may overwrite this entry with the post-substitution args,
|
|
991
|
+
* which is strictly more accurate.
|
|
992
|
+
*/
|
|
993
|
+
if (effectiveCall !== call && batchContext.resolvedArgsByCallId != null && call.id != null && call.id !== "") batchContext.resolvedArgsByCallId.set(call.id, effectiveCall.args);
|
|
971
994
|
const output = await this.runTool(effectiveCall, config, {
|
|
972
995
|
...batchContext,
|
|
973
996
|
usageCount
|
|
@@ -1174,7 +1197,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1174
1197
|
* by `runTool`. Threaded as a local map (instead of instance state)
|
|
1175
1198
|
* so concurrent batches cannot read each other's entries.
|
|
1176
1199
|
*/
|
|
1177
|
-
async handleRunToolCompletions(calls, outputs, config, resolvedArgsByCallId) {
|
|
1200
|
+
async handleRunToolCompletions(calls, outputs, config, resolvedArgsByCallId, errorOwnership) {
|
|
1201
|
+
const ownership = errorOwnership ?? this.looseErrorOwnership;
|
|
1178
1202
|
for (let i = 0; i < calls.length; i++) {
|
|
1179
1203
|
const call = calls[i];
|
|
1180
1204
|
const output = outputs[i];
|
|
@@ -1182,8 +1206,13 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1182
1206
|
if (isCommand(output)) continue;
|
|
1183
1207
|
const toolMessage = output;
|
|
1184
1208
|
const toolCallId = call.id ?? "";
|
|
1185
|
-
if (toolMessage.status === "error" && this.errorHandler != null)
|
|
1186
|
-
|
|
1209
|
+
if (toolMessage.status === "error" && this.errorHandler != null) {
|
|
1210
|
+
if (ownership.handlerOwned.has(toolCallId)) {
|
|
1211
|
+
ownership.handlerOwned.delete(toolCallId);
|
|
1212
|
+
continue;
|
|
1213
|
+
}
|
|
1214
|
+
ownership.undispatched.delete(toolCallId);
|
|
1215
|
+
}
|
|
1187
1216
|
if (this.sessions && this.participatesInCodeSession(call.name)) {
|
|
1188
1217
|
const artifact = toolMessage.artifact;
|
|
1189
1218
|
const execSessionId = artifact?.session_id;
|
|
@@ -1195,16 +1224,27 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1195
1224
|
if (isComputerCallOutputMessage(toolMessage)) contentString = truncateToolResultContent("[Computer screenshot omitted from completion event]", this.maxToolResultChars);
|
|
1196
1225
|
else if (typeof toolMessage.content === "string") contentString = toolMessage.content;
|
|
1197
1226
|
else contentString = serializeStructuredValueBounded(toolMessage.content, this.maxToolResultChars).content;
|
|
1227
|
+
/**
|
|
1228
|
+
* Prefer the post-substitution args when a `{{…}}` placeholder
|
|
1229
|
+
* was resolved in `runTool`. This keeps
|
|
1230
|
+
* `ON_RUN_STEP_COMPLETED.tool_call.args` consistent with what
|
|
1231
|
+
* the tool actually received rather than leaking the template.
|
|
1232
|
+
*/
|
|
1233
|
+
const effectiveArgs = resolvedArgsByCallId?.get(toolCallId) ?? call.args;
|
|
1234
|
+
/** Authored outcomes apply to failed calls too (“Search failed for…”);
|
|
1235
|
+
* without one, an error call simply stays unlabeled. */
|
|
1236
|
+
const outcome = resolveToolOutcome(effectiveArgs, readOutcomeFields(toolMessage.artifact), { isError: toolMessage.status === "error" });
|
|
1198
1237
|
await safeDispatchCustomEvent("on_run_step_completed", { result: {
|
|
1199
1238
|
id: stepId,
|
|
1200
1239
|
index: turn,
|
|
1201
1240
|
type: "tool_call",
|
|
1202
1241
|
tool_call: {
|
|
1203
|
-
args: serializeToolContentBounded(
|
|
1242
|
+
args: serializeToolContentBounded(effectiveArgs ?? {}, this.maxToolResultChars),
|
|
1204
1243
|
name: call.name,
|
|
1205
1244
|
id: toolCallId,
|
|
1206
1245
|
output: contentString,
|
|
1207
|
-
progress: 1
|
|
1246
|
+
progress: 1,
|
|
1247
|
+
...outcome != null && { outcome }
|
|
1208
1248
|
}
|
|
1209
1249
|
} }, config);
|
|
1210
1250
|
}
|
|
@@ -1253,7 +1293,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1253
1293
|
resolvedArgs = pre.resolved;
|
|
1254
1294
|
if (pre.unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, pre.unresolved);
|
|
1255
1295
|
} else if (registry != null) {
|
|
1256
|
-
const { resolved, unresolved } = registry.resolve(registryRunId, originalArgs);
|
|
1296
|
+
const { resolved, unresolved } = registry.resolve(registryRunId, originalArgs, { substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) });
|
|
1257
1297
|
resolvedArgs = resolved;
|
|
1258
1298
|
if (unresolved.length > 0 && call.id != null) unresolvedByCallId.set(call.id, unresolved);
|
|
1259
1299
|
}
|
|
@@ -1429,7 +1469,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1429
1469
|
*/
|
|
1430
1470
|
const applyInputOverride = (entry, nextArgs) => {
|
|
1431
1471
|
if (registry != null) {
|
|
1432
|
-
const { resolved, unresolved } = (preBatchSnapshot ?? { resolve: (args) => registry.resolve(registryRunId, args) }).resolve(nextArgs);
|
|
1472
|
+
const { resolved, unresolved } = (preBatchSnapshot ?? { resolve: (args, options) => registry.resolve(registryRunId, args, options) }).resolve(nextArgs, { substituteIntentKey: this.toolDeclaresBusinessIntent(entry.call.name) });
|
|
1433
1473
|
entry.args = resolved;
|
|
1434
1474
|
if (entry.call.id != null) if (unresolved.length > 0) unresolvedByCallId.set(entry.call.id, unresolved);
|
|
1435
1475
|
else unresolvedByCallId.delete(entry.call.id);
|
|
@@ -1772,7 +1812,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1772
1812
|
this.storeCodeSessionFromResults(results, requestMap);
|
|
1773
1813
|
for (const result of results) {
|
|
1774
1814
|
if (result.injectedMessages && result.injectedMessages.length > 0) try {
|
|
1775
|
-
injected.push(...
|
|
1815
|
+
injected.push(...convertInjectedMessages(result.injectedMessages));
|
|
1776
1816
|
} catch (e) {
|
|
1777
1817
|
console.warn(`[ToolNode] Failed to convert injectedMessages for toolCallId=${result.toolCallId}:`, e instanceof Error ? e.message : e);
|
|
1778
1818
|
}
|
|
@@ -1890,7 +1930,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
1890
1930
|
...successRefMeta != null && { additional_kwargs: successRefMeta }
|
|
1891
1931
|
});
|
|
1892
1932
|
}
|
|
1893
|
-
if (!eagerCompletionDispatchedIds.has(result.toolCallId) && !earlyCompletionDispatchedIds.has(result.toolCallId)) await this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn);
|
|
1933
|
+
if (!eagerCompletionDispatchedIds.has(result.toolCallId) && !earlyCompletionDispatchedIds.has(result.toolCallId)) await this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn, resolveToolOutcome(request?.args, outcomeFieldsFromResult(result), { isError: result.status === "error" }));
|
|
1894
1934
|
postToolBatchEntryByCallId.set(result.toolCallId, {
|
|
1895
1935
|
toolName,
|
|
1896
1936
|
toolInput: request?.args ?? {},
|
|
@@ -2021,12 +2061,26 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2021
2061
|
* user speech (e.g. steering) sits closest to the next model call.
|
|
2022
2062
|
*/
|
|
2023
2063
|
if (hookInjectedMessages.length > 0) try {
|
|
2024
|
-
injected.push(...
|
|
2064
|
+
injected.push(...convertInjectedMessages(hookInjectedMessages));
|
|
2025
2065
|
} catch (e) {
|
|
2026
2066
|
console.warn("[ToolNode] Failed to convert PostToolBatch injectedMessages:", e instanceof Error ? e.message : e);
|
|
2027
2067
|
}
|
|
2028
2068
|
}
|
|
2029
|
-
|
|
2069
|
+
/**
|
|
2070
|
+
* Whether `name`'s own schema declares a BUSINESS parameter called
|
|
2071
|
+
* `intent` (declared, and not the injected label contract — see
|
|
2072
|
+
* `isIntentLabelProperty`). Such a parameter must keep participating in
|
|
2073
|
+
* `{{tool…}}` placeholder substitution; only the display label is exempt.
|
|
2074
|
+
*/
|
|
2075
|
+
toolDeclaresBusinessIntent(name) {
|
|
2076
|
+
const instance = this.toolMap.get(name);
|
|
2077
|
+
const instanceProp = instance?.schema?.properties?.["intent"] ?? instance?.schema?.shape?.["intent"];
|
|
2078
|
+
if (instanceProp != null) return !isIntentLabelProperty(instanceProp);
|
|
2079
|
+
const defProp = this.toolRegistry?.get(name)?.parameters?.properties?.[INTENT_ARG];
|
|
2080
|
+
if (defProp != null) return !isIntentLabelProperty(defProp);
|
|
2081
|
+
return false;
|
|
2082
|
+
}
|
|
2083
|
+
async dispatchStepCompleted(toolCallId, toolName, args, output, config, turn, outcome) {
|
|
2030
2084
|
const stepId = this.toolCallStepIds?.get(toolCallId) ?? "";
|
|
2031
2085
|
if (!stepId) console.warn(`[ToolNode] toolCallStepIds missing entry for toolCallId=${toolCallId} (tool=${toolName}). This indicates a race between the stream consumer and graph execution. Map size: ${this.toolCallStepIds?.size ?? 0}`);
|
|
2032
2086
|
return await safeDispatchCustomEvent("on_run_step_completed", { result: {
|
|
@@ -2038,7 +2092,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2038
2092
|
name: toolName,
|
|
2039
2093
|
id: toolCallId,
|
|
2040
2094
|
output,
|
|
2041
|
-
progress: 1
|
|
2095
|
+
progress: 1,
|
|
2096
|
+
...outcome != null && { outcome }
|
|
2042
2097
|
}
|
|
2043
2098
|
} }, config) !== false;
|
|
2044
2099
|
}
|
|
@@ -2051,27 +2106,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2051
2106
|
*/
|
|
2052
2107
|
async dispatchEarlyToolCompletion(result, request, config) {
|
|
2053
2108
|
const output = result.status === "error" ? truncateToolResultContent(`Error: ${result.errorMessage ?? "Unknown error"}\n Please fix your mistakes.`, this.maxToolResultChars) : serializeToolOutputWithinLimits(result.content, this.maxToolResultChars).content;
|
|
2054
|
-
return this.dispatchStepCompleted(result.toolCallId, request.name, request.args, output, config, request.turn);
|
|
2055
|
-
}
|
|
2056
|
-
/**
|
|
2057
|
-
* Converts InjectedMessage instances to LangChain HumanMessage objects.
|
|
2058
|
-
* Both 'user' and 'system' roles become HumanMessage to avoid provider
|
|
2059
|
-
* rejections (Anthropic/Google reject non-leading SystemMessages).
|
|
2060
|
-
* The original role is preserved in additional_kwargs for downstream consumers.
|
|
2061
|
-
*/
|
|
2062
|
-
convertInjectedMessages(messages) {
|
|
2063
|
-
const converted = [];
|
|
2064
|
-
for (const msg of messages) {
|
|
2065
|
-
const additional_kwargs = { role: msg.role };
|
|
2066
|
-
if (msg.isMeta != null) additional_kwargs.isMeta = msg.isMeta;
|
|
2067
|
-
if (msg.source != null) additional_kwargs.source = msg.source;
|
|
2068
|
-
if (msg.skillName != null) additional_kwargs.skillName = msg.skillName;
|
|
2069
|
-
converted.push(new HumanMessage({
|
|
2070
|
-
content: toLangChainContent(msg.content),
|
|
2071
|
-
additional_kwargs
|
|
2072
|
-
}));
|
|
2073
|
-
}
|
|
2074
|
-
return converted;
|
|
2109
|
+
return this.dispatchStepCompleted(result.toolCallId, request.name, request.args, output, config, request.turn, resolveToolOutcome(request.args, outcomeFieldsFromResult(result), { isError: result.status === "error" }));
|
|
2075
2110
|
}
|
|
2076
2111
|
/**
|
|
2077
2112
|
* Execute a group of direct (in-process) tool calls with interrupt-safe
|
|
@@ -2152,6 +2187,8 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2152
2187
|
* ToolNode cannot read or wipe each other's entries.
|
|
2153
2188
|
*/
|
|
2154
2189
|
const resolvedArgsByCallId = /* @__PURE__ */ new Map();
|
|
2190
|
+
/** Per-invocation error-completion ownership — see `ToolErrorOwnership`. */
|
|
2191
|
+
const errorOwnership = createToolErrorOwnership();
|
|
2155
2192
|
const batchScopeId = config.configurable?.run_id ?? `\0anon-${this.anonBatchCounter++}`;
|
|
2156
2193
|
const turn = this.toolOutputRegistry?.nextTurn(batchScopeId) ?? 0;
|
|
2157
2194
|
let outputs;
|
|
@@ -2169,6 +2206,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2169
2206
|
turn,
|
|
2170
2207
|
batchScopeId,
|
|
2171
2208
|
resolvedArgsByCallId,
|
|
2209
|
+
errorOwnership,
|
|
2172
2210
|
additionalContextsSink: directAdditionalContexts,
|
|
2173
2211
|
runInput: sendState
|
|
2174
2212
|
});
|
|
@@ -2179,7 +2217,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2179
2217
|
source: "hook"
|
|
2180
2218
|
}
|
|
2181
2219
|
})] : [sendOutput];
|
|
2182
|
-
await this.handleRunToolCompletions([input.lg_tool_call], [sendOutput], config, resolvedArgsByCallId);
|
|
2220
|
+
await this.handleRunToolCompletions([input.lg_tool_call], [sendOutput], config, resolvedArgsByCallId, errorOwnership);
|
|
2183
2221
|
} else {
|
|
2184
2222
|
let messages;
|
|
2185
2223
|
if (Array.isArray(input)) messages = input;
|
|
@@ -2257,7 +2295,7 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2257
2295
|
const preBatchSnapshot = this.toolOutputRegistry?.snapshot(batchScopeId);
|
|
2258
2296
|
if (preBatchSnapshot != null) {
|
|
2259
2297
|
for (const entry of eventEntries) if (entry.call.id != null) {
|
|
2260
|
-
const { resolved, unresolved } = preBatchSnapshot.resolve(entry.call.args);
|
|
2298
|
+
const { resolved, unresolved } = preBatchSnapshot.resolve(entry.call.args, { substituteIntentKey: this.toolDeclaresBusinessIntent(entry.call.name) });
|
|
2261
2299
|
preResolvedEventArgs.set(entry.call.id, {
|
|
2262
2300
|
resolved,
|
|
2263
2301
|
unresolved
|
|
@@ -2269,11 +2307,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2269
2307
|
turn,
|
|
2270
2308
|
batchScopeId,
|
|
2271
2309
|
resolvedArgsByCallId,
|
|
2310
|
+
errorOwnership,
|
|
2272
2311
|
preBatchSnapshot,
|
|
2273
2312
|
additionalContextsSink: directAdditionalContexts,
|
|
2274
2313
|
runInput: input
|
|
2275
2314
|
}) : [];
|
|
2276
|
-
if (directCalls.length > 0 && directOutputs.length > 0) await this.handleRunToolCompletions(directCalls, directOutputs, config, resolvedArgsByCallId);
|
|
2315
|
+
if (directCalls.length > 0 && directOutputs.length > 0) await this.handleRunToolCompletions(directCalls, directOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
2277
2316
|
const eventResult = eventCalls.length > 0 ? await this.dispatchToolEvents(eventCalls, config, {
|
|
2278
2317
|
batchIndices: eventIndices,
|
|
2279
2318
|
turn,
|
|
@@ -2304,11 +2343,12 @@ var ToolNode = class extends RunnableCallable {
|
|
|
2304
2343
|
turn,
|
|
2305
2344
|
batchScopeId,
|
|
2306
2345
|
resolvedArgsByCallId,
|
|
2346
|
+
errorOwnership,
|
|
2307
2347
|
preBatchSnapshot,
|
|
2308
2348
|
additionalContextsSink: directAdditionalContexts,
|
|
2309
2349
|
runInput: input
|
|
2310
2350
|
});
|
|
2311
|
-
await this.handleRunToolCompletions(filteredCalls, toolOutputs, config, resolvedArgsByCallId);
|
|
2351
|
+
await this.handleRunToolCompletions(filteredCalls, toolOutputs, config, resolvedArgsByCallId, errorOwnership);
|
|
2312
2352
|
outputs = directAdditionalContexts.length > 0 ? [...toolOutputs, new HumanMessage({
|
|
2313
2353
|
content: directAdditionalContexts.join("\n\n"),
|
|
2314
2354
|
additional_kwargs: {
|
|
@@ -2414,6 +2454,6 @@ function toolsCondition(state, toolNode, invokedToolIds) {
|
|
|
2414
2454
|
return END;
|
|
2415
2455
|
}
|
|
2416
2456
|
//#endregion
|
|
2417
|
-
export { ToolNode, toolsCondition };
|
|
2457
|
+
export { ToolNode, createToolErrorOwnership, toolsCondition };
|
|
2418
2458
|
|
|
2419
2459
|
//# sourceMappingURL=ToolNode.mjs.map
|