@librechat/agents 4.0.2 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +3 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/decisions/structuredChat.cjs +2 -8
- package/dist/cjs/decisions/structuredChat.cjs.map +1 -1
- package/dist/cjs/decisions/structuredOutput.cjs +18 -0
- package/dist/cjs/decisions/structuredOutput.cjs.map +1 -0
- package/dist/cjs/graphs/Graph.cjs +25 -9
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +34 -12
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +7 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/providerTextBoundary.cjs +355 -0
- package/dist/cjs/llm/providerTextBoundary.cjs.map +1 -0
- package/dist/cjs/llm/providerTextChunk.cjs +14 -0
- package/dist/cjs/llm/providerTextChunk.cjs.map +1 -0
- package/dist/cjs/llm/providerTextControls.cjs +236 -0
- package/dist/cjs/llm/providerTextControls.cjs.map +1 -0
- package/dist/cjs/llm/stream/smoother.cjs +2 -1
- package/dist/cjs/llm/stream/smoother.cjs.map +1 -1
- package/dist/cjs/main.cjs +10 -1
- package/dist/cjs/protection/providerText.cjs +224 -0
- package/dist/cjs/protection/providerText.cjs.map +1 -0
- package/dist/cjs/protection/providerTextInput.cjs +25 -0
- package/dist/cjs/protection/providerTextInput.cjs.map +1 -0
- package/dist/cjs/run.cjs +7 -1
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +42 -14
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +26 -8
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +11 -3
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +6 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +2 -2
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +66 -16
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +4 -2
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +3 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
- package/dist/cjs/tools/subagent/diagnostics.cjs +48 -5
- package/dist/cjs/tools/subagent/diagnostics.cjs.map +1 -1
- package/dist/cjs/tools/subagent/hostArgs.cjs +214 -0
- package/dist/cjs/tools/subagent/hostArgs.cjs.map +1 -0
- package/dist/cjs/tools/subagent/index.cjs +1 -0
- package/dist/cjs/tools/toolErrorContent.cjs +1 -1
- package/dist/esm/agents/AgentContext.mjs +3 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/decisions/structuredChat.mjs +2 -8
- package/dist/esm/decisions/structuredChat.mjs.map +1 -1
- package/dist/esm/decisions/structuredOutput.mjs +18 -0
- package/dist/esm/decisions/structuredOutput.mjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +25 -9
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +34 -12
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +7 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/providerTextBoundary.mjs +355 -0
- package/dist/esm/llm/providerTextBoundary.mjs.map +1 -0
- package/dist/esm/llm/providerTextChunk.mjs +13 -0
- package/dist/esm/llm/providerTextChunk.mjs.map +1 -0
- package/dist/esm/llm/providerTextControls.mjs +230 -0
- package/dist/esm/llm/providerTextControls.mjs.map +1 -0
- package/dist/esm/llm/stream/smoother.mjs +2 -1
- package/dist/esm/llm/stream/smoother.mjs.map +1 -1
- package/dist/esm/main.mjs +5 -3
- package/dist/esm/protection/providerText.mjs +218 -0
- package/dist/esm/protection/providerText.mjs.map +1 -0
- package/dist/esm/protection/providerTextInput.mjs +24 -0
- package/dist/esm/protection/providerTextInput.mjs.map +1 -0
- package/dist/esm/run.mjs +7 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +42 -14
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +26 -8
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/SubagentTool.mjs +11 -3
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +6 -5
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +2 -2
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +66 -16
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +4 -2
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs +3 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
- package/dist/esm/tools/subagent/diagnostics.mjs +46 -6
- package/dist/esm/tools/subagent/diagnostics.mjs.map +1 -1
- package/dist/esm/tools/subagent/hostArgs.mjs +207 -0
- package/dist/esm/tools/subagent/hostArgs.mjs.map +1 -0
- package/dist/esm/tools/subagent/index.mjs +1 -0
- package/dist/esm/tools/toolErrorContent.mjs +1 -1
- package/dist/types/decisions/structuredChat.d.ts +3 -2
- package/dist/types/decisions/structuredOutput.d.ts +4 -0
- package/dist/types/graphs/Graph.d.ts +6 -3
- package/dist/types/index.d.ts +2 -0
- package/dist/types/llm/invoke.d.ts +4 -1
- package/dist/types/llm/providerTextBoundary.d.ts +4 -0
- package/dist/types/llm/providerTextChunk.d.ts +7 -0
- package/dist/types/llm/providerTextControls.d.ts +18 -0
- package/dist/types/protection/providerText.d.ts +77 -0
- package/dist/types/protection/providerTextInput.d.ts +3 -0
- package/dist/types/run.d.ts +1 -0
- package/dist/types/tools/BashExecutor.d.ts +4 -0
- package/dist/types/tools/CodeExecutor.d.ts +4 -0
- package/dist/types/tools/ReadFile.d.ts +4 -0
- package/dist/types/tools/SkillTool.d.ts +4 -0
- package/dist/types/tools/SubagentTool.d.ts +2 -0
- package/dist/types/tools/ToolSearch.d.ts +4 -0
- package/dist/types/tools/search/schema.d.ts +4 -0
- package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +2 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +10 -2
- package/dist/types/tools/subagent/SubagentReplay.d.ts +3 -1
- package/dist/types/tools/subagent/diagnostics.d.ts +27 -3
- package/dist/types/tools/subagent/hostArgs.d.ts +57 -0
- package/dist/types/tools/subagent/index.d.ts +3 -2
- package/dist/types/types/graph.d.ts +36 -0
- package/dist/types/types/run.d.ts +4 -2
- package/dist/types/types/tools.d.ts +2 -0
- package/package.json +4 -4
- package/src/agents/AgentContext.ts +3 -2
- package/src/decisions/structuredChat.ts +9 -15
- package/src/decisions/structuredOutput.ts +25 -0
- package/src/graphs/Graph.ts +53 -9
- package/src/index.ts +7 -0
- package/src/llm/invoke.ts +48 -7
- package/src/llm/openai/index.ts +8 -0
- package/src/llm/providerTextBoundary.ts +446 -0
- package/src/llm/providerTextChunk.ts +15 -0
- package/src/llm/providerTextControls.ts +173 -0
- package/src/llm/stream/smoother.ts +4 -2
- package/src/protection/providerText.ts +325 -0
- package/src/protection/providerTextInput.ts +21 -0
- package/src/run.ts +9 -0
- package/src/stream.ts +33 -7
- package/src/summarization/node.ts +32 -14
- package/src/tools/SubagentTool.ts +14 -3
- package/src/tools/ToolNode.ts +7 -3
- package/src/tools/subagent/SubagentExecutionRegistry.ts +6 -2
- package/src/tools/subagent/SubagentExecutor.ts +145 -18
- package/src/tools/subagent/SubagentReplay.ts +10 -3
- package/src/tools/subagent/childGraphConfig.ts +12 -1
- package/src/tools/subagent/diagnostics.ts +98 -6
- package/src/tools/subagent/hostArgs.ts +413 -0
- package/src/tools/subagent/index.ts +9 -0
- package/src/types/graph.ts +41 -0
- package/src/types/run.ts +4 -2
- package/src/types/tools.ts +6 -1
package/src/tools/ToolNode.ts
CHANGED
|
@@ -130,6 +130,7 @@ import {
|
|
|
130
130
|
} from '@/tools/local';
|
|
131
131
|
import { stripCodeSessionFileSummary } from '@/tools/CodeSessionFileSummary';
|
|
132
132
|
import { Constants, GraphEvents, CODE_EXECUTION_TOOLS } from '@/common';
|
|
133
|
+
import { ProviderTextProtectionError } from '@/protection/providerText';
|
|
133
134
|
import { formatToolErrorContent } from '@/tools/toolErrorContent';
|
|
134
135
|
import { PreparedSubagentError } from '@/tools/preparedSubagents';
|
|
135
136
|
import { attachRunStepResumeState } from '@/tools/runStepResume';
|
|
@@ -2146,7 +2147,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2146
2147
|
*/
|
|
2147
2148
|
if (
|
|
2148
2149
|
e instanceof StreamLimitExceededError ||
|
|
2149
|
-
e instanceof PreparedSubagentError
|
|
2150
|
+
e instanceof PreparedSubagentError ||
|
|
2151
|
+
e instanceof ProviderTextProtectionError
|
|
2150
2152
|
) {
|
|
2151
2153
|
throw e;
|
|
2152
2154
|
}
|
|
@@ -3486,7 +3488,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3486
3488
|
if (
|
|
3487
3489
|
signal?.aborted === true &&
|
|
3488
3490
|
(signal.reason instanceof StreamLimitExceededError ||
|
|
3489
|
-
signal.reason instanceof PreparedSubagentError
|
|
3491
|
+
signal.reason instanceof PreparedSubagentError ||
|
|
3492
|
+
signal.reason instanceof ProviderTextProtectionError)
|
|
3490
3493
|
) {
|
|
3491
3494
|
throw signal.reason;
|
|
3492
3495
|
}
|
|
@@ -5467,7 +5470,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
5467
5470
|
if (
|
|
5468
5471
|
composedSignal?.aborted === true &&
|
|
5469
5472
|
(composedSignal.reason instanceof StreamLimitExceededError ||
|
|
5470
|
-
composedSignal.reason instanceof PreparedSubagentError
|
|
5473
|
+
composedSignal.reason instanceof PreparedSubagentError ||
|
|
5474
|
+
composedSignal.reason instanceof ProviderTextProtectionError)
|
|
5471
5475
|
) {
|
|
5472
5476
|
throw composedSignal.reason;
|
|
5473
5477
|
}
|
|
@@ -63,6 +63,8 @@ export type SubagentInvocationBinding = Readonly<{
|
|
|
63
63
|
description: string;
|
|
64
64
|
subagentType: string;
|
|
65
65
|
configId?: string;
|
|
66
|
+
/** Value-free identity of the call's validated host arguments. */
|
|
67
|
+
hostArgsDigest?: string;
|
|
66
68
|
}>;
|
|
67
69
|
|
|
68
70
|
export type SubagentSettlementBinding = Readonly<{
|
|
@@ -340,7 +342,8 @@ function assertCompatibleResumeExecution(
|
|
|
340
342
|
current.parentToolCallId === next.parentToolCallId &&
|
|
341
343
|
current.childRunId === next.childRunId &&
|
|
342
344
|
current.subagentType === next.subagentType &&
|
|
343
|
-
current.configId === next.configId
|
|
345
|
+
current.configId === next.configId &&
|
|
346
|
+
current.hostArgsDigest === next.hostArgsDigest
|
|
344
347
|
) {
|
|
345
348
|
return;
|
|
346
349
|
}
|
|
@@ -354,7 +357,8 @@ function assertSameInvocation(
|
|
|
354
357
|
if (
|
|
355
358
|
current.description === next.description &&
|
|
356
359
|
current.subagentType === next.subagentType &&
|
|
357
|
-
current.configId === next.configId
|
|
360
|
+
current.configId === next.configId &&
|
|
361
|
+
current.hostArgsDigest === next.hostArgsDigest
|
|
358
362
|
) {
|
|
359
363
|
return;
|
|
360
364
|
}
|
|
@@ -60,6 +60,7 @@ import type {
|
|
|
60
60
|
SubagentTaskConfig,
|
|
61
61
|
SubagentTaskRuntime,
|
|
62
62
|
SubagentResolveConfigurable,
|
|
63
|
+
SubagentHostArgs,
|
|
63
64
|
SubagentResolveRequestContext,
|
|
64
65
|
SubagentResolveUserContext,
|
|
65
66
|
StepCompleted,
|
|
@@ -80,6 +81,12 @@ import type {
|
|
|
80
81
|
SubagentExecutionPreparationLease,
|
|
81
82
|
SubagentExecutionRecord,
|
|
82
83
|
} from './SubagentExecutionRegistry';
|
|
84
|
+
import type {
|
|
85
|
+
SubagentResolutionPhase,
|
|
86
|
+
SubagentResolutionCause,
|
|
87
|
+
SubagentHostArgumentFailure,
|
|
88
|
+
SubagentResolutionFailureHandler,
|
|
89
|
+
} from './diagnostics';
|
|
83
90
|
import type {
|
|
84
91
|
SubagentResumeExecution,
|
|
85
92
|
SubagentResumeManifest,
|
|
@@ -92,11 +99,6 @@ import type {
|
|
|
92
99
|
PreemptBoundaryHookOutput,
|
|
93
100
|
ToolApprovalReplaySnapshot,
|
|
94
101
|
} from '@/hooks';
|
|
95
|
-
import type {
|
|
96
|
-
SubagentResolutionPhase,
|
|
97
|
-
SubagentResolutionCause,
|
|
98
|
-
SubagentResolutionFailureHandler,
|
|
99
|
-
} from './diagnostics';
|
|
100
102
|
import type { RunBreakerScope } from '@/llm/streamLimits';
|
|
101
103
|
import type { GraphFactory } from '@/graphs/graphFactory';
|
|
102
104
|
import type { StandardGraph } from '@/graphs/Graph';
|
|
@@ -114,6 +116,18 @@ import {
|
|
|
114
116
|
SUBAGENT_RESUME_ATTEMPT_CONFIG_KEY,
|
|
115
117
|
SUBAGENT_RESUME_MANIFEST_CONFIG_KEY,
|
|
116
118
|
} from './SubagentReplay';
|
|
119
|
+
import {
|
|
120
|
+
logSubagentResolutionFailure,
|
|
121
|
+
SubagentResolutionError,
|
|
122
|
+
getSubagentHostArgumentFailure,
|
|
123
|
+
getSubagentHostArgumentFailureMessage,
|
|
124
|
+
} from './diagnostics';
|
|
125
|
+
import {
|
|
126
|
+
getSubagentHostArgSpecs,
|
|
127
|
+
resolveSubagentHostArgs,
|
|
128
|
+
pickSubagentHostArgInput,
|
|
129
|
+
getSubagentHostArgsDigest,
|
|
130
|
+
} from './hostArgs';
|
|
117
131
|
import {
|
|
118
132
|
rebindToolBatchReplayScope,
|
|
119
133
|
rebindToolBatchReplayPayload,
|
|
@@ -132,10 +146,6 @@ import {
|
|
|
132
146
|
DEFAULT_SUBAGENT_MAX_TURNS,
|
|
133
147
|
SUBAGENT_RECURSION_MULTIPLIER,
|
|
134
148
|
} from './runtimeLimits';
|
|
135
|
-
import {
|
|
136
|
-
logSubagentResolutionFailure,
|
|
137
|
-
SubagentResolutionError,
|
|
138
|
-
} from './diagnostics';
|
|
139
149
|
import {
|
|
140
150
|
ContentTypes,
|
|
141
151
|
Constants,
|
|
@@ -147,6 +157,7 @@ import {
|
|
|
147
157
|
createChildGraphPlan,
|
|
148
158
|
isGraphSubagentConfig,
|
|
149
159
|
} from './childGraphConfig';
|
|
160
|
+
import { ProviderTextProtectionError } from '@/protection/providerText';
|
|
150
161
|
import { stripRunStepResumeState } from '@/tools/runStepResume';
|
|
151
162
|
import { seedAgentInitialSessions } from '@/utils/toolSessions';
|
|
152
163
|
import { stableStringify } from '@/tools/eagerEventExecution';
|
|
@@ -178,7 +189,11 @@ const SUBAGENT_INVOCATION_CHANGED_MESSAGE =
|
|
|
178
189
|
|
|
179
190
|
function isSubagentResolutionControlFlow(error: unknown): boolean {
|
|
180
191
|
try {
|
|
181
|
-
return
|
|
192
|
+
return (
|
|
193
|
+
error instanceof StreamLimitExceededError ||
|
|
194
|
+
error instanceof ProviderTextProtectionError ||
|
|
195
|
+
isGraphInterrupt(error)
|
|
196
|
+
);
|
|
182
197
|
} catch {
|
|
183
198
|
return false;
|
|
184
199
|
}
|
|
@@ -678,7 +693,8 @@ function getSettlementFingerprint(output: PersistedToolOutput): string {
|
|
|
678
693
|
function getBackgroundTaskFingerprint(
|
|
679
694
|
description: string,
|
|
680
695
|
subagentType: string,
|
|
681
|
-
threadId?: string
|
|
696
|
+
threadId?: string,
|
|
697
|
+
hostArgsDigest?: string
|
|
682
698
|
): string {
|
|
683
699
|
return createHash('sha256')
|
|
684
700
|
.update(
|
|
@@ -686,11 +702,29 @@ function getBackgroundTaskFingerprint(
|
|
|
686
702
|
description,
|
|
687
703
|
subagentType,
|
|
688
704
|
...(threadId == null || threadId === '' ? {} : { threadId }),
|
|
705
|
+
...(hostArgsDigest == null ? {} : { hostArgsDigest }),
|
|
689
706
|
})
|
|
690
707
|
)
|
|
691
708
|
.digest('hex');
|
|
692
709
|
}
|
|
693
710
|
|
|
711
|
+
/** Host-argument digest of persisted lifecycle args, when they are well formed. */
|
|
712
|
+
function getHostArgsDigestFromArgs(
|
|
713
|
+
config: ExecutableSubagentConfigEntry | undefined,
|
|
714
|
+
args: unknown
|
|
715
|
+
): string | undefined {
|
|
716
|
+
if (config == null || !isObjectLike(args)) {
|
|
717
|
+
return undefined;
|
|
718
|
+
}
|
|
719
|
+
const names = new Set(getSubagentHostArgSpecs(config).map(([name]) => name));
|
|
720
|
+
const picked = pickSubagentHostArgInput(args, names);
|
|
721
|
+
if (!picked.ok) {
|
|
722
|
+
return undefined;
|
|
723
|
+
}
|
|
724
|
+
const resolved = resolveSubagentHostArgs(config, picked.hostArgs);
|
|
725
|
+
return resolved.ok ? getSubagentHostArgsDigest(resolved.hostArgs) : undefined;
|
|
726
|
+
}
|
|
727
|
+
|
|
694
728
|
function getBackgroundTaskHookSessionId(
|
|
695
729
|
sourceHookSessionId: string,
|
|
696
730
|
taskId: string
|
|
@@ -877,6 +911,11 @@ export type SubagentExecuteParams = {
|
|
|
877
911
|
taskRuntime?: SubagentTaskRuntime;
|
|
878
912
|
/** Host-restored child transcript for a fresh continuation run. @internal */
|
|
879
913
|
initialMessages?: BaseMessage[];
|
|
914
|
+
/**
|
|
915
|
+
* Values for the selected subagent's declared `hostArgs`. Checked against
|
|
916
|
+
* the declaration before an execution opens, then bound to it.
|
|
917
|
+
*/
|
|
918
|
+
hostArgs?: SubagentHostArgs;
|
|
880
919
|
};
|
|
881
920
|
|
|
882
921
|
export type SubagentExecuteResult = SubagentContextResult & {
|
|
@@ -886,6 +925,7 @@ export type SubagentExecuteResult = SubagentContextResult & {
|
|
|
886
925
|
resolutionFailure?: {
|
|
887
926
|
phase: SubagentResolutionPhase;
|
|
888
927
|
cause: SubagentResolutionCause;
|
|
928
|
+
hostArgument?: SubagentHostArgumentFailure;
|
|
889
929
|
};
|
|
890
930
|
/** Completed child work whose host projection must be retried without re-execution. */
|
|
891
931
|
retryableDelivery?: true;
|
|
@@ -957,6 +997,7 @@ export type SubagentExecutorOptions = {
|
|
|
957
997
|
* graph's own resolved limits; without this the child would silently
|
|
958
998
|
* revert to the defaults.
|
|
959
999
|
*/
|
|
1000
|
+
providerTextProtection?: StandardGraphInput['providerTextProtection'];
|
|
960
1001
|
streamLimits?: StandardGraphInput['streamLimits'];
|
|
961
1002
|
humanInTheLoop?: HumanInTheLoopConfig;
|
|
962
1003
|
/** Shared durable saver used to recover outer tool lifecycle results before
|
|
@@ -1034,6 +1075,7 @@ export class SubagentExecutor {
|
|
|
1034
1075
|
private readonly executionContext: SubagentExecutionContext;
|
|
1035
1076
|
private readonly langfuse?: StandardGraphInput['langfuse'];
|
|
1036
1077
|
private readonly tokenCounter?: TokenCounter;
|
|
1078
|
+
private readonly providerTextProtection?: StandardGraphInput['providerTextProtection'];
|
|
1037
1079
|
private readonly streamLimits?: StandardGraphInput['streamLimits'];
|
|
1038
1080
|
private readonly humanInTheLoop?: HumanInTheLoopConfig;
|
|
1039
1081
|
private readonly checkpointer?: BaseCheckpointSaver;
|
|
@@ -1074,6 +1116,7 @@ export class SubagentExecutor {
|
|
|
1074
1116
|
this.langfuse = options.langfuse;
|
|
1075
1117
|
this.tokenCounter = options.tokenCounter;
|
|
1076
1118
|
this.streamLimits = options.streamLimits;
|
|
1119
|
+
this.providerTextProtection = options.providerTextProtection;
|
|
1077
1120
|
this.humanInTheLoop = options.humanInTheLoop;
|
|
1078
1121
|
this.checkpointer = isCheckpointSaver(options.checkpointer)
|
|
1079
1122
|
? options.checkpointer
|
|
@@ -1148,6 +1191,18 @@ export class SubagentExecutor {
|
|
|
1148
1191
|
message: `Unknown subagent type "${params.subagentType}".`,
|
|
1149
1192
|
});
|
|
1150
1193
|
}
|
|
1194
|
+
const hostArgResult = resolveSubagentHostArgs(
|
|
1195
|
+
executableConfig,
|
|
1196
|
+
params.hostArgs
|
|
1197
|
+
);
|
|
1198
|
+
if (!hostArgResult.ok) {
|
|
1199
|
+
return JSON.stringify({
|
|
1200
|
+
status: 'rejected',
|
|
1201
|
+
tool: Constants.SUBAGENT,
|
|
1202
|
+
message: hostArgResult.message,
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
const { hostArgs } = hostArgResult;
|
|
1151
1206
|
if (this.maxDepth <= 0) {
|
|
1152
1207
|
return JSON.stringify({
|
|
1153
1208
|
status: 'rejected',
|
|
@@ -1213,7 +1268,8 @@ export class SubagentExecutor {
|
|
|
1213
1268
|
requestFingerprint: getBackgroundTaskFingerprint(
|
|
1214
1269
|
params.description,
|
|
1215
1270
|
params.subagentType,
|
|
1216
|
-
subagentThreadId
|
|
1271
|
+
subagentThreadId,
|
|
1272
|
+
getSubagentHostArgsDigest(hostArgs)
|
|
1217
1273
|
),
|
|
1218
1274
|
...(subagentThreadId == null || subagentThreadId === ''
|
|
1219
1275
|
? {}
|
|
@@ -1228,6 +1284,7 @@ export class SubagentExecutor {
|
|
|
1228
1284
|
this.executeDetached(
|
|
1229
1285
|
{
|
|
1230
1286
|
...params,
|
|
1287
|
+
hostArgs,
|
|
1231
1288
|
...(initialMessages == null ? {} : { initialMessages }),
|
|
1232
1289
|
},
|
|
1233
1290
|
runtime,
|
|
@@ -1344,6 +1401,7 @@ export class SubagentExecutor {
|
|
|
1344
1401
|
subagentContext: this.subagentContext,
|
|
1345
1402
|
onResolutionFailure: this.onResolutionFailure,
|
|
1346
1403
|
streamLimits: this.streamLimits,
|
|
1404
|
+
providerTextProtection: this.providerTextProtection,
|
|
1347
1405
|
humanInTheLoop:
|
|
1348
1406
|
this.humanInTheLoop?.enabled === true ||
|
|
1349
1407
|
this.humanInTheLoop?.backgroundPausePolicy === 'deny'
|
|
@@ -1397,7 +1455,8 @@ export class SubagentExecutor {
|
|
|
1397
1455
|
if (result.resolutionFailure != null) {
|
|
1398
1456
|
throw new SubagentResolutionError(
|
|
1399
1457
|
result.resolutionFailure.phase,
|
|
1400
|
-
result.resolutionFailure.cause
|
|
1458
|
+
result.resolutionFailure.cause,
|
|
1459
|
+
result.resolutionFailure.hostArgument
|
|
1401
1460
|
);
|
|
1402
1461
|
}
|
|
1403
1462
|
throw new Error(result.error);
|
|
@@ -1461,6 +1520,7 @@ export class SubagentExecutor {
|
|
|
1461
1520
|
threadId?: string;
|
|
1462
1521
|
parentToolCallId?: string;
|
|
1463
1522
|
parentConfigurable?: Record<string, unknown>;
|
|
1523
|
+
hostArgs?: SubagentHostArgs;
|
|
1464
1524
|
}
|
|
1465
1525
|
): Promise<ResolvedSubagentConfigEntry> {
|
|
1466
1526
|
if (isGraphSubagentConfig(config) || config.agentInputs != null) {
|
|
@@ -1489,6 +1549,9 @@ export class SubagentExecutor {
|
|
|
1489
1549
|
context.parentConfigurable == null
|
|
1490
1550
|
? undefined
|
|
1491
1551
|
: sanitizeResolverConfigurable(context.parentConfigurable),
|
|
1552
|
+
...(context.hostArgs == null
|
|
1553
|
+
? {}
|
|
1554
|
+
: { hostArgs: context.hostArgs }),
|
|
1492
1555
|
}),
|
|
1493
1556
|
context.childSignal
|
|
1494
1557
|
).then(
|
|
@@ -1937,7 +2000,7 @@ export class SubagentExecutor {
|
|
|
1937
2000
|
}
|
|
1938
2001
|
const executions: SubagentResumeExecution[] = [];
|
|
1939
2002
|
for (const record of records) {
|
|
1940
|
-
const { identity, binding, activeRun } = record.snapshot;
|
|
2003
|
+
const { identity, binding, invocation, activeRun } = record.snapshot;
|
|
1941
2004
|
if (identity == null) {
|
|
1942
2005
|
continue;
|
|
1943
2006
|
}
|
|
@@ -1981,6 +2044,9 @@ export class SubagentExecutor {
|
|
|
1981
2044
|
? {}
|
|
1982
2045
|
: { subagentType: binding.subagentType }),
|
|
1983
2046
|
...(binding?.configId == null ? {} : { configId: binding.configId }),
|
|
2047
|
+
...(invocation?.hostArgsDigest == null
|
|
2048
|
+
? {}
|
|
2049
|
+
: { hostArgsDigest: invocation.hostArgsDigest }),
|
|
1984
2050
|
approvalExecutionScope: identity.approvalExecutionScope,
|
|
1985
2051
|
checkpoints,
|
|
1986
2052
|
graphState,
|
|
@@ -2333,6 +2399,22 @@ export class SubagentExecutor {
|
|
|
2333
2399
|
) {
|
|
2334
2400
|
return;
|
|
2335
2401
|
}
|
|
2402
|
+
const resolvedHostArgsDigest =
|
|
2403
|
+
settled.resolvedArgs == null
|
|
2404
|
+
? undefined
|
|
2405
|
+
: getHostArgsDigestFromArgs(
|
|
2406
|
+
this.configs.get(
|
|
2407
|
+
resolvedSubagentType ?? execution.binding?.subagentType ?? ''
|
|
2408
|
+
),
|
|
2409
|
+
settled.resolvedArgs
|
|
2410
|
+
);
|
|
2411
|
+
if (
|
|
2412
|
+
boundInvocation != null &&
|
|
2413
|
+
settled.resolvedArgs != null &&
|
|
2414
|
+
resolvedHostArgsDigest !== boundInvocation.hostArgsDigest
|
|
2415
|
+
) {
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2336
2418
|
const description =
|
|
2337
2419
|
boundInvocation?.description ??
|
|
2338
2420
|
resolvedDescription ??
|
|
@@ -2364,10 +2446,15 @@ export class SubagentExecutor {
|
|
|
2364
2446
|
return;
|
|
2365
2447
|
}
|
|
2366
2448
|
const persistedOutput = serializeToolOutput(settled);
|
|
2449
|
+
const hostArgsDigest =
|
|
2450
|
+
settled.resolvedArgs == null
|
|
2451
|
+
? getHostArgsDigestFromArgs(executableConfig, call.args)
|
|
2452
|
+
: resolvedHostArgsDigest;
|
|
2367
2453
|
const invocation = boundInvocation ?? {
|
|
2368
2454
|
description,
|
|
2369
2455
|
subagentType,
|
|
2370
2456
|
...(configId == null ? {} : { configId }),
|
|
2457
|
+
...(hostArgsDigest == null ? {} : { hostArgsDigest }),
|
|
2371
2458
|
};
|
|
2372
2459
|
try {
|
|
2373
2460
|
await execution.settle(
|
|
@@ -2484,6 +2571,15 @@ export class SubagentExecutor {
|
|
|
2484
2571
|
)
|
|
2485
2572
|
);
|
|
2486
2573
|
}
|
|
2574
|
+
const hostArgResult = resolveSubagentHostArgs(
|
|
2575
|
+
executableConfig,
|
|
2576
|
+
params.hostArgs
|
|
2577
|
+
);
|
|
2578
|
+
if (!hostArgResult.ok) {
|
|
2579
|
+
return Promise.resolve(createSubagentFailure(hostArgResult.message));
|
|
2580
|
+
}
|
|
2581
|
+
const { hostArgs } = hostArgResult;
|
|
2582
|
+
const hostArgsDigest = getSubagentHostArgsDigest(hostArgs);
|
|
2487
2583
|
if (this.maxDepth <= 0) {
|
|
2488
2584
|
return Promise.resolve(
|
|
2489
2585
|
createSubagentFailure('Error: Maximum subagent nesting depth exceeded.')
|
|
@@ -2522,8 +2618,10 @@ export class SubagentExecutor {
|
|
|
2522
2618
|
...(executableConfig.configId == null
|
|
2523
2619
|
? {}
|
|
2524
2620
|
: { configId: executableConfig.configId }),
|
|
2621
|
+
...(hostArgsDigest == null ? {} : { hostArgsDigest }),
|
|
2525
2622
|
},
|
|
2526
|
-
() =>
|
|
2623
|
+
() =>
|
|
2624
|
+
this.executeOnce({ ...params, hostArgs }, execution, executableConfig)
|
|
2527
2625
|
);
|
|
2528
2626
|
} catch (error) {
|
|
2529
2627
|
if (error instanceof SubagentDefinitionBindingError) {
|
|
@@ -2616,8 +2714,21 @@ export class SubagentExecutor {
|
|
|
2616
2714
|
: execution.address.branchChildThreadId),
|
|
2617
2715
|
taskId: params.taskRuntime?.taskId,
|
|
2618
2716
|
},
|
|
2619
|
-
this.onResolutionFailure
|
|
2717
|
+
this.onResolutionFailure,
|
|
2718
|
+
params.hostArgs
|
|
2620
2719
|
);
|
|
2720
|
+
const hostArgument =
|
|
2721
|
+
phase === 'config'
|
|
2722
|
+
? getSubagentHostArgumentFailure(error, params.hostArgs)
|
|
2723
|
+
: undefined;
|
|
2724
|
+
if (hostArgument != null) {
|
|
2725
|
+
return {
|
|
2726
|
+
...createSubagentFailure(
|
|
2727
|
+
getSubagentHostArgumentFailureMessage(hostArgument)
|
|
2728
|
+
),
|
|
2729
|
+
resolutionFailure: { phase, cause: detail.cause, hostArgument },
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2621
2732
|
return {
|
|
2622
2733
|
...createSubagentFailure(detail.message),
|
|
2623
2734
|
resolutionFailure: { phase, cause: detail.cause },
|
|
@@ -2652,6 +2763,14 @@ export class SubagentExecutor {
|
|
|
2652
2763
|
this.executions.remove(execution);
|
|
2653
2764
|
return createSubagentFailure(SUBAGENT_CONFIG_CHANGED_MESSAGE);
|
|
2654
2765
|
}
|
|
2766
|
+
if (
|
|
2767
|
+
resumeExecution != null &&
|
|
2768
|
+
resumeExecution.hostArgsDigest !==
|
|
2769
|
+
getSubagentHostArgsDigest(params.hostArgs)
|
|
2770
|
+
) {
|
|
2771
|
+
this.executions.remove(execution);
|
|
2772
|
+
return createSubagentFailure(SUBAGENT_INVOCATION_CHANGED_MESSAGE);
|
|
2773
|
+
}
|
|
2655
2774
|
let identity: SubagentExecutionIdentity;
|
|
2656
2775
|
try {
|
|
2657
2776
|
identity = await this.resolveChildExecutionIdentity(execution);
|
|
@@ -2690,6 +2809,7 @@ export class SubagentExecutor {
|
|
|
2690
2809
|
threadId,
|
|
2691
2810
|
parentToolCallId,
|
|
2692
2811
|
parentConfigurable: params.parentConfigurable,
|
|
2812
|
+
hostArgs: params.hostArgs,
|
|
2693
2813
|
});
|
|
2694
2814
|
execution.assertUsable(childSignal);
|
|
2695
2815
|
} catch (error) {
|
|
@@ -2831,6 +2951,7 @@ export class SubagentExecutor {
|
|
|
2831
2951
|
langfuse: this.langfuse,
|
|
2832
2952
|
tokenCounter: this.tokenCounter,
|
|
2833
2953
|
streamLimits: this.streamLimits,
|
|
2954
|
+
providerTextProtection: this.providerTextProtection,
|
|
2834
2955
|
subagentScope: true,
|
|
2835
2956
|
subagentExecutionContext: childExecutionContext,
|
|
2836
2957
|
subagentContext: this.subagentContext,
|
|
@@ -3277,7 +3398,10 @@ export class SubagentExecutor {
|
|
|
3277
3398
|
* quota for that entire interval. Trips the ENTRY-captured controller:
|
|
3278
3399
|
* after a reset, a straggler must break its own dead run, not the
|
|
3279
3400
|
* current one. */
|
|
3280
|
-
if (
|
|
3401
|
+
if (
|
|
3402
|
+
error instanceof StreamLimitExceededError ||
|
|
3403
|
+
error instanceof ProviderTextProtectionError
|
|
3404
|
+
) {
|
|
3281
3405
|
childBreaker.abort(error);
|
|
3282
3406
|
}
|
|
3283
3407
|
const errorMessage = truncateErrorMessage(error);
|
|
@@ -3316,7 +3440,10 @@ export class SubagentExecutor {
|
|
|
3316
3440
|
* fired. Rethrown here and passed through ToolNode's error conversion,
|
|
3317
3441
|
* so the parent run rejects with the child's limit error.
|
|
3318
3442
|
*/
|
|
3319
|
-
if (
|
|
3443
|
+
if (
|
|
3444
|
+
error instanceof StreamLimitExceededError ||
|
|
3445
|
+
error instanceof ProviderTextProtectionError
|
|
3446
|
+
) {
|
|
3320
3447
|
throw error;
|
|
3321
3448
|
}
|
|
3322
3449
|
return createSubagentFailure(
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { ToolCall, ToolMessage } from '@langchain/core/messages/tool';
|
|
2
2
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
3
|
-
import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
|
|
4
|
-
import type { ToolApprovalReplaySnapshot } from '@/hooks';
|
|
5
3
|
import type {
|
|
6
4
|
FadingTier,
|
|
7
5
|
FadingTiers,
|
|
8
6
|
RunStepResumeState,
|
|
9
7
|
ToolSessionContext,
|
|
10
8
|
} from '@/types';
|
|
11
|
-
import {
|
|
9
|
+
import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
|
|
10
|
+
import type { ToolApprovalReplaySnapshot } from '@/hooks';
|
|
12
11
|
import {
|
|
13
12
|
attachRunStepResumeState,
|
|
14
13
|
getRunStepResumeState,
|
|
15
14
|
isRunStepResumeState,
|
|
16
15
|
stripRunStepResumeState,
|
|
17
16
|
} from '@/tools/runStepResume';
|
|
17
|
+
import { isFadingTier, isLegacyFadingTier } from '@/messages/fading';
|
|
18
18
|
|
|
19
19
|
export const SUBAGENT_RESUME_MANIFEST_CONFIG_KEY =
|
|
20
20
|
'__librechat_subagent_resume_manifest';
|
|
@@ -35,6 +35,7 @@ const SUBAGENT_RESUME_PRIVATE_PAYLOAD_KEYS = [
|
|
|
35
35
|
SUBAGENT_RESUME_WRAPPER_VERSION_KEY,
|
|
36
36
|
] as const;
|
|
37
37
|
const MAX_RESUME_MANIFEST_DEPTH = 32;
|
|
38
|
+
const HOST_ARGS_DIGEST_PATTERN = /^[a-f0-9]{64}$/;
|
|
38
39
|
|
|
39
40
|
export interface SubagentCheckpointReference {
|
|
40
41
|
threadId: string;
|
|
@@ -83,6 +84,8 @@ export interface SubagentResumeExecution {
|
|
|
83
84
|
subagentType?: string;
|
|
84
85
|
/** Lazy child revision bound when this execution first resolved. */
|
|
85
86
|
configId?: string;
|
|
87
|
+
/** SHA-256 identity of the host arguments bound to this execution; never the values. */
|
|
88
|
+
hostArgsDigest?: string;
|
|
86
89
|
approvalExecutionScope: string;
|
|
87
90
|
checkpoints: SubagentCheckpointReference[];
|
|
88
91
|
graphState: SubagentGraphResumeState;
|
|
@@ -354,6 +357,7 @@ function isSubagentResumeExecution(
|
|
|
354
357
|
const childRunId = execution.childRunId;
|
|
355
358
|
const subagentType = execution.subagentType;
|
|
356
359
|
const configId = execution.configId;
|
|
360
|
+
const hostArgsDigest = execution.hostArgsDigest;
|
|
357
361
|
const approvalExecutionScope = execution.approvalExecutionScope;
|
|
358
362
|
const checkpoints = execution.checkpoints;
|
|
359
363
|
const graphState = execution.graphState;
|
|
@@ -363,6 +367,9 @@ function isSubagentResumeExecution(
|
|
|
363
367
|
!isString(childRunId) ||
|
|
364
368
|
(subagentType != null && !isString(subagentType)) ||
|
|
365
369
|
(configId != null && !isString(configId)) ||
|
|
370
|
+
(hostArgsDigest != null &&
|
|
371
|
+
(typeof hostArgsDigest !== 'string' ||
|
|
372
|
+
!HOST_ARGS_DIGEST_PATTERN.test(hostArgsDigest))) ||
|
|
366
373
|
!isString(approvalExecutionScope) ||
|
|
367
374
|
!Array.isArray(checkpoints) ||
|
|
368
375
|
checkpoints.length === 0 ||
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
MAX_GRAPH_SUBAGENT_MEMBERS,
|
|
16
16
|
MAX_GRAPH_SUBAGENT_TURNS,
|
|
17
17
|
} from './runtimeLimits';
|
|
18
|
+
import { getSubagentHostArgSpecs } from './hostArgs';
|
|
18
19
|
|
|
19
20
|
const RESERVED_GRAPH_MEMBER_IDS = new Set([
|
|
20
21
|
'__start__',
|
|
@@ -69,6 +70,7 @@ type GraphSubagentConfigCandidate = {
|
|
|
69
70
|
configId?: unknown;
|
|
70
71
|
agentInputs?: unknown;
|
|
71
72
|
resolveAgentInputs?: unknown;
|
|
73
|
+
hostArgs?: unknown;
|
|
72
74
|
self?: unknown;
|
|
73
75
|
};
|
|
74
76
|
|
|
@@ -156,10 +158,11 @@ function assertGraphSubagentConfigShape(
|
|
|
156
158
|
candidate.agentInputs !== undefined ||
|
|
157
159
|
candidate.resolveAgentInputs !== undefined ||
|
|
158
160
|
candidate.configId !== undefined ||
|
|
161
|
+
candidate.hostArgs !== undefined ||
|
|
159
162
|
candidate.self !== undefined
|
|
160
163
|
) {
|
|
161
164
|
throw new Error(
|
|
162
|
-
`Graph subagent "${configType}" cannot define agentInputs or self, or lazy fields configId/resolveAgentInputs.`
|
|
165
|
+
`Graph subagent "${configType}" cannot define agentInputs or self, or lazy fields configId/resolveAgentInputs/hostArgs.`
|
|
163
166
|
);
|
|
164
167
|
}
|
|
165
168
|
}
|
|
@@ -482,6 +485,14 @@ function normalizeSingleAgentConfig(
|
|
|
482
485
|
`Subagent "${config.type}" cannot combine self with resolveAgentInputs.`
|
|
483
486
|
);
|
|
484
487
|
}
|
|
488
|
+
if (
|
|
489
|
+
getSubagentHostArgSpecs(config).length > 0 &&
|
|
490
|
+
(config.resolveAgentInputs == null || config.agentInputs != null)
|
|
491
|
+
) {
|
|
492
|
+
throw new Error(
|
|
493
|
+
`Subagent "${config.type}" declares hostArgs, which only a lazy resolveAgentInputs config without eager agentInputs can receive.`
|
|
494
|
+
);
|
|
495
|
+
}
|
|
485
496
|
if (config.agentInputs != null) {
|
|
486
497
|
return config as ResolvedSingleAgentSubagentConfig;
|
|
487
498
|
}
|