@librechat/agents 3.8.5 → 3.8.7
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 +1 -1
- package/dist/cjs/common/constants.cjs +2 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +18 -9
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/hitl/approvalReview.cjs +1 -1
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/main.cjs +8 -6
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +1 -1
- package/dist/cjs/run.cjs +7 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +13 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +3 -1
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +79 -27
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +47 -7
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +5 -2
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/CodeSessionFileSummary.cjs +11 -1
- package/dist/cjs/tools/CodeSessionFileSummary.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +54 -8
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +176 -43
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +1 -0
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +0 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +120 -26
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/toolBatchReplay.cjs +4 -2
- package/dist/cjs/tools/toolBatchReplay.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/esm/agents/AgentContext.mjs +1 -1
- package/dist/esm/common/constants.mjs +2 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +17 -8
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/hitl/approvalReview.mjs +1 -1
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/main.mjs +7 -7
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +1 -1
- package/dist/esm/run.mjs +7 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +13 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +3 -1
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +81 -29
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +48 -9
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +5 -2
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/CodeSessionFileSummary.mjs +11 -2
- package/dist/esm/tools/CodeSessionFileSummary.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +55 -9
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +176 -43
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +1 -0
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +0 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +120 -26
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/toolBatchReplay.mjs +4 -2
- package/dist/esm/tools/toolBatchReplay.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/types/common/constants.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +3 -2
- package/dist/types/hooks/types.d.ts +3 -0
- package/dist/types/run.d.ts +1 -0
- package/dist/types/summarization/node.d.ts +1 -0
- package/dist/types/tools/BashExecutor.d.ts +2 -0
- package/dist/types/tools/BashProgrammaticToolCalling.d.ts +1 -0
- package/dist/types/tools/CodeExecutor.d.ts +1 -1
- package/dist/types/tools/CodeSessionFileSummary.d.ts +3 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +2 -2
- package/dist/types/tools/ToolNode.d.ts +6 -2
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +7 -4
- package/dist/types/tools/toolBatchReplay.d.ts +2 -0
- package/dist/types/types/graph.d.ts +28 -0
- package/dist/types/types/run.d.ts +2 -0
- package/dist/types/types/tools.d.ts +27 -3
- package/package.json +2 -2
- package/src/common/constants.ts +3 -0
- package/src/graphs/Graph.ts +32 -18
- package/src/hooks/types.ts +3 -0
- package/src/run.ts +30 -15
- package/src/stream.ts +27 -5
- package/src/summarization/node.ts +3 -0
- package/src/tools/BashExecutor.ts +143 -40
- package/src/tools/BashProgrammaticToolCalling.ts +82 -10
- package/src/tools/CodeExecutor.ts +12 -2
- package/src/tools/CodeSessionFileSummary.ts +25 -1
- package/src/tools/ProgrammaticToolCalling.ts +77 -6
- package/src/tools/ToolNode.ts +665 -170
- package/src/tools/local/LocalProgrammaticToolCalling.ts +1 -0
- package/src/tools/subagent/SubagentExecutionRegistry.ts +0 -1
- package/src/tools/subagent/SubagentExecutor.ts +214 -55
- package/src/tools/toolBatchReplay.ts +23 -1
- package/src/types/graph.ts +37 -0
- package/src/types/run.ts +2 -0
- package/src/types/tools.ts +30 -3
- package/src/utils/llmConfig.ts +0 -1
|
@@ -214,6 +214,7 @@ export async function applyPreToolUseHooksForBridge(
|
|
|
214
214
|
runId: hookContext.runId,
|
|
215
215
|
threadId: hookContext.threadId,
|
|
216
216
|
agentId: hookContext.agentId,
|
|
217
|
+
executionContext: hookContext.executionContext,
|
|
217
218
|
executingAgentId: hookContext.executingAgentId,
|
|
218
219
|
toolName,
|
|
219
220
|
toolInput,
|
|
@@ -783,7 +783,6 @@ export class SubagentExecutionRecord<
|
|
|
783
783
|
this.transitionTo('completed', ['active']);
|
|
784
784
|
this.completedValue = true;
|
|
785
785
|
this.completedResultValue = result;
|
|
786
|
-
this.resolvedConfigValue = undefined;
|
|
787
786
|
}
|
|
788
787
|
|
|
789
788
|
releaseActiveRun(): TActiveRun | undefined {
|
|
@@ -52,6 +52,10 @@ import type {
|
|
|
52
52
|
ResolvedSubagentConfig,
|
|
53
53
|
ResolvedSubagentConfigEntry,
|
|
54
54
|
SubagentExecutionContext,
|
|
55
|
+
SubagentContextAdapter,
|
|
56
|
+
SubagentContextInput,
|
|
57
|
+
SubagentContextResult,
|
|
58
|
+
PreparedSubagentContext,
|
|
55
59
|
SubagentTaskConfig,
|
|
56
60
|
SubagentTaskRuntime,
|
|
57
61
|
SubagentResolveConfigurable,
|
|
@@ -88,11 +92,6 @@ import type {
|
|
|
88
92
|
ToolApprovalReplaySnapshot,
|
|
89
93
|
} from '@/hooks';
|
|
90
94
|
import type { GraphFactory } from '@/graphs/graphFactory';
|
|
91
|
-
import {
|
|
92
|
-
rebindToolBatchReplayScope,
|
|
93
|
-
rebindToolBatchReplayPayload,
|
|
94
|
-
restoreToolReplayConfig,
|
|
95
|
-
} from '@/tools/toolBatchReplay';
|
|
96
95
|
import type { StandardGraph } from '@/graphs/Graph';
|
|
97
96
|
import {
|
|
98
97
|
getSubagentApprovalExecutionScope,
|
|
@@ -108,6 +107,11 @@ import {
|
|
|
108
107
|
SUBAGENT_RESUME_ATTEMPT_CONFIG_KEY,
|
|
109
108
|
SUBAGENT_RESUME_MANIFEST_CONFIG_KEY,
|
|
110
109
|
} from './SubagentReplay';
|
|
110
|
+
import {
|
|
111
|
+
rebindToolBatchReplayScope,
|
|
112
|
+
rebindToolBatchReplayPayload,
|
|
113
|
+
restoreToolReplayConfig,
|
|
114
|
+
} from '@/tools/toolBatchReplay';
|
|
111
115
|
import {
|
|
112
116
|
executeHooks,
|
|
113
117
|
HookRegistry,
|
|
@@ -138,6 +142,7 @@ import { stableStringify } from '@/tools/eagerEventExecution';
|
|
|
138
142
|
import { convertInjectedMessages } from '@/messages/injected';
|
|
139
143
|
import { resolveClientOptionsModel } from '@/llm/request';
|
|
140
144
|
import { composeAbortSignals } from '@/utils/misc';
|
|
145
|
+
import { sleep } from '@/utils/run';
|
|
141
146
|
import { HandlerRegistry } from '@/events';
|
|
142
147
|
|
|
143
148
|
export {
|
|
@@ -168,6 +173,31 @@ function seedChildGraphSessions(
|
|
|
168
173
|
seedAgentInitialSessions(childGraph.sessions, agents);
|
|
169
174
|
}
|
|
170
175
|
|
|
176
|
+
async function awaitWithAbort<T>(
|
|
177
|
+
promise: Promise<T>,
|
|
178
|
+
signal: AbortSignal
|
|
179
|
+
): Promise<T> {
|
|
180
|
+
signal.throwIfAborted();
|
|
181
|
+
let onAbort: (() => void) | undefined;
|
|
182
|
+
const aborted = new Promise<never>((_resolve, reject) => {
|
|
183
|
+
onAbort = (): void => {
|
|
184
|
+
reject(
|
|
185
|
+
signal.reason instanceof Error
|
|
186
|
+
? signal.reason
|
|
187
|
+
: new Error('Detached subagent task cancelled.')
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
191
|
+
});
|
|
192
|
+
try {
|
|
193
|
+
return await Promise.race([promise, aborted]);
|
|
194
|
+
} finally {
|
|
195
|
+
if (onAbort != null) {
|
|
196
|
+
signal.removeEventListener('abort', onAbort);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
171
201
|
async function dispatchObservationalSubagentUpdate(
|
|
172
202
|
handler: EventHandler,
|
|
173
203
|
event: SubagentUpdateEvent
|
|
@@ -831,11 +861,11 @@ export type SubagentExecuteParams = {
|
|
|
831
861
|
initialMessages?: BaseMessage[];
|
|
832
862
|
};
|
|
833
863
|
|
|
834
|
-
export type SubagentExecuteResult = {
|
|
835
|
-
content: string;
|
|
836
|
-
messages: BaseMessage[];
|
|
864
|
+
export type SubagentExecuteResult = SubagentContextResult & {
|
|
837
865
|
/** Tagged internal failure; foreground callers retain the legacy content. */
|
|
838
866
|
error?: string;
|
|
867
|
+
/** Completed child work whose host projection must be retried without re-execution. */
|
|
868
|
+
retryableDelivery?: true;
|
|
839
869
|
};
|
|
840
870
|
|
|
841
871
|
function createSubagentFailure(
|
|
@@ -931,6 +961,7 @@ export type SubagentExecutorOptions = {
|
|
|
931
961
|
usageSink?: SubagentUsageSink;
|
|
932
962
|
/** Host-owned process-local task namespace for detached execution. */
|
|
933
963
|
taskConfig?: SubagentTaskConfig;
|
|
964
|
+
subagentContext?: SubagentContextAdapter;
|
|
934
965
|
};
|
|
935
966
|
|
|
936
967
|
type DurableExecutionRecord = SubagentExecutionRecord<
|
|
@@ -968,6 +999,7 @@ export class SubagentExecutor {
|
|
|
968
999
|
) => GraphFactory;
|
|
969
1000
|
private readonly usageSink?: SubagentUsageSink;
|
|
970
1001
|
private readonly taskConfig?: SubagentTaskConfig;
|
|
1002
|
+
private readonly subagentContext?: SubagentContextAdapter;
|
|
971
1003
|
private readonly executions: SubagentExecutionRegistry<
|
|
972
1004
|
SubagentExecuteResult,
|
|
973
1005
|
ResolvedSubagentConfig,
|
|
@@ -1012,6 +1044,7 @@ export class SubagentExecutor {
|
|
|
1012
1044
|
options.createDetachedChildGraphFactory;
|
|
1013
1045
|
this.usageSink = options.usageSink;
|
|
1014
1046
|
this.taskConfig = options.taskConfig;
|
|
1047
|
+
this.subagentContext = options.subagentContext;
|
|
1015
1048
|
const rawRegistry = options.parentHandlerRegistry;
|
|
1016
1049
|
if (typeof rawRegistry === 'function') {
|
|
1017
1050
|
this.resolveParentHandlerRegistry = rawRegistry;
|
|
@@ -1257,6 +1290,7 @@ export class SubagentExecutor {
|
|
|
1257
1290
|
langfuse: this.langfuse,
|
|
1258
1291
|
tokenCounter: this.tokenCounter,
|
|
1259
1292
|
usageSink: this.usageSink,
|
|
1293
|
+
subagentContext: this.subagentContext,
|
|
1260
1294
|
streamLimits: this.streamLimits,
|
|
1261
1295
|
maxDepth: this.maxDepth,
|
|
1262
1296
|
createChildGraph:
|
|
@@ -1268,21 +1302,38 @@ export class SubagentExecutor {
|
|
|
1268
1302
|
detachedGraphFactory ?? this.createChildGraphByKind,
|
|
1269
1303
|
});
|
|
1270
1304
|
try {
|
|
1271
|
-
const
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1305
|
+
const executeAttempt = async (): Promise<SubagentExecuteResult> => {
|
|
1306
|
+
const result = await detached.execute({
|
|
1307
|
+
...params,
|
|
1308
|
+
signal: undefined,
|
|
1309
|
+
breaker: undefined,
|
|
1310
|
+
hookSessionId: taskHookSessionId,
|
|
1311
|
+
taskRuntime: runtime,
|
|
1312
|
+
parentConfigurable: {
|
|
1313
|
+
...params.parentConfigurable,
|
|
1314
|
+
run_id: taskHookSessionId,
|
|
1315
|
+
},
|
|
1316
|
+
});
|
|
1317
|
+
if (runtime.signal.aborted) {
|
|
1318
|
+
throw runtime.signal.reason instanceof Error
|
|
1319
|
+
? runtime.signal.reason
|
|
1320
|
+
: new Error('Detached subagent task cancelled.');
|
|
1321
|
+
}
|
|
1322
|
+
return result;
|
|
1323
|
+
};
|
|
1324
|
+
let deliveryAttempts = 1;
|
|
1325
|
+
let result = await executeAttempt();
|
|
1326
|
+
while (
|
|
1327
|
+
result.retryableDelivery === true &&
|
|
1328
|
+
deliveryAttempts < 3
|
|
1329
|
+
) {
|
|
1330
|
+
if (deliveryAttempts > 1) {
|
|
1331
|
+
await sleep(
|
|
1332
|
+
Math.min(100 * 2 ** Math.min(deliveryAttempts - 2, 6), 5_000)
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
deliveryAttempts += 1;
|
|
1336
|
+
result = await executeAttempt();
|
|
1286
1337
|
}
|
|
1287
1338
|
if (result.error != null) {
|
|
1288
1339
|
throw new Error(result.error);
|
|
@@ -1454,7 +1505,10 @@ export class SubagentExecutor {
|
|
|
1454
1505
|
resumeExecution.checkpoints,
|
|
1455
1506
|
branchChildThreadId,
|
|
1456
1507
|
lease,
|
|
1457
|
-
{
|
|
1508
|
+
{
|
|
1509
|
+
source: resumeExecution.approvalExecutionScope,
|
|
1510
|
+
target: approvalExecutionScope,
|
|
1511
|
+
}
|
|
1458
1512
|
);
|
|
1459
1513
|
let previousApprovals: ToolApprovalReplaySnapshot[] = [];
|
|
1460
1514
|
let approvalsMutated = false;
|
|
@@ -1765,14 +1819,20 @@ export class SubagentExecutor {
|
|
|
1765
1819
|
}
|
|
1766
1820
|
/** Repeated unconsumed forks must persist their current owner. */
|
|
1767
1821
|
const reboundValue =
|
|
1768
|
-
channel === INTERRUPT &&
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1822
|
+
channel === INTERRUPT &&
|
|
1823
|
+
approvalScope != null &&
|
|
1824
|
+
value != null &&
|
|
1825
|
+
typeof value === 'object' &&
|
|
1826
|
+
'value' in value
|
|
1827
|
+
? {
|
|
1828
|
+
...value,
|
|
1829
|
+
value: rebindToolBatchReplayPayload(
|
|
1830
|
+
value.value,
|
|
1831
|
+
approvalScope.source,
|
|
1832
|
+
approvalScope.target,
|
|
1833
|
+
targetThreadId
|
|
1834
|
+
),
|
|
1835
|
+
}
|
|
1776
1836
|
: value;
|
|
1777
1837
|
writes.push([channel, reboundValue]);
|
|
1778
1838
|
}
|
|
@@ -2117,6 +2177,9 @@ export class SubagentExecutor {
|
|
|
2117
2177
|
) {
|
|
2118
2178
|
return;
|
|
2119
2179
|
}
|
|
2180
|
+
if (settled.output.status === 'error' && config.signal?.aborted === true) {
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2120
2183
|
const parentConfigurable = config.configurable as
|
|
2121
2184
|
| Record<string, unknown>
|
|
2122
2185
|
| undefined;
|
|
@@ -2126,6 +2189,9 @@ export class SubagentExecutor {
|
|
|
2126
2189
|
parentToolCallId,
|
|
2127
2190
|
parentConfigurable,
|
|
2128
2191
|
});
|
|
2192
|
+
if (execution.completedResult != null && settled.output.status === 'error') {
|
|
2193
|
+
return;
|
|
2194
|
+
}
|
|
2129
2195
|
const { resumeExecution } = execution;
|
|
2130
2196
|
const resolvedSubagentType = getSubagentTypeFromArgs(settled.resolvedArgs);
|
|
2131
2197
|
const resolvedDescription = getSubagentDescriptionFromArgs(
|
|
@@ -2386,11 +2452,6 @@ export class SubagentExecutor {
|
|
|
2386
2452
|
if (!bound) {
|
|
2387
2453
|
return createSubagentFailure(SUBAGENT_CONFIG_CHANGED_MESSAGE);
|
|
2388
2454
|
}
|
|
2389
|
-
const completedChildResult = execution.completedResult;
|
|
2390
|
-
if (completedChildResult != null) {
|
|
2391
|
-
return completedChildResult;
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
2455
|
let config: ResolvedSubagentConfigEntry;
|
|
2395
2456
|
try {
|
|
2396
2457
|
config = await this.resolveExecutionConfig(executableConfig, execution, {
|
|
@@ -2450,6 +2511,63 @@ export class SubagentExecutor {
|
|
|
2450
2511
|
},
|
|
2451
2512
|
],
|
|
2452
2513
|
};
|
|
2514
|
+
const hostContextInput: SubagentContextInput = {
|
|
2515
|
+
executionContext: childExecutionContext,
|
|
2516
|
+
parentThreadId: threadId,
|
|
2517
|
+
memberAgentIds: childPlan.agents.map((agent) => agent.agentId),
|
|
2518
|
+
signal: childSignal,
|
|
2519
|
+
resumed: execution.started || resumeExecution != null,
|
|
2520
|
+
};
|
|
2521
|
+
let preparedContext: PreparedSubagentContext | undefined;
|
|
2522
|
+
try {
|
|
2523
|
+
preparedContext =
|
|
2524
|
+
this.subagentContext?.prepare == null
|
|
2525
|
+
? undefined
|
|
2526
|
+
: await awaitWithAbort(
|
|
2527
|
+
Promise.resolve(this.subagentContext.prepare(hostContextInput)),
|
|
2528
|
+
childSignal
|
|
2529
|
+
);
|
|
2530
|
+
execution.assertUsable(childSignal);
|
|
2531
|
+
for (const [agentId, sessions] of Object.entries(
|
|
2532
|
+
preparedContext?.agentSessions ?? {}
|
|
2533
|
+
)) {
|
|
2534
|
+
const member = childPlan.memberInputs.get(agentId);
|
|
2535
|
+
if (member == null) throw new Error('Unknown subagent context member.');
|
|
2536
|
+
const activeMember =
|
|
2537
|
+
execution.activeRun?.graph.agentContexts.get(agentId);
|
|
2538
|
+
if (
|
|
2539
|
+
activeMember != null &&
|
|
2540
|
+
activeMember.codeSessionKey !== sessions.codeSessionKey
|
|
2541
|
+
) {
|
|
2542
|
+
throw new Error(
|
|
2543
|
+
'Subagent session partition changed during execution.'
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
member.codeSessionKey = sessions.codeSessionKey;
|
|
2547
|
+
member.initialSessions = sessions.initialSessions;
|
|
2548
|
+
}
|
|
2549
|
+
} catch (error) {
|
|
2550
|
+
if (childSignal.aborted) {
|
|
2551
|
+
throw childSignal.reason instanceof Error
|
|
2552
|
+
? childSignal.reason
|
|
2553
|
+
: error;
|
|
2554
|
+
}
|
|
2555
|
+
if (execution.completedResult != null) {
|
|
2556
|
+
return {
|
|
2557
|
+
...createSubagentFailure(
|
|
2558
|
+
'Subagent context is unavailable or access was denied.'
|
|
2559
|
+
),
|
|
2560
|
+
retryableDelivery: true,
|
|
2561
|
+
};
|
|
2562
|
+
}
|
|
2563
|
+
return createSubagentFailure(
|
|
2564
|
+
'Subagent context is unavailable or access was denied.'
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
const completedChildResult = execution.completedResult;
|
|
2568
|
+
if (completedChildResult != null) {
|
|
2569
|
+
return this.completeHostContext(hostContextInput, completedChildResult);
|
|
2570
|
+
}
|
|
2453
2571
|
const maxTurns = config.maxTurns ?? DEFAULT_SUBAGENT_MAX_TURNS;
|
|
2454
2572
|
const memberRecursionLimit = maxTurns * SUBAGENT_RECURSION_MULTIPLIER;
|
|
2455
2573
|
const recursionLimit =
|
|
@@ -2476,6 +2594,7 @@ export class SubagentExecutor {
|
|
|
2476
2594
|
streamLimits: this.streamLimits,
|
|
2477
2595
|
subagentScope: true,
|
|
2478
2596
|
subagentExecutionContext: childExecutionContext,
|
|
2597
|
+
subagentContext: this.subagentContext,
|
|
2479
2598
|
...(resumeExecution?.graphState.fadingTier == null
|
|
2480
2599
|
? {}
|
|
2481
2600
|
: { fadingTier: resumeExecution.graphState.fadingTier }),
|
|
@@ -2522,9 +2641,7 @@ export class SubagentExecutor {
|
|
|
2522
2641
|
if (params.taskRuntime != null) {
|
|
2523
2642
|
childGraph.hookRegistry = this.hookRegistry;
|
|
2524
2643
|
}
|
|
2525
|
-
|
|
2526
|
-
seedChildGraphSessions(childGraph, childPlan.agents);
|
|
2527
|
-
}
|
|
2644
|
+
seedChildGraphSessions(childGraph, childPlan.agents);
|
|
2528
2645
|
let forwarding: ForwarderCallback | undefined;
|
|
2529
2646
|
if (forwardingEnabled) {
|
|
2530
2647
|
forwarding = this.createForwarderCallback({
|
|
@@ -2626,6 +2743,8 @@ export class SubagentExecutor {
|
|
|
2626
2743
|
}
|
|
2627
2744
|
const childConfigurable: Record<string, unknown> = {
|
|
2628
2745
|
...inheritedConfigurable,
|
|
2746
|
+
...sanitizePreparedConfigurable(preparedContext?.configurable),
|
|
2747
|
+
executionContext: childExecutionContext,
|
|
2629
2748
|
};
|
|
2630
2749
|
if (this.humanInTheLoop?.enabled === true) {
|
|
2631
2750
|
childConfigurable[TOOL_APPROVAL_EXECUTION_SCOPE_CONFIG_KEY] =
|
|
@@ -2666,16 +2785,18 @@ export class SubagentExecutor {
|
|
|
2666
2785
|
}
|
|
2667
2786
|
const persistedInterrupts = getPersistedInterrupts(persistedState);
|
|
2668
2787
|
if (persistedInterrupts.length > 0) {
|
|
2669
|
-
activeChildRun.pendingInterrupts =
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
pending
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2788
|
+
activeChildRun.pendingInterrupts =
|
|
2789
|
+
resumeExecution == null
|
|
2790
|
+
? persistedInterrupts
|
|
2791
|
+
: persistedInterrupts.map((pending) => ({
|
|
2792
|
+
...pending,
|
|
2793
|
+
value: rebindToolBatchReplayPayload(
|
|
2794
|
+
pending.value,
|
|
2795
|
+
resumeExecution.approvalExecutionScope,
|
|
2796
|
+
approvalExecutionScope,
|
|
2797
|
+
childThreadId
|
|
2798
|
+
),
|
|
2799
|
+
}));
|
|
2679
2800
|
execution.markStarted();
|
|
2680
2801
|
childAlreadyStarted = true;
|
|
2681
2802
|
} else if (persistedState.next.length > 0) {
|
|
@@ -2710,9 +2831,12 @@ export class SubagentExecutor {
|
|
|
2710
2831
|
}
|
|
2711
2832
|
let childInput: BaseGraphState | Command | null;
|
|
2712
2833
|
if (childResumeMap != null) {
|
|
2713
|
-
const pending =
|
|
2714
|
-
|
|
2715
|
-
|
|
2834
|
+
const pending =
|
|
2835
|
+
activeChildRun.pendingInterrupts.find(
|
|
2836
|
+
(entry) =>
|
|
2837
|
+
entry.id != null &&
|
|
2838
|
+
Object.prototype.hasOwnProperty.call(childResumeMap, entry.id)
|
|
2839
|
+
) ?? activeChildRun.pendingInterrupts[0];
|
|
2716
2840
|
restoreToolReplayConfig(childConfigurable, pending.id, pending.value);
|
|
2717
2841
|
rebindToolBatchReplayScope(
|
|
2718
2842
|
childConfigurable,
|
|
@@ -2734,6 +2858,7 @@ export class SubagentExecutor {
|
|
|
2734
2858
|
[SUBAGENT_RUN_ID_KEY]: childRunId,
|
|
2735
2859
|
},
|
|
2736
2860
|
}),
|
|
2861
|
+
...(preparedContext?.messages ?? []),
|
|
2737
2862
|
],
|
|
2738
2863
|
};
|
|
2739
2864
|
}
|
|
@@ -2749,6 +2874,7 @@ export class SubagentExecutor {
|
|
|
2749
2874
|
registry: this.hookRegistry,
|
|
2750
2875
|
input: {
|
|
2751
2876
|
hook_event_name: 'SubagentStart',
|
|
2877
|
+
executionContext: childExecutionContext,
|
|
2752
2878
|
runId: currentHookSessionId,
|
|
2753
2879
|
threadId,
|
|
2754
2880
|
parentAgentId: this.parentAgentId,
|
|
@@ -2955,6 +3081,7 @@ export class SubagentExecutor {
|
|
|
2955
3081
|
registry: this.hookRegistry,
|
|
2956
3082
|
input: {
|
|
2957
3083
|
hook_event_name: 'SubagentStop',
|
|
3084
|
+
executionContext: childExecutionContext,
|
|
2958
3085
|
runId: currentHookSessionId,
|
|
2959
3086
|
threadId,
|
|
2960
3087
|
agentId: childAgentId,
|
|
@@ -2997,12 +3124,33 @@ export class SubagentExecutor {
|
|
|
2997
3124
|
|
|
2998
3125
|
this.clearChildGraph(childGraph);
|
|
2999
3126
|
|
|
3000
|
-
const completedResult = {
|
|
3127
|
+
const completedResult: SubagentExecuteResult = {
|
|
3001
3128
|
content: filteredContent,
|
|
3002
3129
|
messages: result.messages,
|
|
3003
3130
|
};
|
|
3004
3131
|
execution.markCompleted(completedResult);
|
|
3005
|
-
return completedResult;
|
|
3132
|
+
return this.completeHostContext(hostContextInput, completedResult);
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
private async completeHostContext(
|
|
3136
|
+
input: SubagentContextInput,
|
|
3137
|
+
result: SubagentExecuteResult
|
|
3138
|
+
): Promise<SubagentExecuteResult> {
|
|
3139
|
+
if (this.subagentContext?.complete == null) return result;
|
|
3140
|
+
try {
|
|
3141
|
+
input.signal.throwIfAborted();
|
|
3142
|
+
const completed = await awaitWithAbort(
|
|
3143
|
+
this.subagentContext.complete(input, result),
|
|
3144
|
+
input.signal
|
|
3145
|
+
);
|
|
3146
|
+
input.signal.throwIfAborted();
|
|
3147
|
+
return { ...result, content: completed.content };
|
|
3148
|
+
} catch {
|
|
3149
|
+
return {
|
|
3150
|
+
...createSubagentFailure('Subagent result delivery failed.'),
|
|
3151
|
+
retryableDelivery: true,
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3006
3154
|
}
|
|
3007
3155
|
|
|
3008
3156
|
/**
|
|
@@ -3535,6 +3683,17 @@ function sanitizeChildConfigurable(
|
|
|
3535
3683
|
);
|
|
3536
3684
|
}
|
|
3537
3685
|
|
|
3686
|
+
function sanitizePreparedConfigurable(
|
|
3687
|
+
configurable: RunnableConfig['configurable']
|
|
3688
|
+
): Record<string, unknown> {
|
|
3689
|
+
const prepared = sanitizeChildConfigurable(configurable);
|
|
3690
|
+
delete prepared.run_id;
|
|
3691
|
+
delete prepared.parent_run_id;
|
|
3692
|
+
delete prepared.thread_id;
|
|
3693
|
+
delete prepared.executionContext;
|
|
3694
|
+
return prepared;
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3538
3697
|
function isLangGraphRuntimeConfigKey(key: string): boolean {
|
|
3539
3698
|
return (
|
|
3540
3699
|
key.startsWith(LANGGRAPH_RUNTIME_CONFIG_PREFIX) ||
|
|
@@ -32,6 +32,8 @@ export interface SettledToolBatchResult {
|
|
|
32
32
|
output: BaseMessage | Command;
|
|
33
33
|
additionalContexts: string[];
|
|
34
34
|
resolvedArgs?: Record<string, unknown>;
|
|
35
|
+
/** Code-session identities injected into this completed direct call. */
|
|
36
|
+
codeSessionBaseline?: Array<[string, string]>;
|
|
35
37
|
completionHandled?: boolean;
|
|
36
38
|
referenceContent?: string;
|
|
37
39
|
turn?: number;
|
|
@@ -474,6 +476,14 @@ export async function restoreToolBatchReplayState(
|
|
|
474
476
|
throw new Error('Invalid settled tool batch results');
|
|
475
477
|
}
|
|
476
478
|
const result = entry[1] as Partial<SettledToolBatchResult> | null;
|
|
479
|
+
const codeSessionBaseline: unknown = (
|
|
480
|
+
result as { codeSessionBaseline?: unknown } | null
|
|
481
|
+
)?.codeSessionBaseline;
|
|
482
|
+
const baselineNames = Array.isArray(codeSessionBaseline)
|
|
483
|
+
? codeSessionBaseline.map((pair) =>
|
|
484
|
+
Array.isArray(pair) ? pair[0] : undefined
|
|
485
|
+
)
|
|
486
|
+
: [];
|
|
477
487
|
if (
|
|
478
488
|
result == null ||
|
|
479
489
|
(!isBaseMessage(result.output) && !isCommand(result.output)) ||
|
|
@@ -491,7 +501,19 @@ export async function restoreToolBatchReplayState(
|
|
|
491
501
|
typeof result.proposal.name !== 'string' ||
|
|
492
502
|
result.proposal.name.length === 0 ||
|
|
493
503
|
!isRecord(result.proposal.args) ||
|
|
494
|
-
(result.resolvedArgs != null && !isRecord(result.resolvedArgs))
|
|
504
|
+
(result.resolvedArgs != null && !isRecord(result.resolvedArgs)) ||
|
|
505
|
+
(codeSessionBaseline != null &&
|
|
506
|
+
(!Array.isArray(codeSessionBaseline) ||
|
|
507
|
+
codeSessionBaseline.some(
|
|
508
|
+
(pair) =>
|
|
509
|
+
!Array.isArray(pair) ||
|
|
510
|
+
pair.length !== 2 ||
|
|
511
|
+
typeof pair[0] !== 'string' ||
|
|
512
|
+
pair[0].length === 0 ||
|
|
513
|
+
typeof pair[1] !== 'string' ||
|
|
514
|
+
pair[1].length === 0
|
|
515
|
+
) ||
|
|
516
|
+
new Set(baselineNames).size !== baselineNames.length))
|
|
495
517
|
) {
|
|
496
518
|
throw new Error('Invalid settled tool batch results');
|
|
497
519
|
}
|
package/src/types/graph.ts
CHANGED
|
@@ -395,6 +395,8 @@ export type StandardGraphInput = {
|
|
|
395
395
|
* do not inherit it, keeping background nesting disabled for the MVP.
|
|
396
396
|
*/
|
|
397
397
|
subagentTasks?: SubagentTaskConfig;
|
|
398
|
+
/** Host-owned context and result projection for each isolated child execution. */
|
|
399
|
+
subagentContext?: SubagentContextAdapter;
|
|
398
400
|
/**
|
|
399
401
|
* True when this graph IS a subagent child run (set by `SubagentExecutor`
|
|
400
402
|
* when it constructs the child graph). Drives the hook-input `agentId`
|
|
@@ -669,6 +671,41 @@ export interface SubagentExecutionContext {
|
|
|
669
671
|
readonly ancestry: readonly SubagentAncestryEntry[];
|
|
670
672
|
}
|
|
671
673
|
|
|
674
|
+
/** Trusted identity supplied before a child can access host-owned resources. */
|
|
675
|
+
export interface SubagentContextInput {
|
|
676
|
+
executionContext: SubagentExecutionContext;
|
|
677
|
+
parentThreadId?: string;
|
|
678
|
+
memberAgentIds: readonly string[];
|
|
679
|
+
signal: AbortSignal;
|
|
680
|
+
resumed: boolean;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
export interface PreparedSubagentContext {
|
|
684
|
+
/** Added to the initial child input; checkpoint recovery does not add them again. */
|
|
685
|
+
messages?: BaseMessage[];
|
|
686
|
+
/** Host configuration; SDK execution and checkpoint identities remain authoritative. */
|
|
687
|
+
configurable?: RunnableConfig['configurable'];
|
|
688
|
+
/** Each entry replaces that member's inherited code partition and initial sessions. */
|
|
689
|
+
agentSessions?: Readonly<
|
|
690
|
+
Record<string, Pick<AgentInputs, 'codeSessionKey' | 'initialSessions'>>
|
|
691
|
+
>;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export interface SubagentContextResult {
|
|
695
|
+
content: string;
|
|
696
|
+
messages: BaseMessage[];
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export interface SubagentContextAdapter {
|
|
700
|
+
/** Reauthorizes reconstructed executions; durable work must be idempotent by child run ID. */
|
|
701
|
+
prepare(input: SubagentContextInput): Promise<PreparedSubagentContext>;
|
|
702
|
+
/** Projects durable references into the result returned to the parent. */
|
|
703
|
+
complete?(
|
|
704
|
+
input: SubagentContextInput,
|
|
705
|
+
result: SubagentContextResult
|
|
706
|
+
): Promise<Pick<SubagentContextResult, 'content'>>;
|
|
707
|
+
}
|
|
708
|
+
|
|
672
709
|
/**
|
|
673
710
|
* Wrapper event emitted when a subagent's child graph dispatches activity.
|
|
674
711
|
* Lets hosts show subagent progress in a UI surface separate from the parent
|
package/src/types/run.ts
CHANGED
|
@@ -291,6 +291,8 @@ export type RunConfig = {
|
|
|
291
291
|
* Omit to preserve foreground-only subagent behavior.
|
|
292
292
|
*/
|
|
293
293
|
subagentTasks?: SubagentTaskConfig;
|
|
294
|
+
/** Authorizes and supplies host-owned context to isolated child runs. */
|
|
295
|
+
subagentContext?: g.SubagentContextAdapter;
|
|
294
296
|
/**
|
|
295
297
|
* Pre-constructed hook registry for this run. Hooks fire at lifecycle
|
|
296
298
|
* points in `processStream` (RunStart, UserPromptSubmit, Stop,
|