@mongodb-js/agent-engine-sdk-langgraph 0.11.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/CHANGELOG.md +39 -0
- package/LICENSE.md +201 -0
- package/README.md +149 -0
- package/dist/agent.d.ts +53 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +508 -0
- package/dist/agent.js.map +1 -0
- package/dist/backends/tool_sandbox.d.ts +15 -0
- package/dist/backends/tool_sandbox.d.ts.map +1 -0
- package/dist/backends/tool_sandbox.js +15 -0
- package/dist/backends/tool_sandbox.js.map +1 -0
- package/dist/backends/toolpod.d.ts +68 -0
- package/dist/backends/toolpod.d.ts.map +1 -0
- package/dist/backends/toolpod.js +451 -0
- package/dist/backends/toolpod.js.map +1 -0
- package/dist/call_interrupt.d.ts +20 -0
- package/dist/call_interrupt.d.ts.map +1 -0
- package/dist/call_interrupt.js +23 -0
- package/dist/call_interrupt.js.map +1 -0
- package/dist/checkpoint_branch.d.ts +58 -0
- package/dist/checkpoint_branch.d.ts.map +1 -0
- package/dist/checkpoint_branch.js +239 -0
- package/dist/checkpoint_branch.js.map +1 -0
- package/dist/checkpointer.d.ts +21 -0
- package/dist/checkpointer.d.ts.map +1 -0
- package/dist/checkpointer.js +31 -0
- package/dist/checkpointer.js.map +1 -0
- package/dist/deep_agent.d.ts +49 -0
- package/dist/deep_agent.d.ts.map +1 -0
- package/dist/deep_agent.js +110 -0
- package/dist/deep_agent.js.map +1 -0
- package/dist/deep_agent_checkpointer.d.ts +11 -0
- package/dist/deep_agent_checkpointer.d.ts.map +1 -0
- package/dist/deep_agent_checkpointer.js +19 -0
- package/dist/deep_agent_checkpointer.js.map +1 -0
- package/dist/deep_agent_task.d.ts +26 -0
- package/dist/deep_agent_task.d.ts.map +1 -0
- package/dist/deep_agent_task.js +49 -0
- package/dist/deep_agent_task.js.map +1 -0
- package/dist/durable_deep_agent.d.ts +23 -0
- package/dist/durable_deep_agent.d.ts.map +1 -0
- package/dist/durable_deep_agent.js +176 -0
- package/dist/durable_deep_agent.js.map +1 -0
- package/dist/durable_message_identity.d.ts +5 -0
- package/dist/durable_message_identity.d.ts.map +1 -0
- package/dist/durable_message_identity.js +106 -0
- package/dist/durable_message_identity.js.map +1 -0
- package/dist/durable_session.d.ts +30 -0
- package/dist/durable_session.d.ts.map +1 -0
- package/dist/durable_session.js +400 -0
- package/dist/durable_session.js.map +1 -0
- package/dist/durable_subgraphs.d.ts +13 -0
- package/dist/durable_subgraphs.d.ts.map +1 -0
- package/dist/durable_subgraphs.js +82 -0
- package/dist/durable_subgraphs.js.map +1 -0
- package/dist/durable_tools.d.ts +12 -0
- package/dist/durable_tools.d.ts.map +1 -0
- package/dist/durable_tools.js +41 -0
- package/dist/durable_tools.js.map +1 -0
- package/dist/execution_session.d.ts +63 -0
- package/dist/execution_session.d.ts.map +1 -0
- package/dist/execution_session.js +300 -0
- package/dist/execution_session.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/llm_adapter.d.ts +41 -0
- package/dist/llm_adapter.d.ts.map +1 -0
- package/dist/llm_adapter.js +177 -0
- package/dist/llm_adapter.js.map +1 -0
- package/dist/messages.d.ts +56 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +592 -0
- package/dist/messages.js.map +1 -0
- package/dist/node_logger_adapter.d.ts +51 -0
- package/dist/node_logger_adapter.d.ts.map +1 -0
- package/dist/node_logger_adapter.js +163 -0
- package/dist/node_logger_adapter.js.map +1 -0
- package/dist/platform_checkpointer.d.ts +70 -0
- package/dist/platform_checkpointer.d.ts.map +1 -0
- package/dist/platform_checkpointer.js +252 -0
- package/dist/platform_checkpointer.js.map +1 -0
- package/dist/query.d.ts +103 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +623 -0
- package/dist/query.js.map +1 -0
- package/dist/runtime.d.ts +336 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +881 -0
- package/dist/runtime.js.map +1 -0
- package/dist/secure_llm.d.ts +93 -0
- package/dist/secure_llm.d.ts.map +1 -0
- package/dist/secure_llm.js +423 -0
- package/dist/secure_llm.js.map +1 -0
- package/dist/session_factory.d.ts +6 -0
- package/dist/session_factory.d.ts.map +1 -0
- package/dist/session_factory.js +29 -0
- package/dist/session_factory.js.map +1 -0
- package/dist/session_fork.d.ts +76 -0
- package/dist/session_fork.d.ts.map +1 -0
- package/dist/session_fork.js +428 -0
- package/dist/session_fork.js.map +1 -0
- package/dist/subagents.d.ts +37 -0
- package/dist/subagents.d.ts.map +1 -0
- package/dist/subagents.js +67 -0
- package/dist/subagents.js.map +1 -0
- package/dist/suspend.d.ts +27 -0
- package/dist/suspend.d.ts.map +1 -0
- package/dist/suspend.js +87 -0
- package/dist/suspend.js.map +1 -0
- package/dist/thread_id.d.ts +30 -0
- package/dist/thread_id.d.ts.map +1 -0
- package/dist/thread_id.js +69 -0
- package/dist/thread_id.js.map +1 -0
- package/dist/workflow_json.d.ts +11 -0
- package/dist/workflow_json.d.ts.map +1 -0
- package/dist/workflow_json.js +49 -0
- package/dist/workflow_json.js.map +1 -0
- package/dist/workflow_message.d.ts +11 -0
- package/dist/workflow_message.d.ts.map +1 -0
- package/dist/workflow_message.js +179 -0
- package/dist/workflow_message.js.map +1 -0
- package/dist/workflow_state.d.ts +7 -0
- package/dist/workflow_state.d.ts.map +1 -0
- package/dist/workflow_state.js +62 -0
- package/dist/workflow_state.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session fork. See `docs/session-fork.md`.
|
|
3
|
+
*
|
|
4
|
+
* Port of Python's `agent_engine_sdk_langgraph/session_fork.py`. LangGraph.js has no
|
|
5
|
+
* synchronous `update_state` and no `task_id` parameter, so only the async
|
|
6
|
+
* `updateState` surface is wrapped and branch keys omit the task component.
|
|
7
|
+
*/
|
|
8
|
+
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
9
|
+
import type { CompiledStateGraph } from "@langchain/langgraph";
|
|
10
|
+
import { currentAttemptContext } from "@mongodb-js/agent-engine-runner-shared";
|
|
11
|
+
import type { RequestContext } from "@mongodb-js/agent-engine-sdk";
|
|
12
|
+
import { type ResolveThreadIdHook } from "./thread_id.js";
|
|
13
|
+
/** Response for forking a session into a new independent session. */
|
|
14
|
+
export interface SessionForkResponse {
|
|
15
|
+
/** Identifier of the new branch session. */
|
|
16
|
+
sessionId: string;
|
|
17
|
+
/** Pending execution on the new branch session. */
|
|
18
|
+
executionId: string;
|
|
19
|
+
}
|
|
20
|
+
interface ForkableAgent {
|
|
21
|
+
compiledGraph: CompiledStateGraph<unknown, unknown>;
|
|
22
|
+
resolveThreadId?: ResolveThreadIdHook | null;
|
|
23
|
+
}
|
|
24
|
+
/** True once: dest should `invoke(null)`. See `docs/session-fork.md`. */
|
|
25
|
+
export declare function takeContinueWithoutUserMessage(threadId: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Create a branch session and copy the source checkpoint onto it.
|
|
28
|
+
*
|
|
29
|
+
* Port of Python's `fork_native_session`: the selected checkpoint and its
|
|
30
|
+
* replay plan are validated before CreateBranch, and the copy reuses this
|
|
31
|
+
* package's `copyCheckpoint` with that validated plan.
|
|
32
|
+
*/
|
|
33
|
+
export declare function forkNativeSession(graph: CompiledStateGraph<unknown, unknown>, args: {
|
|
34
|
+
ctx: RequestContext;
|
|
35
|
+
historyId: string | null;
|
|
36
|
+
resolveThreadId?: ResolveThreadIdHook | null;
|
|
37
|
+
state?: unknown;
|
|
38
|
+
asNode?: string | null;
|
|
39
|
+
}): Promise<[SessionForkResponse, RunnableConfig]>;
|
|
40
|
+
/**
|
|
41
|
+
* Create an OE-owned branch from a selected committed scratch checkpoint.
|
|
42
|
+
*
|
|
43
|
+
* Port of Python's `_fork_durable_session`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function forkDurableSession(graph: CompiledStateGraph<unknown, unknown>, args: {
|
|
46
|
+
context: NonNullable<ReturnType<typeof currentAttemptContext>>;
|
|
47
|
+
config: RunnableConfig;
|
|
48
|
+
resolveThreadId?: ResolveThreadIdHook | null;
|
|
49
|
+
}): Promise<[SessionForkResponse, RunnableConfig]>;
|
|
50
|
+
/** Reject patches until OE can record one as a branch-local transition. */
|
|
51
|
+
export declare function requireExactDurableBranch(state: unknown): void;
|
|
52
|
+
/**
|
|
53
|
+
* Route live `updateState` through the persistence-specific session fork.
|
|
54
|
+
*
|
|
55
|
+
* See `docs/session-fork.md`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function wrapSessionForkUpdateState(graph: CompiledStateGraph<unknown, unknown>, args: {
|
|
58
|
+
resolveThreadId: ResolveThreadIdHook | null;
|
|
59
|
+
}): void;
|
|
60
|
+
/** AER write plugin that forks a LangGraph session. */
|
|
61
|
+
export declare class LangGraphForkPlugin {
|
|
62
|
+
private readonly getAgent;
|
|
63
|
+
private readonly workspaceIdResolver;
|
|
64
|
+
constructor(args: {
|
|
65
|
+
getAgent: () => ForkableAgent;
|
|
66
|
+
workspaceIdResolver: () => string;
|
|
67
|
+
});
|
|
68
|
+
forkSession(args: {
|
|
69
|
+
sessionId: string;
|
|
70
|
+
executionId: string;
|
|
71
|
+
historyId: string | null;
|
|
72
|
+
state?: unknown;
|
|
73
|
+
}): Promise<SessionForkResponse>;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
|
76
|
+
//# sourceMappingURL=session_fork.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session_fork.d.ts","sourceRoot":"","sources":["../src/session_fork.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EAUtB,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAWnE,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG9E,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,aAAa;IACrB,aAAa,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC9C;AAQD,yEAAyE;AACzE,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIxE;AA8BD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,EAC3C,IAAI,EAAE;IACJ,GAAG,EAAE,cAAc,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GACA,OAAO,CAAC,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAuFhD;AA8BD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,EAC3C,IAAI,EAAE;IACJ,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC;IAC/D,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC9C,GACA,OAAO,CAAC,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC,CA4DhD;AAYD,2EAA2E;AAC3E,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAM9D;AA4BD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,EAC3C,IAAI,EAAE;IAAE,eAAe,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAE,GACpD,IAAI,CA6DN;AAED,uDAAuD;AACvD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAe;gBAEvC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,aAAa,CAAC;QAC9B,mBAAmB,EAAE,MAAM,MAAM,CAAC;KACnC;IAKK,WAAW,CAAC,IAAI,EAAE;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAoDjC"}
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session fork. See `docs/session-fork.md`.
|
|
3
|
+
*
|
|
4
|
+
* Port of Python's `agent_engine_sdk_langgraph/session_fork.py`. LangGraph.js has no
|
|
5
|
+
* synchronous `update_state` and no `task_id` parameter, so only the async
|
|
6
|
+
* `updateState` surface is wrapped and branch keys omit the task component.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { currentAttemptContext, encodeProtoJson, fetchPlatform, getFetchOptionsWithTLS, getCurrentOeUrl, quotePathSegment, resolveOeUrl, StateSnapshotSchema, } from "@mongodb-js/agent-engine-runner-shared";
|
|
10
|
+
import { checkpointReplayPlan, completedRootCheckpoint, copyCheckpoint, } from "./checkpoint_branch.js";
|
|
11
|
+
import { OE_STEP_ORDINAL_METADATA_KEY, PlatformCheckpointer, } from "./platform_checkpointer.js";
|
|
12
|
+
import { checkpointThreadId } from "./thread_id.js";
|
|
13
|
+
import { channelValuesToStateSnapshot } from "./workflow_state.js";
|
|
14
|
+
const CREATE_BRANCH_TIMEOUT_MS = 15_000;
|
|
15
|
+
// Dest continue is process-local. Bound so unused dests cannot accumulate;
|
|
16
|
+
// an evicted mark behaves like a dest execution that starts in another process.
|
|
17
|
+
const CONTINUE_MARK_LIMIT = 256;
|
|
18
|
+
const CONTINUE_WITHOUT_USER_MESSAGE = new Map();
|
|
19
|
+
/** True once: dest should `invoke(null)`. See `docs/session-fork.md`. */
|
|
20
|
+
export function takeContinueWithoutUserMessage(threadId) {
|
|
21
|
+
if (!CONTINUE_WITHOUT_USER_MESSAGE.has(threadId))
|
|
22
|
+
return false;
|
|
23
|
+
CONTINUE_WITHOUT_USER_MESSAGE.delete(threadId);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
function armContinueWithoutUserMessage(threadId) {
|
|
27
|
+
if (CONTINUE_WITHOUT_USER_MESSAGE.has(threadId)) {
|
|
28
|
+
CONTINUE_WITHOUT_USER_MESSAGE.delete(threadId);
|
|
29
|
+
}
|
|
30
|
+
else if (CONTINUE_WITHOUT_USER_MESSAGE.size >= CONTINUE_MARK_LIMIT) {
|
|
31
|
+
const oldest = CONTINUE_WITHOUT_USER_MESSAGE.keys().next();
|
|
32
|
+
if (!oldest.done)
|
|
33
|
+
CONTINUE_WITHOUT_USER_MESSAGE.delete(oldest.value);
|
|
34
|
+
}
|
|
35
|
+
CONTINUE_WITHOUT_USER_MESSAGE.set(threadId, null);
|
|
36
|
+
}
|
|
37
|
+
function requireNonEmpty(value, what) {
|
|
38
|
+
if (!value || !value.trim()) {
|
|
39
|
+
throw new Error(`${what} is required to fork a session`);
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function isEmptyValues(state) {
|
|
44
|
+
return (state === null ||
|
|
45
|
+
state === undefined ||
|
|
46
|
+
(typeof state === "object" && Object.keys(state).length === 0));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create a branch session and copy the source checkpoint onto it.
|
|
50
|
+
*
|
|
51
|
+
* Port of Python's `fork_native_session`: the selected checkpoint and its
|
|
52
|
+
* replay plan are validated before CreateBranch, and the copy reuses this
|
|
53
|
+
* package's `copyCheckpoint` with that validated plan.
|
|
54
|
+
*/
|
|
55
|
+
export async function forkNativeSession(graph, args) {
|
|
56
|
+
if (currentAttemptContext() !== null) {
|
|
57
|
+
throw new Error("session fork is not supported on durable_workflow sessions");
|
|
58
|
+
}
|
|
59
|
+
const { ctx } = args;
|
|
60
|
+
const sessionId = requireNonEmpty(ctx.sessionId, "session identity");
|
|
61
|
+
const workspaceId = requireNonEmpty(ctx.workspaceId, "workspace identity");
|
|
62
|
+
const executionId = requireNonEmpty(ctx.executionId, "execution identity");
|
|
63
|
+
const source = await completedRootCheckpoint(graph, {
|
|
64
|
+
threadId: checkpointThreadId(ctx, args.resolveThreadId),
|
|
65
|
+
historyId: args.historyId,
|
|
66
|
+
});
|
|
67
|
+
const plan = await checkpointReplayPlan(graph, source);
|
|
68
|
+
const hasPatch = !isEmptyValues(args.state);
|
|
69
|
+
// Resolve and validate the patch node before CreateBranch: LangGraph would
|
|
70
|
+
// only reject an unknown or ambiguous target after the branch and copy
|
|
71
|
+
// already exist.
|
|
72
|
+
const patchNode = hasPatch ? (args.asNode ?? singleNodeName(graph)) : null;
|
|
73
|
+
if (hasPatch &&
|
|
74
|
+
args.asNode !== null &&
|
|
75
|
+
args.asNode !== undefined &&
|
|
76
|
+
!graphNodeNames(graph).includes(args.asNode)) {
|
|
77
|
+
throw new Error(`session fork state patch node "${args.asNode}" is not a node in this graph`);
|
|
78
|
+
}
|
|
79
|
+
if (hasPatch && patchNode === null) {
|
|
80
|
+
throw new Error("session fork state patch requires a destination node: " +
|
|
81
|
+
"pass asNode or fork a single-node graph");
|
|
82
|
+
}
|
|
83
|
+
const branch = await createNativeBranch({
|
|
84
|
+
orgId: tenantEnvId("ORG_ID"),
|
|
85
|
+
projectId: tenantEnvId("PROJECT_ID"),
|
|
86
|
+
workspaceId,
|
|
87
|
+
sessionId,
|
|
88
|
+
executionId,
|
|
89
|
+
branchKey: branchKey(source.checkpointId, args.state, args.asNode ?? null, null),
|
|
90
|
+
checkpointId: source.checkpointId,
|
|
91
|
+
});
|
|
92
|
+
const destThreadId = checkpointThreadId({
|
|
93
|
+
sessionId: branch.sessionId,
|
|
94
|
+
workspaceId,
|
|
95
|
+
executionId: branch.executionId,
|
|
96
|
+
}, args.resolveThreadId);
|
|
97
|
+
const destConfig = {
|
|
98
|
+
configurable: { thread_id: destThreadId, checkpoint_ns: "" },
|
|
99
|
+
};
|
|
100
|
+
// Python `fork_native_session` parity: copy onto the empty destination,
|
|
101
|
+
// then apply the optional patch. A populated destination (a repeated fork
|
|
102
|
+
// for the same branch key, or a destination left behind by a failed
|
|
103
|
+
// attempt) is sealed by `copyCheckpoint`'s empty-destination guard instead
|
|
104
|
+
// of being repaired, verified, or silently reused.
|
|
105
|
+
await copyCheckpoint(graph, destConfig, source, plan);
|
|
106
|
+
if (patchNode !== null) {
|
|
107
|
+
await graph.updateState(destConfig, args.state, patchNode);
|
|
108
|
+
}
|
|
109
|
+
const destCheckpointId = await latestCheckpointId(graph, destThreadId);
|
|
110
|
+
const finalConfig = {
|
|
111
|
+
...destConfig,
|
|
112
|
+
configurable: {
|
|
113
|
+
...destConfig.configurable,
|
|
114
|
+
checkpoint_id: destCheckpointId,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
armContinueWithoutUserMessage(destThreadId);
|
|
118
|
+
return [branch, finalConfig];
|
|
119
|
+
}
|
|
120
|
+
async function latestCheckpointId(graph, threadId) {
|
|
121
|
+
const snapshot = await graph.getState({
|
|
122
|
+
configurable: { thread_id: threadId },
|
|
123
|
+
});
|
|
124
|
+
const checkpointId = snapshot.config.configurable?.["checkpoint_id"];
|
|
125
|
+
if (typeof checkpointId !== "string" || checkpointId === "") {
|
|
126
|
+
throw new Error("LangGraph branch point was not found");
|
|
127
|
+
}
|
|
128
|
+
return checkpointId;
|
|
129
|
+
}
|
|
130
|
+
/** Root-loop node names a state patch may target. */
|
|
131
|
+
function graphNodeNames(graph) {
|
|
132
|
+
return Object.keys(graph.nodes ?? {}).filter((name) => !name.startsWith("__"));
|
|
133
|
+
}
|
|
134
|
+
function singleNodeName(graph) {
|
|
135
|
+
const names = graphNodeNames(graph);
|
|
136
|
+
return names.length === 1 ? (names[0] ?? null) : null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Create an OE-owned branch from a selected committed scratch checkpoint.
|
|
140
|
+
*
|
|
141
|
+
* Port of Python's `_fork_durable_session`.
|
|
142
|
+
*/
|
|
143
|
+
export async function forkDurableSession(graph, args) {
|
|
144
|
+
const { context } = args;
|
|
145
|
+
const identity = context.workflowIdentity;
|
|
146
|
+
const scope = identity?.tenantScope;
|
|
147
|
+
if (!identity ||
|
|
148
|
+
!scope ||
|
|
149
|
+
!identity.sessionId ||
|
|
150
|
+
!identity.executionId ||
|
|
151
|
+
!scope.orgId ||
|
|
152
|
+
!scope.projectId ||
|
|
153
|
+
!scope.workspaceId) {
|
|
154
|
+
throw new Error("durable session fork requires complete OE attempt identity");
|
|
155
|
+
}
|
|
156
|
+
const checkpointer = graph.checkpointer;
|
|
157
|
+
if (!(checkpointer instanceof PlatformCheckpointer)) {
|
|
158
|
+
throw new Error("durable session fork requires the platform checkpointer");
|
|
159
|
+
}
|
|
160
|
+
const source = await checkpointer.getTuple(args.config);
|
|
161
|
+
if (source === undefined) {
|
|
162
|
+
throw new Error("durable branch point is not a committed root step");
|
|
163
|
+
}
|
|
164
|
+
const stepOrdinal = oeStepOrdinal(source.metadata);
|
|
165
|
+
// Materialized state adds unwritten reducer defaults absent from the OE hash.
|
|
166
|
+
const sourceState = channelValuesToStateSnapshot((source.checkpoint.channel_values ?? {}), context.replayMode);
|
|
167
|
+
const branchSource = `${identity.executionId}/step/${stepOrdinal}`;
|
|
168
|
+
const branch = await createDurableBranch({
|
|
169
|
+
orgId: scope.orgId,
|
|
170
|
+
projectId: scope.projectId,
|
|
171
|
+
workspaceId: scope.workspaceId,
|
|
172
|
+
sessionId: identity.sessionId,
|
|
173
|
+
executionId: identity.executionId,
|
|
174
|
+
branchKey: branchKey(branchSource, null, null, null),
|
|
175
|
+
stepOrdinal,
|
|
176
|
+
state: sourceState,
|
|
177
|
+
});
|
|
178
|
+
// RequestContext is request-local. Use a minimal value only to resolve the
|
|
179
|
+
// destination thread; the future branch invocation receives its own context.
|
|
180
|
+
const destConfig = {
|
|
181
|
+
configurable: {
|
|
182
|
+
thread_id: checkpointThreadId({
|
|
183
|
+
sessionId: branch.sessionId,
|
|
184
|
+
workspaceId: scope.workspaceId,
|
|
185
|
+
executionId: branch.executionId,
|
|
186
|
+
}, args.resolveThreadId),
|
|
187
|
+
checkpoint_ns: "",
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
return [branch, destConfig];
|
|
191
|
+
}
|
|
192
|
+
/** Read the absolute OE ordinal recorded with a committed scratch step. */
|
|
193
|
+
function oeStepOrdinal(metadata) {
|
|
194
|
+
const values = (metadata ?? {});
|
|
195
|
+
const stepOrdinal = values[OE_STEP_ORDINAL_METADATA_KEY];
|
|
196
|
+
if (stepOrdinal === undefined || stepOrdinal === null) {
|
|
197
|
+
throw new Error("durable branch point is not a committed root step");
|
|
198
|
+
}
|
|
199
|
+
return Number(stepOrdinal);
|
|
200
|
+
}
|
|
201
|
+
/** Reject patches until OE can record one as a branch-local transition. */
|
|
202
|
+
export function requireExactDurableBranch(state) {
|
|
203
|
+
if (!isEmptyValues(state)) {
|
|
204
|
+
throw new Error("durable_workflow session fork does not support an updateState patch");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function liveSource(config, snapshotConfig, resolveThreadId) {
|
|
208
|
+
if (currentAttemptContext() !== null)
|
|
209
|
+
return null;
|
|
210
|
+
const checkpointId = snapshotConfig.configurable?.["checkpoint_id"];
|
|
211
|
+
if (typeof checkpointId !== "string" || checkpointId === "")
|
|
212
|
+
return null;
|
|
213
|
+
const ctx = config.configurable?.["request_context"];
|
|
214
|
+
if (ctx === undefined || ctx === null)
|
|
215
|
+
return null;
|
|
216
|
+
if (!ctx.sessionId || !ctx.workspaceId || !ctx.executionId)
|
|
217
|
+
return null;
|
|
218
|
+
const threadId = config.configurable?.["thread_id"];
|
|
219
|
+
if (threadId !== checkpointThreadId(ctx, resolveThreadId))
|
|
220
|
+
return null;
|
|
221
|
+
return ctx;
|
|
222
|
+
}
|
|
223
|
+
function tenantEnvId(name) {
|
|
224
|
+
const value = (process.env[name] ?? "").trim();
|
|
225
|
+
if (!value) {
|
|
226
|
+
throw new Error(`${name} is required to fork a session`);
|
|
227
|
+
}
|
|
228
|
+
return value;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Route live `updateState` through the persistence-specific session fork.
|
|
232
|
+
*
|
|
233
|
+
* See `docs/session-fork.md`.
|
|
234
|
+
*/
|
|
235
|
+
export function wrapSessionForkUpdateState(graph, args) {
|
|
236
|
+
// Python wraps only when the graph exposes the async update surface; graph
|
|
237
|
+
// test doubles may omit it entirely.
|
|
238
|
+
const originalUpdate = graph.updateState;
|
|
239
|
+
if (typeof originalUpdate !== "function")
|
|
240
|
+
return;
|
|
241
|
+
const original = originalUpdate.bind(graph);
|
|
242
|
+
const originalGetState = graph.getState.bind(graph);
|
|
243
|
+
graph.updateState = async (config, values, asNode) => {
|
|
244
|
+
const attempt = currentAttemptContext();
|
|
245
|
+
if (attempt !== null) {
|
|
246
|
+
if (args.resolveThreadId !== null) {
|
|
247
|
+
throw new Error("session fork requires the default thread_id formula; " +
|
|
248
|
+
"custom App.resolveThreadId is not supported on graph.updateState");
|
|
249
|
+
}
|
|
250
|
+
// CreateBranch hash-validates the selected committed snapshot. A
|
|
251
|
+
// state patch needs a separate branch-local transition contract.
|
|
252
|
+
requireExactDurableBranch(values);
|
|
253
|
+
const [, destConfig] = await forkDurableSession(graph, {
|
|
254
|
+
context: attempt,
|
|
255
|
+
config,
|
|
256
|
+
resolveThreadId: args.resolveThreadId,
|
|
257
|
+
});
|
|
258
|
+
return destConfig;
|
|
259
|
+
}
|
|
260
|
+
const snapshot = await originalGetState(config);
|
|
261
|
+
const ctx = liveSource(config, snapshot.config, args.resolveThreadId);
|
|
262
|
+
if (ctx !== null) {
|
|
263
|
+
if (args.resolveThreadId !== null) {
|
|
264
|
+
throw new Error("session fork requires the default thread_id formula; " +
|
|
265
|
+
"custom App.resolveThreadId is not supported on graph.updateState");
|
|
266
|
+
}
|
|
267
|
+
const pinned = config.configurable?.["checkpoint_id"];
|
|
268
|
+
const snapshotId = snapshot.config.configurable?.["checkpoint_id"];
|
|
269
|
+
const historyId = typeof pinned === "string" && pinned !== ""
|
|
270
|
+
? pinned
|
|
271
|
+
: typeof snapshotId === "string"
|
|
272
|
+
? snapshotId
|
|
273
|
+
: null;
|
|
274
|
+
const [, destConfig] = await forkNativeSession(graph, {
|
|
275
|
+
ctx,
|
|
276
|
+
historyId,
|
|
277
|
+
resolveThreadId: null,
|
|
278
|
+
state: values,
|
|
279
|
+
asNode: asNode ?? null,
|
|
280
|
+
});
|
|
281
|
+
return destConfig;
|
|
282
|
+
}
|
|
283
|
+
return original(config, values, asNode);
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/** AER write plugin that forks a LangGraph session. */
|
|
287
|
+
export class LangGraphForkPlugin {
|
|
288
|
+
getAgent;
|
|
289
|
+
workspaceIdResolver;
|
|
290
|
+
constructor(args) {
|
|
291
|
+
this.getAgent = args.getAgent;
|
|
292
|
+
this.workspaceIdResolver = args.workspaceIdResolver;
|
|
293
|
+
}
|
|
294
|
+
async forkSession(args) {
|
|
295
|
+
const agent = this.getAgent();
|
|
296
|
+
const workspaceId = this.workspaceIdResolver();
|
|
297
|
+
const attempt = currentAttemptContext();
|
|
298
|
+
if (attempt !== null) {
|
|
299
|
+
const identity = attempt.workflowIdentity;
|
|
300
|
+
if (!identity ||
|
|
301
|
+
args.sessionId !== identity.sessionId ||
|
|
302
|
+
args.executionId !== identity.executionId ||
|
|
303
|
+
workspaceId !== (identity.tenantScope?.workspaceId ?? "")) {
|
|
304
|
+
throw new Error("durable fork request identity does not match the current OE attempt");
|
|
305
|
+
}
|
|
306
|
+
// Durable CreateBranch accepts the exact committed snapshot. Do not
|
|
307
|
+
// reinterpret an API state patch as part of that source snapshot.
|
|
308
|
+
requireExactDurableBranch(args.state);
|
|
309
|
+
const configurable = {
|
|
310
|
+
thread_id: checkpointThreadId({
|
|
311
|
+
sessionId: args.sessionId,
|
|
312
|
+
workspaceId,
|
|
313
|
+
executionId: args.executionId,
|
|
314
|
+
}, agent.resolveThreadId ?? null),
|
|
315
|
+
checkpoint_ns: "",
|
|
316
|
+
};
|
|
317
|
+
if (args.historyId) {
|
|
318
|
+
configurable["checkpoint_id"] = args.historyId;
|
|
319
|
+
}
|
|
320
|
+
const [branch] = await forkDurableSession(agent.compiledGraph, {
|
|
321
|
+
context: attempt,
|
|
322
|
+
config: { configurable },
|
|
323
|
+
resolveThreadId: agent.resolveThreadId ?? null,
|
|
324
|
+
});
|
|
325
|
+
return branch;
|
|
326
|
+
}
|
|
327
|
+
const [branch] = await forkNativeSession(agent.compiledGraph, {
|
|
328
|
+
ctx: {
|
|
329
|
+
sessionId: args.sessionId,
|
|
330
|
+
workspaceId,
|
|
331
|
+
executionId: args.executionId,
|
|
332
|
+
},
|
|
333
|
+
historyId: args.historyId,
|
|
334
|
+
resolveThreadId: agent.resolveThreadId ?? null,
|
|
335
|
+
state: args.state,
|
|
336
|
+
});
|
|
337
|
+
return branch;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function createNativeBranch(args) {
|
|
341
|
+
const body = { branch_key: args.branchKey };
|
|
342
|
+
if (args.checkpointId)
|
|
343
|
+
body["checkpoint_id"] = args.checkpointId;
|
|
344
|
+
return createBranch(args, body);
|
|
345
|
+
}
|
|
346
|
+
async function createDurableBranch(args) {
|
|
347
|
+
const body = {
|
|
348
|
+
branch_key: args.branchKey,
|
|
349
|
+
step_ordinal: args.stepOrdinal,
|
|
350
|
+
state: JSON.parse(encodeProtoJson(StateSnapshotSchema, args.state)),
|
|
351
|
+
};
|
|
352
|
+
return createBranch(args, body);
|
|
353
|
+
}
|
|
354
|
+
async function createBranch(args, body) {
|
|
355
|
+
const oeUrl = resolveOeUrl(getCurrentOeUrl() ?? "").replace(/\/$/, "");
|
|
356
|
+
if (!oeUrl) {
|
|
357
|
+
throw new Error("OE_URL is not configured; cannot fork a session");
|
|
358
|
+
}
|
|
359
|
+
const path = `/workflow/orgs/${quotePathSegment(args.orgId)}` +
|
|
360
|
+
`/projects/${quotePathSegment(args.projectId)}` +
|
|
361
|
+
`/workspaces/${quotePathSegment(args.workspaceId)}` +
|
|
362
|
+
`/sessions/${quotePathSegment(args.sessionId)}` +
|
|
363
|
+
`/executions/${quotePathSegment(args.executionId)}/branches`;
|
|
364
|
+
const url = `${oeUrl}${path}`;
|
|
365
|
+
const response = await fetchPlatform(url, {
|
|
366
|
+
...getFetchOptionsWithTLS(url),
|
|
367
|
+
method: "POST",
|
|
368
|
+
headers: { "Content-Type": "application/json" },
|
|
369
|
+
body: JSON.stringify(body),
|
|
370
|
+
signal: AbortSignal.timeout(CREATE_BRANCH_TIMEOUT_MS),
|
|
371
|
+
});
|
|
372
|
+
if (response.status !== 200 && response.status !== 201) {
|
|
373
|
+
throw new Error(`CreateBranch failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
|
|
374
|
+
}
|
|
375
|
+
const payload = (await response.json());
|
|
376
|
+
const newSessionId = payload["session_id"];
|
|
377
|
+
const newExecutionId = payload["execution_id"];
|
|
378
|
+
if (typeof newSessionId !== "string" ||
|
|
379
|
+
typeof newExecutionId !== "string" ||
|
|
380
|
+
!newSessionId ||
|
|
381
|
+
!newExecutionId) {
|
|
382
|
+
throw new Error("CreateBranch response is missing session identity");
|
|
383
|
+
}
|
|
384
|
+
return { sessionId: newSessionId, executionId: newExecutionId };
|
|
385
|
+
}
|
|
386
|
+
const BRANCH_KEY_SAFE = /[^A-Za-z0-9._/-]+/g;
|
|
387
|
+
function isPlainObject(value) {
|
|
388
|
+
if (value === null || typeof value !== "object")
|
|
389
|
+
return false;
|
|
390
|
+
const prototype = Object.getPrototypeOf(value);
|
|
391
|
+
return prototype === Object.prototype || prototype === null;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Canonicalize a state patch for hashing: plain-object keys are sorted so
|
|
395
|
+
* equivalent patches hash identically, while array order stays significant
|
|
396
|
+
* (Python `json.dumps(..., sort_keys=True)` parity). Non-plain values keep
|
|
397
|
+
* their own serialization contract.
|
|
398
|
+
*/
|
|
399
|
+
function canonicalStateValue(value) {
|
|
400
|
+
if (Array.isArray(value))
|
|
401
|
+
return value.map(canonicalStateValue);
|
|
402
|
+
if (isPlainObject(value)) {
|
|
403
|
+
return Object.fromEntries(Object.keys(value)
|
|
404
|
+
.sort()
|
|
405
|
+
.map((key) => [key, canonicalStateValue(value[key])]));
|
|
406
|
+
}
|
|
407
|
+
return value;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Deterministic idempotency key for one fork: the same history, state patch,
|
|
411
|
+
* and node always map to the same branch, so retries reuse the OE branch.
|
|
412
|
+
*/
|
|
413
|
+
function branchKey(historyId, state, asNode, taskId) {
|
|
414
|
+
const payload = JSON.stringify({
|
|
415
|
+
state: isEmptyValues(state) ? null : canonicalStateValue(state),
|
|
416
|
+
asNode: asNode ?? "",
|
|
417
|
+
taskId: taskId ?? "",
|
|
418
|
+
});
|
|
419
|
+
const digest = createHash("sha256")
|
|
420
|
+
.update(`${historyId}\0${payload}`)
|
|
421
|
+
.digest("hex")
|
|
422
|
+
.slice(0, 16);
|
|
423
|
+
const safeHistory = historyId
|
|
424
|
+
.replace(BRANCH_KEY_SAFE, "-")
|
|
425
|
+
.replace(/^[-._/]+|[-._/]+$/g, "");
|
|
426
|
+
return `update-${safeHistory.slice(0, 64) || "latest"}-${digest}`;
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=session_fork.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session_fork.js","sourceRoot":"","sources":["../src/session_fork.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent spec validation for `createAgentEngineDeepAgent`.
|
|
3
|
+
*
|
|
4
|
+
* Hard-fails at agent construction time when a subagent spec uses a string
|
|
5
|
+
* model — string models bypass the `SecureWrappedLLM` seam and therefore the
|
|
6
|
+
* OE audit path. Kept in its own module (mirroring Python's `subagents.py`) so
|
|
7
|
+
* the validator has an importable surface for tests rather than being reachable
|
|
8
|
+
* only through the wrapper factory.
|
|
9
|
+
*/
|
|
10
|
+
import type { AnySubAgent } from "deepagents";
|
|
11
|
+
/**
|
|
12
|
+
* Recursion is bounded so an adversarial spec (or an accidental cycle) can't
|
|
13
|
+
* blow the stack at agent-construction time.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MAX_SUBAGENT_NESTING_DEPTH = 10;
|
|
16
|
+
/**
|
|
17
|
+
* Walk the subagent tree, throwing on any string-model spec.
|
|
18
|
+
*
|
|
19
|
+
* String model specs would bypass OE routing because deepagents' `resolveModel`
|
|
20
|
+
* instantiates a raw provider client with no `SecureToolWrapper`. Only model
|
|
21
|
+
* instances (e.g. `SecureWrappedLLM`) are accepted.
|
|
22
|
+
*
|
|
23
|
+
* Spec kinds handled:
|
|
24
|
+
* - `CompiledSubAgent` (`runnable` set) — pre-built graph; the model is already
|
|
25
|
+
* bound and unreadable here. Skipped.
|
|
26
|
+
* - `AsyncSubAgent` (`graphId` set) — remote graph we can't validate in-process.
|
|
27
|
+
* Logged at WARNING and skipped — the receiving end must route through the OE.
|
|
28
|
+
* - Plain `SubAgent` — validated; a string `model` throws.
|
|
29
|
+
*
|
|
30
|
+
* The depth counter is held in a closure rather than a public parameter so
|
|
31
|
+
* callers cannot start recursion mid-tree and bypass the cap.
|
|
32
|
+
*
|
|
33
|
+
* @throws {Error} A subagent spec uses a string `model`, or nesting exceeds
|
|
34
|
+
* {@link MAX_SUBAGENT_NESTING_DEPTH}.
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateSubagentTree(subagents: readonly AnySubAgent[] | undefined): void;
|
|
37
|
+
//# sourceMappingURL=subagents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../src/subagents.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAY,MAAM,YAAY,CAAC;AAMxD;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAK7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,GAC5C,IAAI,CAoCN"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent spec validation for `createAgentEngineDeepAgent`.
|
|
3
|
+
*
|
|
4
|
+
* Hard-fails at agent construction time when a subagent spec uses a string
|
|
5
|
+
* model — string models bypass the `SecureWrappedLLM` seam and therefore the
|
|
6
|
+
* OE audit path. Kept in its own module (mirroring Python's `subagents.py`) so
|
|
7
|
+
* the validator has an importable surface for tests rather than being reachable
|
|
8
|
+
* only through the wrapper factory.
|
|
9
|
+
*/
|
|
10
|
+
import { isAsyncSubAgent } from "deepagents";
|
|
11
|
+
import { getLogger } from "@mongodb-js/agent-engine-runner-shared";
|
|
12
|
+
const logger = getLogger("agent_engine_sdk_langgraph.subagents");
|
|
13
|
+
/**
|
|
14
|
+
* Recursion is bounded so an adversarial spec (or an accidental cycle) can't
|
|
15
|
+
* blow the stack at agent-construction time.
|
|
16
|
+
*/
|
|
17
|
+
export const MAX_SUBAGENT_NESTING_DEPTH = 10;
|
|
18
|
+
/**
|
|
19
|
+
* Walk the subagent tree, throwing on any string-model spec.
|
|
20
|
+
*
|
|
21
|
+
* String model specs would bypass OE routing because deepagents' `resolveModel`
|
|
22
|
+
* instantiates a raw provider client with no `SecureToolWrapper`. Only model
|
|
23
|
+
* instances (e.g. `SecureWrappedLLM`) are accepted.
|
|
24
|
+
*
|
|
25
|
+
* Spec kinds handled:
|
|
26
|
+
* - `CompiledSubAgent` (`runnable` set) — pre-built graph; the model is already
|
|
27
|
+
* bound and unreadable here. Skipped.
|
|
28
|
+
* - `AsyncSubAgent` (`graphId` set) — remote graph we can't validate in-process.
|
|
29
|
+
* Logged at WARNING and skipped — the receiving end must route through the OE.
|
|
30
|
+
* - Plain `SubAgent` — validated; a string `model` throws.
|
|
31
|
+
*
|
|
32
|
+
* The depth counter is held in a closure rather than a public parameter so
|
|
33
|
+
* callers cannot start recursion mid-tree and bypass the cap.
|
|
34
|
+
*
|
|
35
|
+
* @throws {Error} A subagent spec uses a string `model`, or nesting exceeds
|
|
36
|
+
* {@link MAX_SUBAGENT_NESTING_DEPTH}.
|
|
37
|
+
*/
|
|
38
|
+
export function validateSubagentTree(subagents) {
|
|
39
|
+
const walk = (nodes, depth) => {
|
|
40
|
+
if (nodes === undefined)
|
|
41
|
+
return;
|
|
42
|
+
if (depth > MAX_SUBAGENT_NESTING_DEPTH) {
|
|
43
|
+
throw new Error(`SubAgent nesting exceeds maximum recursion depth (${MAX_SUBAGENT_NESTING_DEPTH})`);
|
|
44
|
+
}
|
|
45
|
+
for (const spec of nodes) {
|
|
46
|
+
// Pre-built graph — model already bound, nothing to validate.
|
|
47
|
+
if ("runnable" in spec)
|
|
48
|
+
continue;
|
|
49
|
+
// Remote graph — defer to the receiving end.
|
|
50
|
+
if (isAsyncSubAgent(spec)) {
|
|
51
|
+
logger.warn(`AsyncSubAgent '${spec.name ?? "<unnamed>"}' targets remote ` +
|
|
52
|
+
`graphId='${spec.graphId}' — verify the remote graph routes ` +
|
|
53
|
+
`through the OE for audit compliance`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const sub = spec;
|
|
57
|
+
if (typeof sub.model === "string") {
|
|
58
|
+
throw new Error(`SubAgent '${sub.name ?? "<unnamed>"}' uses a string model spec ` +
|
|
59
|
+
`('${sub.model}') which bypasses OE routing. Pass a model ` +
|
|
60
|
+
`instance (e.g. SecureWrappedLLM via app.llm()) instead.`);
|
|
61
|
+
}
|
|
62
|
+
walk(sub.subagents, depth + 1);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
walk(subagents, 0);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=subagents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.js","sourceRoot":"","sources":["../src/subagents.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAEnE,MAAM,MAAM,GAAG,SAAS,CAAC,sCAAsC,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAK7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAA6C;IAE7C,MAAM,IAAI,GAAG,CACX,KAAyC,EACzC,KAAa,EACP,EAAE;QACR,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,IAAI,KAAK,GAAG,0BAA0B,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,qDAAqD,0BAA0B,GAAG,CACnF,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,8DAA8D;YAC9D,IAAI,UAAU,IAAI,IAAI;gBAAE,SAAS;YACjC,6CAA6C;YAC7C,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,IAAI,CACT,kBAAkB,IAAI,CAAC,IAAI,IAAI,WAAW,mBAAmB;oBAC3D,YAAY,IAAI,CAAC,OAAO,qCAAqC;oBAC7D,qCAAqC,CACxC,CAAC;gBACF,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,IAAwB,CAAC;YACrC,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAClC,MAAM,IAAI,KAAK,CACb,aAAa,GAAG,CAAC,IAAI,IAAI,WAAW,6BAA6B;oBAC/D,KAAK,GAAG,CAAC,KAAK,6CAA6C;oBAC3D,yDAAyD,CAC5D,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;AACrB,CAAC"}
|