@langchain/langgraph 1.4.2 → 1.4.4
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/channels/delta.cjs +8 -9
- package/dist/channels/delta.cjs.map +1 -1
- package/dist/channels/delta.d.cts.map +1 -1
- package/dist/channels/delta.d.ts.map +1 -1
- package/dist/channels/delta.js +8 -9
- package/dist/channels/delta.js.map +1 -1
- package/dist/constants.cjs +10 -1
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +10 -1
- package/dist/constants.js.map +1 -1
- package/dist/graph/messages_reducer.cjs +12 -4
- package/dist/graph/messages_reducer.cjs.map +1 -1
- package/dist/graph/messages_reducer.d.cts +8 -3
- package/dist/graph/messages_reducer.d.cts.map +1 -1
- package/dist/graph/messages_reducer.d.ts +8 -3
- package/dist/graph/messages_reducer.d.ts.map +1 -1
- package/dist/graph/messages_reducer.js +12 -4
- package/dist/graph/messages_reducer.js.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/pregel/algo.cjs +20 -3
- package/dist/pregel/algo.cjs.map +1 -1
- package/dist/pregel/algo.js +20 -3
- package/dist/pregel/algo.js.map +1 -1
- package/dist/pregel/debug.cjs +25 -1
- package/dist/pregel/debug.cjs.map +1 -1
- package/dist/pregel/debug.js +25 -1
- package/dist/pregel/debug.js.map +1 -1
- package/dist/pregel/index.cjs +8 -1
- package/dist/pregel/index.cjs.map +1 -1
- package/dist/pregel/index.d.cts.map +1 -1
- package/dist/pregel/index.d.ts.map +1 -1
- package/dist/pregel/index.js +9 -2
- package/dist/pregel/index.js.map +1 -1
- package/dist/pregel/loop.cjs +19 -1
- package/dist/pregel/loop.cjs.map +1 -1
- package/dist/pregel/loop.js +20 -2
- package/dist/pregel/loop.js.map +1 -1
- package/dist/pregel/messages-v2.cjs +1 -0
- package/dist/pregel/messages-v2.cjs.map +1 -1
- package/dist/pregel/messages-v2.js +1 -0
- package/dist/pregel/messages-v2.js.map +1 -1
- package/dist/pregel/utils/config.cjs +106 -9
- package/dist/pregel/utils/config.cjs.map +1 -1
- package/dist/pregel/utils/config.d.cts.map +1 -1
- package/dist/pregel/utils/config.d.ts.map +1 -1
- package/dist/pregel/utils/config.js +107 -11
- package/dist/pregel/utils/config.js.map +1 -1
- package/dist/pregel/utils/index.cjs +0 -16
- package/dist/pregel/utils/index.cjs.map +1 -1
- package/dist/pregel/utils/index.js +1 -16
- package/dist/pregel/utils/index.js.map +1 -1
- package/dist/state/index.cjs +1 -0
- package/dist/state/index.d.ts +2 -1
- package/dist/state/index.js +1 -0
- package/dist/state/prebuilt/index.d.ts +1 -1
- package/dist/state/prebuilt/messages.cjs +25 -0
- package/dist/state/prebuilt/messages.cjs.map +1 -1
- package/dist/state/prebuilt/messages.d.cts +18 -1
- package/dist/state/prebuilt/messages.d.cts.map +1 -1
- package/dist/state/prebuilt/messages.d.ts +18 -1
- package/dist/state/prebuilt/messages.d.ts.map +1 -1
- package/dist/state/prebuilt/messages.js +31 -4
- package/dist/state/prebuilt/messages.js.map +1 -1
- package/dist/state/schema.cjs +14 -6
- package/dist/state/schema.cjs.map +1 -1
- package/dist/state/schema.d.cts +7 -4
- package/dist/state/schema.d.cts.map +1 -1
- package/dist/state/schema.d.ts +7 -4
- package/dist/state/schema.d.ts.map +1 -1
- package/dist/state/schema.js +14 -6
- package/dist/state/schema.js.map +1 -1
- package/dist/state/values/delta.cjs +77 -0
- package/dist/state/values/delta.cjs.map +1 -0
- package/dist/state/values/delta.d.cts +152 -0
- package/dist/state/values/delta.d.cts.map +1 -0
- package/dist/state/values/delta.d.ts +152 -0
- package/dist/state/values/delta.d.ts.map +1 -0
- package/dist/state/values/delta.js +77 -0
- package/dist/state/values/delta.js.map +1 -0
- package/dist/state/values/index.cjs +1 -0
- package/dist/state/values/index.d.ts +3 -0
- package/dist/state/values/index.js +1 -0
- package/dist/stream/transformers/lifecycle.cjs +93 -2
- package/dist/stream/transformers/lifecycle.cjs.map +1 -1
- package/dist/stream/transformers/lifecycle.js +93 -2
- package/dist/stream/transformers/lifecycle.js.map +1 -1
- package/dist/web.cjs +3 -0
- package/dist/web.d.cts +3 -2
- package/dist/web.d.ts +3 -2
- package/dist/web.js +3 -2
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.js","names":[],"sources":["../../../src/state/values/delta.ts"],"sourcesContent":["import type { SerializableSchema } from \"../types.js\";\nimport type { DeltaReducer } from \"../../channels/delta.js\";\n\n/**\n * Symbol for runtime identification of DeltaValue instances.\n */\nexport const DELTA_VALUE_SYMBOL: symbol = Symbol.for(\n \"langgraph.state.delta_value\"\n);\n\ninterface DeltaValueInitBase<Value = unknown> {\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * writes in a single call: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Reducers must be deterministic and batching-invariant (associative across\n * folds), because {@link DeltaChannel} replays checkpointed writes in larger\n * batches than they were originally produced:\n * `reducer(reducer(state, xs), ys) === reducer(state, xs.concat(ys))`.\n */\n reducer: DeltaReducer<Value, Value>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob\n * instead of relying purely on replayed deltas. Defaults to the channel's\n * own default (1000) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\ninterface DeltaValueInitWithSchema<Value = unknown, Input = Value> {\n /**\n * Schema describing the type and validation logic for reducer input values.\n *\n * When provided, the reducer may accept inputs distinct from the stored\n * (output) type. Each write is validated against this schema before reduction.\n */\n inputSchema: SerializableSchema<unknown, Input>;\n\n /**\n * Batch reducer that combines the current accumulated value with a batch of\n * validated writes: `reducer(state, [w1, w2, ...]) -> newState`.\n *\n * Must be deterministic and batching-invariant — see\n * {@link DeltaValueInitBase.reducer}.\n */\n reducer: DeltaReducer<Value, Input>;\n\n /**\n * How often (in per-channel updates) to persist a full `DeltaSnapshot` blob.\n * Defaults to the channel's own default (1000) when omitted.\n */\n snapshotFrequency?: number;\n\n /**\n * Optional extra fields merged into the generated JSON Schema (e.g.\n * `langgraph_type`) for documentation, Studio hints, or external tooling.\n */\n jsonSchemaExtra?: Record<string, unknown>;\n}\n\n/**\n * Initialization options for {@link DeltaValue}.\n *\n * Two forms are supported:\n * 1. Provide only a reducer (and optionally `snapshotFrequency` /\n * `jsonSchemaExtra`) — the reducer's inputs are validated using the value\n * schema.\n * 2. Provide an explicit `inputSchema` to distinguish the reducer's input type\n * from the stored/output type.\n *\n * @template Value - The type of value stored and produced after reduction.\n * @template Input - The type of inputs accepted by the reducer.\n */\nexport type DeltaValueInit<Value = unknown, Input = Value> =\n | DeltaValueInitWithSchema<Value, Input>\n | DeltaValueInitBase<Value>;\n\n/**\n * Represents a state field backed by a {@link DeltaChannel}.\n *\n * Unlike {@link ReducedValue} (which stores the full accumulated value in every\n * checkpoint blob via `BinaryOperatorAggregate`), a `DeltaValue` field persists\n * only per-step deltas (plus periodic snapshots) and reconstructs its state on\n * read by replaying ancestor writes through a batch reducer. This avoids\n * re-serializing large accumulators (e.g. long message histories) at every step.\n *\n * @remarks Beta. The on-disk representation backing `DeltaChannel` may change in\n * future releases.\n *\n * @template Value - The type of the value stored in state and produced by reduction.\n * @template Input - The type of updates accepted by the reducer.\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * import { StateSchema, DeltaValue } from \"@langchain/langgraph\";\n *\n * const State = new StateSchema({\n * history: new DeltaValue(z.array(z.string()).default(() => []), {\n * inputSchema: z.string(),\n * reducer: (current, writes) => [...current, ...writes],\n * }),\n * });\n * ```\n */\nexport class DeltaValue<Value = unknown, Input = Value> {\n /**\n * Instance marker for runtime identification.\n * @internal\n */\n protected readonly [DELTA_VALUE_SYMBOL] = true as const;\n\n /**\n * The schema that describes the type of value stored in state (after\n * reduction). Its default (if any) seeds the channel's initial value.\n */\n readonly valueSchema: SerializableSchema<unknown, Value>;\n\n /**\n * The schema used to validate reducer inputs. Defaults to `valueSchema` when\n * not specified explicitly.\n */\n readonly inputSchema: SerializableSchema<unknown, Input | Value>;\n\n /**\n * The batch reducer that folds a list of incoming writes into the current\n * accumulated value.\n */\n readonly reducer: DeltaReducer<Value, Input>;\n\n /**\n * Snapshot cadence forwarded to the underlying {@link DeltaChannel}.\n */\n readonly snapshotFrequency?: number;\n\n /**\n * Optional extra fields to merge into the generated JSON Schema.\n */\n readonly jsonSchemaExtra?: Record<string, unknown>;\n\n /**\n * Represents the value stored after all reductions.\n */\n declare ValueType: Value;\n\n /**\n * Represents the type that may be provided as input on each update.\n */\n declare InputType: Input;\n\n /**\n * Constructs a DeltaValue, pairing a value schema with a batch reducer (and an\n * optional distinct input schema).\n *\n * @param valueSchema - The schema describing the stored/output value.\n * @param init - The reducer (required), `inputSchema`, `snapshotFrequency`,\n * and `jsonSchemaExtra` (all optional except the reducer).\n */\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInitWithSchema<Value, Input>\n );\n\n constructor(\n valueSchema: SerializableSchema<Input, Value>,\n init: DeltaValueInitBase<Value>\n );\n\n constructor(\n valueSchema: SerializableSchema<unknown, Value>,\n init: DeltaValueInit<Value, Input>\n ) {\n this.reducer = init.reducer as DeltaReducer<Value, Input>;\n this.valueSchema = valueSchema;\n this.inputSchema = \"inputSchema\" in init ? init.inputSchema : valueSchema;\n this.snapshotFrequency = init.snapshotFrequency;\n this.jsonSchemaExtra = init.jsonSchemaExtra;\n }\n\n /**\n * Type guard to check if a value is a DeltaValue instance.\n */\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input>\n ): value is DeltaValue<Value, Input>;\n\n static isInstance(value: unknown): value is DeltaValue;\n\n static isInstance<Value = unknown, Input = Value>(\n value: DeltaValue<Value, Input> | unknown\n ): value is DeltaValue<Value, Input> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n DELTA_VALUE_SYMBOL in value &&\n (value as Record<symbol, unknown>)[DELTA_VALUE_SYMBOL] === true\n );\n }\n}\n"],"mappings":";;;;AAMA,MAAa,qBAA6B,OAAO,IAC/C,8BACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwGD,IAAa,aAAb,MAAwD;;;;;CAKtD,CAAoB,sBAAsB;;;;;CAM1C;;;;;CAMA;;;;;CAMA;;;;CAKA;;;;CAKA;CA8BA,YACE,aACA,MACA;AACA,OAAK,UAAU,KAAK;AACpB,OAAK,cAAc;AACnB,OAAK,cAAc,iBAAiB,OAAO,KAAK,cAAc;AAC9D,OAAK,oBAAoB,KAAK;AAC9B,OAAK,kBAAkB,KAAK;;CAY9B,OAAO,WACL,OACmC;AACnC,SACE,OAAO,UAAU,YACjB,UAAU,QACV,sBAAsB,SACrB,MAAkC,wBAAwB"}
|
|
@@ -97,6 +97,23 @@ function createLifecycleTransformer(options = {}) {
|
|
|
97
97
|
const log = require_stream_channel.StreamChannel.local();
|
|
98
98
|
const namespaces = /* @__PURE__ */ new Map();
|
|
99
99
|
const namespaceCause = /* @__PURE__ */ new Map();
|
|
100
|
+
/**
|
|
101
|
+
* `lc_agent_name` observed at each namespace (first task event wins). A
|
|
102
|
+
* nested run carrying an `lc_agent_name` (set by `createAgent`) is treated
|
|
103
|
+
* as a named subagent: its `graph_name` becomes that name and a tool-call
|
|
104
|
+
* `cause` is recovered (see {@link deriveToolCallCause}). Namespaces without
|
|
105
|
+
* one fall back to the parsed namespace segment, preserving the prior
|
|
106
|
+
* product-agnostic behavior for plain subgraphs.
|
|
107
|
+
*/
|
|
108
|
+
const lcByNs = /* @__PURE__ */ new Map();
|
|
109
|
+
/**
|
|
110
|
+
* Pregel task id -> triggering LLM `tool_call_id`, harvested from a task
|
|
111
|
+
* whose `input` is a `tool_call_with_context` dict (current shape) or a list
|
|
112
|
+
* of tool-call dicts (legacy shape). The child subgraph's namespace segment
|
|
113
|
+
* `node:<task_id>` shares this task id, so a named subagent recovers the tool
|
|
114
|
+
* call that spawned it across payloads.
|
|
115
|
+
*/
|
|
116
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
100
117
|
const pendingInterruptIds = /* @__PURE__ */ new Set();
|
|
101
118
|
/**
|
|
102
119
|
* Child namespaces whose parent just saw an `updates` event with a
|
|
@@ -109,7 +126,77 @@ function createLifecycleTransformer(options = {}) {
|
|
|
109
126
|
let emitter;
|
|
110
127
|
let inSelfEmit = 0;
|
|
111
128
|
let finalized = false;
|
|
112
|
-
const resolveGraphName = (ns) =>
|
|
129
|
+
const resolveGraphName = (ns) => {
|
|
130
|
+
if (ns.length === 0) return rootGraphName;
|
|
131
|
+
const lc = lcByNs.get(require_mux.nsKey(ns));
|
|
132
|
+
if (typeof lc === "string" && lc.length > 0) return lc;
|
|
133
|
+
return getGraphName(ns);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Record a namespace's `lc_agent_name` from a task-start payload (first
|
|
137
|
+
* event wins). The presence of a name is what marks the namespace a named
|
|
138
|
+
* subagent; the value may be `undefined` for unnamed runs (still recorded so
|
|
139
|
+
* a later event doesn't re-evaluate it).
|
|
140
|
+
*/
|
|
141
|
+
const recordIdentity = (ns, data) => {
|
|
142
|
+
const key = require_mux.nsKey(ns);
|
|
143
|
+
if (lcByNs.has(key)) return;
|
|
144
|
+
const lc = (isRecord(data) && isRecord(data.metadata) ? data.metadata : void 0)?.lc_agent_name;
|
|
145
|
+
lcByNs.set(key, typeof lc === "string" ? lc : void 0);
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Harvest a task's triggering `tool_call_id` keyed by its task id. The
|
|
149
|
+
* spawned subgraph's namespace segment `node:<task_id>` shares that id, so a
|
|
150
|
+
* subagent can later recover the tool call that caused it. Two input shapes
|
|
151
|
+
* are handled: a `tool_call_with_context` object (`input.tool_call.id`) and a
|
|
152
|
+
* legacy list of tool-call objects (first with a string `id`).
|
|
153
|
+
*/
|
|
154
|
+
const recordPendingToolCalls = (data) => {
|
|
155
|
+
if (!isRecord(data)) return;
|
|
156
|
+
const taskId = data.id;
|
|
157
|
+
if (typeof taskId !== "string") return;
|
|
158
|
+
const input = data.input;
|
|
159
|
+
let toolCallId;
|
|
160
|
+
if (isRecord(input) && isRecord(input.tool_call)) {
|
|
161
|
+
const candidate = input.tool_call.id;
|
|
162
|
+
if (typeof candidate === "string") toolCallId = candidate;
|
|
163
|
+
} else if (Array.isArray(input)) {
|
|
164
|
+
for (const toolCall of input) if (isRecord(toolCall) && typeof toolCall.id === "string") {
|
|
165
|
+
toolCallId = toolCall.id;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (toolCallId != null) pendingToolCalls.set(taskId, toolCallId);
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Derive a `toolCall` cause for a named subagent namespace by joining the
|
|
173
|
+
* namespace segment's task id (`node:<task_id>`) to a previously harvested
|
|
174
|
+
* `tool_call_id`. Only fires for namespaces carrying an `lc_agent_name`, so
|
|
175
|
+
* plain subgraphs never get a spurious cause.
|
|
176
|
+
*/
|
|
177
|
+
const deriveToolCallCause = (ns) => {
|
|
178
|
+
if (ns.length === 0) return void 0;
|
|
179
|
+
const lc = lcByNs.get(require_mux.nsKey(ns));
|
|
180
|
+
if (typeof lc !== "string" || lc.length === 0) return void 0;
|
|
181
|
+
const segment = ns[ns.length - 1];
|
|
182
|
+
const colon = segment.indexOf(":");
|
|
183
|
+
if (colon === -1) return void 0;
|
|
184
|
+
const triggerCallId = segment.slice(colon + 1);
|
|
185
|
+
if (triggerCallId.length === 0) return void 0;
|
|
186
|
+
const toolCallId = pendingToolCalls.get(triggerCallId);
|
|
187
|
+
if (typeof toolCallId !== "string" || toolCallId.length === 0) return;
|
|
188
|
+
return {
|
|
189
|
+
type: "toolCall",
|
|
190
|
+
tool_call_id: toolCallId
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Resolve the `cause` to attach to a namespace's `started`. An upstream
|
|
195
|
+
* `cause` stashed from a product-specific transformer (e.g. deepagents'
|
|
196
|
+
* SubagentTransformer) wins; otherwise a tool-call cause is recovered for
|
|
197
|
+
* named subagents.
|
|
198
|
+
*/
|
|
199
|
+
const resolveStartCause = (ns) => namespaceCause.get(require_mux.nsKey(ns)) ?? deriveToolCallCause(ns);
|
|
113
200
|
const emit = (ns, status, extras) => {
|
|
114
201
|
const key = require_mux.nsKey(ns);
|
|
115
202
|
let current = namespaces.get(key);
|
|
@@ -204,7 +291,7 @@ function createLifecycleTransformer(options = {}) {
|
|
|
204
291
|
const key = require_mux.nsKey(prefix);
|
|
205
292
|
if (namespaces.has(key)) continue;
|
|
206
293
|
trackNamespace(prefix);
|
|
207
|
-
const cause =
|
|
294
|
+
const cause = resolveStartCause(prefix);
|
|
208
295
|
emit(prefix, "started", cause != null ? { cause } : void 0);
|
|
209
296
|
}
|
|
210
297
|
};
|
|
@@ -258,6 +345,10 @@ function createLifecycleTransformer(options = {}) {
|
|
|
258
345
|
if (inSelfEmit > 0) return true;
|
|
259
346
|
const taskCompletion = event.method === "tasks" ? extractTaskResultCompletion(event.params.data) : void 0;
|
|
260
347
|
if (taskCompletion != null) removePendingNodeCompletions(ns, taskCompletion.name);
|
|
348
|
+
else if (event.method === "tasks") {
|
|
349
|
+
recordIdentity(ns, event.params.data);
|
|
350
|
+
recordPendingToolCalls(event.params.data);
|
|
351
|
+
}
|
|
261
352
|
flushPendingCompletions();
|
|
262
353
|
if (event.method === "lifecycle") {
|
|
263
354
|
const cause = extractCause(event.params.data);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.cjs","names":["hasPrefix","StreamChannel","nsKey"],"sources":["../../../src/stream/transformers/lifecycle.ts"],"sourcesContent":["/**\n * LifecycleTransformer - synthesizes `lifecycle` channel events that\n * track the status of the root run and every subgraph it spawns.\n *\n * The transformer is registered first in `createGraphRunStream` so that\n * every other transformer / consumer sees a coherent, authoritative\n * lifecycle stream. It is product-agnostic: deeper semantics (e.g.\n * DeepAgents' `SubagentTransformer` tool-call causation) reach the wire\n * by way of the re-entrant {@link StreamEmitter} - the transformer\n * stashes any `cause` attached upstream and re-emits its own\n * authoritative `lifecycle.started` with the correlation in place.\n *\n * Events are also pushed to a local {@link StreamChannel} so in-process\n * consumers can iterate `run.lifecycle` without filtering the main\n * event stream.\n */\n\nimport type {\n AgentStatus,\n LifecycleCause,\n LifecycleData,\n} from \"@langchain/protocol\";\n\nimport { hasPrefix, nsKey } from \"../mux.js\";\nimport { StreamChannel } from \"../stream-channel.js\";\nimport type {\n NativeStreamTransformer,\n Namespace,\n ProtocolEvent,\n StreamEmitter,\n} from \"../types.js\";\nimport type { LifecycleEntry, LifecycleTransformerOptions } from \"./types.js\";\n\n/**\n * Projection returned from the lifecycle transformer's `init()`.\n *\n * The local `StreamChannel` is closed automatically when the transformer\n * finalizes or fails. `_lifecycleLog` is intentionally underscore-prefixed to\n * signal that it is consumed by the run stream wiring\n * (see `run-stream.ts`) and not meant for direct user access -\n * consumers should read `run.lifecycle` instead.\n *\n * The `lifecycle` iterable is the root-scoped projection (prefix\n * `[]`, starting at offset `0`) mirroring the pattern used by the\n * subgraph discovery transformer. Root stream wiring consumes it\n * via `SET_LIFECYCLE_ITERABLE`; child streams are wired with their\n * own path-scoped iterable produced by `filterLifecycleEntries`.\n */\nexport interface LifecycleProjection {\n _lifecycleLog: StreamChannel<LifecycleEntry>;\n lifecycle: AsyncIterable<LifecycleEntry>;\n}\n\n/**\n * Filter a lifecycle {@link StreamChannel} to only the entries whose\n * namespace lies within the subtree rooted at {@link path}.\n *\n * Returns an `AsyncIterable` whose iterator yields every entry whose\n * namespace either equals {@link path} or is a descendant of it.\n * Iteration begins at {@link startAt}, so callers can capture the\n * log's current size at construction time to skip entries emitted\n * before the caller existed (e.g. a subgraph stream discovered\n * mid-run shouldn't replay the root's `started`).\n *\n * @param log - The shared lifecycle log owned by the transformer.\n * @param path - Namespace prefix to scope entries by (use `[]` for\n * the root subtree, i.e. everything).\n * @param startAt - Zero-based index into the log to begin from.\n * @returns An async iterable of matching lifecycle entries.\n */\nexport function filterLifecycleEntries(\n log: StreamChannel<LifecycleEntry>,\n path: Namespace,\n startAt = 0\n): AsyncIterable<LifecycleEntry> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<LifecycleEntry> {\n const base = log.iterate(startAt);\n return {\n async next(): Promise<IteratorResult<LifecycleEntry>> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const result = await base.next();\n if (result.done) {\n return {\n value: undefined as unknown as LifecycleEntry,\n done: true,\n };\n }\n if (hasPrefix(result.value.namespace, path)) {\n return { value: result.value, done: false };\n }\n }\n },\n };\n },\n };\n}\n\nconst DEFAULT_ROOT_GRAPH_NAME = \"root\";\n\nfunction defaultGuessGraphName(ns: Namespace): string {\n if (ns.length === 0) return DEFAULT_ROOT_GRAPH_NAME;\n const last = ns[ns.length - 1];\n const colon = last.indexOf(\":\");\n return colon === -1 ? last : last.slice(0, colon);\n}\n\nfunction defaultSerializeError(err: unknown): string {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (err instanceof Error) return err.message;\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Extract an upstream `cause` from a `lifecycle.started` payload, if\n * the shape matches one of the known variants. Shape validation is\n * intentionally loose: any object with a string `type` is accepted, so\n * future protocol variants flow through unchanged.\n */\nfunction extractCause(data: unknown): LifecycleCause | undefined {\n if (!isRecord(data)) return undefined;\n if (data.event !== \"started\") return undefined;\n const cause = data.cause;\n if (!isRecord(cause)) return undefined;\n if (typeof cause.type !== \"string\") return undefined;\n return cause as unknown as LifecycleCause;\n}\n\nfunction extractTaskResultCompletion(\n data: unknown\n): TaskResultCompletion | undefined {\n if (!isRecord(data)) return undefined;\n if (!(\"result\" in data)) return undefined;\n if (typeof data.name !== \"string\") return undefined;\n if (typeof data.id !== \"string\") return undefined;\n if (data.name.startsWith(\"__\")) return undefined;\n return { name: data.name, id: data.id };\n}\n\ninterface NamespaceRecord {\n readonly namespace: Namespace;\n readonly graphName: string;\n /** Last emitted status; `undefined` until `emit` fires for this namespace. */\n status: AgentStatus | undefined;\n}\n\ninterface TaskResultCompletion {\n readonly name: string;\n readonly id: string;\n}\n\ninterface PendingCompletion {\n readonly namespace: Namespace;\n readonly source:\n | { readonly type: \"task\" }\n | {\n readonly type: \"node\";\n readonly parent: Namespace;\n readonly node: string;\n };\n}\n\n/**\n * Create the built-in lifecycle transformer.\n *\n * Marked as a {@link NativeStreamTransformer} so the run stream\n * factory can expose `_lifecycleLog` via a dedicated getter\n * (`run.lifecycle`) rather than through `run.extensions`.\n */\nexport function createLifecycleTransformer(\n options: LifecycleTransformerOptions = {}\n): NativeStreamTransformer<LifecycleProjection> {\n const rootGraphName = options.rootGraphName ?? DEFAULT_ROOT_GRAPH_NAME;\n const initialStatus: AgentStatus = options.initialStatus ?? \"running\";\n const emitRootOnRegister = options.emitRootOnRegister ?? true;\n const getGraphName = options.getGraphName ?? defaultGuessGraphName;\n const serializeError = options.serializeError ?? defaultSerializeError;\n const getTerminalStatusOverride = options.getTerminalStatusOverride;\n\n const log = StreamChannel.local<LifecycleEntry>();\n const namespaces = new Map<string, NamespaceRecord>();\n const namespaceCause = new Map<string, LifecycleCause>();\n const pendingInterruptIds = new Set<string>();\n /**\n * Child namespaces whose parent just saw an `updates` event with a\n * `node` attribution. We defer the `lifecycle.completed` emission\n * until the *next* inbound event (or `finalize`) so the parent's\n * `updates` lands on the wire before its child is marked complete -\n * matching the previous session behavior.\n */\n const pendingCompletions: PendingCompletion[] = [];\n\n let emitter: StreamEmitter | undefined;\n let inSelfEmit = 0;\n let finalized = false;\n\n const resolveGraphName = (ns: Namespace): string =>\n ns.length === 0 ? rootGraphName : getGraphName(ns);\n\n const emit = (\n ns: Namespace,\n status: AgentStatus,\n extras?: { cause?: LifecycleCause; error?: string }\n ): void => {\n const key = nsKey(ns);\n let current = namespaces.get(key);\n const graphName = current?.graphName ?? resolveGraphName(ns);\n\n // Dedup: identical status + graph name + no error override => skip.\n if (\n current != null &&\n current.status === status &&\n current.graphName === graphName &&\n extras?.error == null\n ) {\n return;\n }\n\n if (current == null) {\n current = { namespace: ns, graphName, status };\n namespaces.set(key, current);\n } else {\n current.status = status;\n }\n\n const data: LifecycleData = {\n event: status,\n graph_name: graphName,\n ...(extras?.cause != null ? { cause: extras.cause } : {}),\n ...(extras?.error != null ? { error: extras.error } : {}),\n };\n\n const timestamp = Date.now();\n\n log.push({ namespace: ns, timestamp, ...data });\n\n if (ns.length === 0 && !emitRootOnRegister) return;\n\n if (emitter == null) return;\n\n inSelfEmit += 1;\n try {\n emitter.push(ns, {\n type: \"event\",\n seq: 0,\n method: \"lifecycle\",\n params: { namespace: ns, timestamp, data },\n });\n } finally {\n inSelfEmit -= 1;\n }\n };\n\n /**\n * Ensures a record exists for `ns` without mutating its status. Used\n * by hooks that need a canonical `graphName` for lookups before emit\n * writes the first status. Status remains `undefined` until `emit`\n * fires.\n */\n const trackNamespace = (ns: Namespace): NamespaceRecord => {\n const key = nsKey(ns);\n let rec = namespaces.get(key);\n if (rec == null) {\n rec = {\n namespace: ns,\n graphName: resolveGraphName(ns),\n status: undefined,\n };\n namespaces.set(key, rec);\n }\n return rec;\n };\n\n const flushPendingCompletions = (): void => {\n if (pendingCompletions.length === 0) return;\n const toFlush = pendingCompletions.splice(0, pendingCompletions.length);\n for (const completion of toFlush) {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") continue;\n emit(completion.namespace, \"completed\");\n }\n };\n\n const enqueueCompletion = (completion: PendingCompletion): void => {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") return;\n if (\n pendingCompletions.some((pending) => nsKey(pending.namespace) === key)\n ) {\n return;\n }\n pendingCompletions.push(completion);\n };\n\n const removePendingNodeCompletions = (\n parent: Namespace,\n node: string\n ): void => {\n for (let index = pendingCompletions.length - 1; index >= 0; index -= 1) {\n const pending = pendingCompletions[index];\n if (pending.source.type !== \"node\") continue;\n if (pending.source.node !== node) continue;\n if (nsKey(pending.source.parent) !== nsKey(parent)) continue;\n pendingCompletions.splice(index, 1);\n }\n };\n\n const ensureStarted = (ns: Namespace): void => {\n // Synthesize `lifecycle.started` for each unseen prefix of `ns`,\n // outermost first. Deepest-first would force consumers to see a\n // child's started before its parent, which is wrong.\n for (let length = 1; length <= ns.length; length += 1) {\n const prefix = ns.slice(0, length);\n const key = nsKey(prefix);\n if (namespaces.has(key)) continue;\n trackNamespace(prefix);\n const cause = namespaceCause.get(key);\n emit(prefix, \"started\", cause != null ? { cause } : undefined);\n }\n };\n\n const defaultTerminalStatus = (): AgentStatus =>\n pendingInterruptIds.size > 0 ? \"interrupted\" : \"completed\";\n\n const cascadeTerminalStatus = (status: AgentStatus): void => {\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, status);\n }\n emit([], status);\n log.close();\n };\n\n const resolveTerminalStatusOverride = async (): Promise<AgentStatus> => {\n if (getTerminalStatusOverride == null) return defaultTerminalStatus();\n try {\n return (await getTerminalStatusOverride()) ?? defaultTerminalStatus();\n } catch {\n return defaultTerminalStatus();\n }\n };\n\n const findStartedChildForNode = (\n parentNamespace: Namespace,\n node: string\n ): Namespace | undefined => {\n const prefix = `${node}:`;\n for (const rec of namespaces.values()) {\n if (rec.namespace.length !== parentNamespace.length + 1) continue;\n if (rec.status !== \"started\") continue;\n if (!hasPrefix(rec.namespace, parentNamespace)) continue;\n const last = rec.namespace[rec.namespace.length - 1];\n if (last === node || last.startsWith(prefix)) return rec.namespace;\n }\n return undefined;\n };\n\n const findStartedChildForTask = (\n parentNamespace: Namespace,\n task: TaskResultCompletion\n ): Namespace | undefined => {\n const namespace = [...parentNamespace, `${task.name}:${task.id}`];\n const rec = namespaces.get(nsKey(namespace));\n return rec?.status === \"started\" ? namespace : undefined;\n };\n\n const transformer: NativeStreamTransformer<LifecycleProjection> = {\n __native: true,\n\n init() {\n return {\n _lifecycleLog: log,\n lifecycle: filterLifecycleEntries(log, [], 0),\n };\n },\n\n onRegister(handle: StreamEmitter) {\n emitter = handle;\n // Seed root record so cascade logic can see it, even when the\n // outer authority owns root emission.\n trackNamespace([]);\n if (emitRootOnRegister) {\n emit([], initialStatus);\n }\n },\n\n process(event: ProtocolEvent): boolean {\n const ns = event.params.namespace;\n\n // Re-entrant loopback: an event we emitted via `emitter.push`\n // is being routed back through this transformer by the mux.\n // Allow it through the wire unchanged.\n if (inSelfEmit > 0) return true;\n\n const taskCompletion =\n event.method === \"tasks\"\n ? extractTaskResultCompletion(event.params.data)\n : undefined;\n if (taskCompletion != null) {\n // Prefer exact task-result attribution over any ambiguous\n // `updates.node` completion deferred from the previous event.\n removePendingNodeCompletions(ns, taskCompletion.name);\n }\n\n // Flush any completions deferred by the previous event so the\n // wire order is [triggering event] -> [deferred completed].\n flushPendingCompletions();\n\n // Upstream `lifecycle` events: stash any `cause` attached by a\n // product-specific transformer (e.g. deepagents' SubagentTransformer),\n // synthesize our authoritative started/... for the namespace, and\n // suppress the original so we are the single source of truth.\n if (event.method === \"lifecycle\") {\n const cause = extractCause(event.params.data);\n if (cause != null) {\n namespaceCause.set(nsKey(ns), cause);\n }\n ensureStarted(ns);\n return false;\n }\n\n // Lifecycle for parent + any unseen prefix => synthesize started.\n ensureStarted(ns);\n\n // Track interrupt ids so `finalize` can decide between\n // `completed` and `interrupted`.\n if (\n event.method === \"input\" &&\n isRecord(event.params.data) &&\n event.params.data.event === \"requested\"\n ) {\n const id = (event.params.data as { id?: unknown }).id;\n if (typeof id === \"string\") {\n pendingInterruptIds.add(id);\n }\n }\n\n if (taskCompletion != null) {\n const childNamespace = findStartedChildForTask(ns, taskCompletion);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"task\" },\n });\n }\n }\n\n // Defer child-node completion: the `updates` event carries the\n // node attribution; the corresponding child namespace is\n // `[...ns, \"<node>:<uuid>\"]`. We pick the oldest still-started\n // matching child (LangGraph emits one updates per completed task\n // so repeated calls drain parallel fan-outs in order).\n if (event.method === \"updates\") {\n const node = event.params.node;\n if (typeof node === \"string\" && !node.startsWith(\"__\")) {\n const childNamespace = findStartedChildForNode(ns, node);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"node\", parent: ns, node },\n });\n }\n }\n }\n\n return true;\n },\n\n finalize(): void | PromiseLike<void> {\n if (finalized) return;\n finalized = true;\n flushPendingCompletions();\n\n if (getTerminalStatusOverride == null) {\n cascadeTerminalStatus(defaultTerminalStatus());\n return;\n }\n\n return resolveTerminalStatusOverride()\n .then(cascadeTerminalStatus)\n .catch((err) => {\n log.fail(err);\n });\n },\n\n fail(err: unknown) {\n if (finalized) return;\n finalized = true;\n const errorMessage = serializeError(err);\n\n // Cascade `failed` to every still-started namespace. Children\n // that had already entered a terminal state are left untouched\n // by the dedup guard in `emit`.\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, \"failed\");\n }\n\n emit([], \"failed\", { error: errorMessage });\n log.fail(err);\n },\n };\n\n return transformer;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecycle.cjs","names":["hasPrefix","StreamChannel","nsKey"],"sources":["../../../src/stream/transformers/lifecycle.ts"],"sourcesContent":["/**\n * LifecycleTransformer - synthesizes `lifecycle` channel events that\n * track the status of the root run and every subgraph it spawns.\n *\n * The transformer is registered first in `createGraphRunStream` so that\n * every other transformer / consumer sees a coherent, authoritative\n * lifecycle stream. It is product-agnostic: deeper semantics (e.g.\n * DeepAgents' `SubagentTransformer` tool-call causation) reach the wire\n * by way of the re-entrant {@link StreamEmitter} - the transformer\n * stashes any `cause` attached upstream and re-emits its own\n * authoritative `lifecycle.started` with the correlation in place.\n *\n * Events are also pushed to a local {@link StreamChannel} so in-process\n * consumers can iterate `run.lifecycle` without filtering the main\n * event stream.\n */\n\nimport type {\n AgentStatus,\n LifecycleCause,\n LifecycleData,\n} from \"@langchain/protocol\";\n\nimport { hasPrefix, nsKey } from \"../mux.js\";\nimport { StreamChannel } from \"../stream-channel.js\";\nimport type {\n NativeStreamTransformer,\n Namespace,\n ProtocolEvent,\n StreamEmitter,\n} from \"../types.js\";\nimport type { LifecycleEntry, LifecycleTransformerOptions } from \"./types.js\";\n\n/**\n * Projection returned from the lifecycle transformer's `init()`.\n *\n * The local `StreamChannel` is closed automatically when the transformer\n * finalizes or fails. `_lifecycleLog` is intentionally underscore-prefixed to\n * signal that it is consumed by the run stream wiring\n * (see `run-stream.ts`) and not meant for direct user access -\n * consumers should read `run.lifecycle` instead.\n *\n * The `lifecycle` iterable is the root-scoped projection (prefix\n * `[]`, starting at offset `0`) mirroring the pattern used by the\n * subgraph discovery transformer. Root stream wiring consumes it\n * via `SET_LIFECYCLE_ITERABLE`; child streams are wired with their\n * own path-scoped iterable produced by `filterLifecycleEntries`.\n */\nexport interface LifecycleProjection {\n _lifecycleLog: StreamChannel<LifecycleEntry>;\n lifecycle: AsyncIterable<LifecycleEntry>;\n}\n\n/**\n * Filter a lifecycle {@link StreamChannel} to only the entries whose\n * namespace lies within the subtree rooted at {@link path}.\n *\n * Returns an `AsyncIterable` whose iterator yields every entry whose\n * namespace either equals {@link path} or is a descendant of it.\n * Iteration begins at {@link startAt}, so callers can capture the\n * log's current size at construction time to skip entries emitted\n * before the caller existed (e.g. a subgraph stream discovered\n * mid-run shouldn't replay the root's `started`).\n *\n * @param log - The shared lifecycle log owned by the transformer.\n * @param path - Namespace prefix to scope entries by (use `[]` for\n * the root subtree, i.e. everything).\n * @param startAt - Zero-based index into the log to begin from.\n * @returns An async iterable of matching lifecycle entries.\n */\nexport function filterLifecycleEntries(\n log: StreamChannel<LifecycleEntry>,\n path: Namespace,\n startAt = 0\n): AsyncIterable<LifecycleEntry> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<LifecycleEntry> {\n const base = log.iterate(startAt);\n return {\n async next(): Promise<IteratorResult<LifecycleEntry>> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const result = await base.next();\n if (result.done) {\n return {\n value: undefined as unknown as LifecycleEntry,\n done: true,\n };\n }\n if (hasPrefix(result.value.namespace, path)) {\n return { value: result.value, done: false };\n }\n }\n },\n };\n },\n };\n}\n\nconst DEFAULT_ROOT_GRAPH_NAME = \"root\";\n\nfunction defaultGuessGraphName(ns: Namespace): string {\n if (ns.length === 0) return DEFAULT_ROOT_GRAPH_NAME;\n const last = ns[ns.length - 1];\n const colon = last.indexOf(\":\");\n return colon === -1 ? last : last.slice(0, colon);\n}\n\nfunction defaultSerializeError(err: unknown): string {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (err instanceof Error) return err.message;\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Extract an upstream `cause` from a `lifecycle.started` payload, if\n * the shape matches one of the known variants. Shape validation is\n * intentionally loose: any object with a string `type` is accepted, so\n * future protocol variants flow through unchanged.\n */\nfunction extractCause(data: unknown): LifecycleCause | undefined {\n if (!isRecord(data)) return undefined;\n if (data.event !== \"started\") return undefined;\n const cause = data.cause;\n if (!isRecord(cause)) return undefined;\n if (typeof cause.type !== \"string\") return undefined;\n return cause as unknown as LifecycleCause;\n}\n\nfunction extractTaskResultCompletion(\n data: unknown\n): TaskResultCompletion | undefined {\n if (!isRecord(data)) return undefined;\n if (!(\"result\" in data)) return undefined;\n if (typeof data.name !== \"string\") return undefined;\n if (typeof data.id !== \"string\") return undefined;\n if (data.name.startsWith(\"__\")) return undefined;\n return { name: data.name, id: data.id };\n}\n\ninterface NamespaceRecord {\n readonly namespace: Namespace;\n readonly graphName: string;\n /** Last emitted status; `undefined` until `emit` fires for this namespace. */\n status: AgentStatus | undefined;\n}\n\ninterface TaskResultCompletion {\n readonly name: string;\n readonly id: string;\n}\n\ninterface PendingCompletion {\n readonly namespace: Namespace;\n readonly source:\n | { readonly type: \"task\" }\n | {\n readonly type: \"node\";\n readonly parent: Namespace;\n readonly node: string;\n };\n}\n\n/**\n * Create the built-in lifecycle transformer.\n *\n * Marked as a {@link NativeStreamTransformer} so the run stream\n * factory can expose `_lifecycleLog` via a dedicated getter\n * (`run.lifecycle`) rather than through `run.extensions`.\n */\nexport function createLifecycleTransformer(\n options: LifecycleTransformerOptions = {}\n): NativeStreamTransformer<LifecycleProjection> {\n const rootGraphName = options.rootGraphName ?? DEFAULT_ROOT_GRAPH_NAME;\n const initialStatus: AgentStatus = options.initialStatus ?? \"running\";\n const emitRootOnRegister = options.emitRootOnRegister ?? true;\n const getGraphName = options.getGraphName ?? defaultGuessGraphName;\n const serializeError = options.serializeError ?? defaultSerializeError;\n const getTerminalStatusOverride = options.getTerminalStatusOverride;\n\n const log = StreamChannel.local<LifecycleEntry>();\n const namespaces = new Map<string, NamespaceRecord>();\n const namespaceCause = new Map<string, LifecycleCause>();\n /**\n * `lc_agent_name` observed at each namespace (first task event wins). A\n * nested run carrying an `lc_agent_name` (set by `createAgent`) is treated\n * as a named subagent: its `graph_name` becomes that name and a tool-call\n * `cause` is recovered (see {@link deriveToolCallCause}). Namespaces without\n * one fall back to the parsed namespace segment, preserving the prior\n * product-agnostic behavior for plain subgraphs.\n */\n const lcByNs = new Map<string, string | undefined>();\n /**\n * Pregel task id -> triggering LLM `tool_call_id`, harvested from a task\n * whose `input` is a `tool_call_with_context` dict (current shape) or a list\n * of tool-call dicts (legacy shape). The child subgraph's namespace segment\n * `node:<task_id>` shares this task id, so a named subagent recovers the tool\n * call that spawned it across payloads.\n */\n const pendingToolCalls = new Map<string, string>();\n const pendingInterruptIds = new Set<string>();\n /**\n * Child namespaces whose parent just saw an `updates` event with a\n * `node` attribution. We defer the `lifecycle.completed` emission\n * until the *next* inbound event (or `finalize`) so the parent's\n * `updates` lands on the wire before its child is marked complete -\n * matching the previous session behavior.\n */\n const pendingCompletions: PendingCompletion[] = [];\n\n let emitter: StreamEmitter | undefined;\n let inSelfEmit = 0;\n let finalized = false;\n\n const resolveGraphName = (ns: Namespace): string => {\n if (ns.length === 0) return rootGraphName;\n // A nested run that carried an `lc_agent_name` is a named subagent; its\n // agent name wins over the parsed namespace segment.\n const lc = lcByNs.get(nsKey(ns));\n if (typeof lc === \"string\" && lc.length > 0) return lc;\n return getGraphName(ns);\n };\n\n /**\n * Record a namespace's `lc_agent_name` from a task-start payload (first\n * event wins). The presence of a name is what marks the namespace a named\n * subagent; the value may be `undefined` for unnamed runs (still recorded so\n * a later event doesn't re-evaluate it).\n */\n const recordIdentity = (ns: Namespace, data: unknown): void => {\n const key = nsKey(ns);\n if (lcByNs.has(key)) return;\n const metadata =\n isRecord(data) && isRecord(data.metadata) ? data.metadata : undefined;\n const lc = metadata?.lc_agent_name;\n lcByNs.set(key, typeof lc === \"string\" ? lc : undefined);\n };\n\n /**\n * Harvest a task's triggering `tool_call_id` keyed by its task id. The\n * spawned subgraph's namespace segment `node:<task_id>` shares that id, so a\n * subagent can later recover the tool call that caused it. Two input shapes\n * are handled: a `tool_call_with_context` object (`input.tool_call.id`) and a\n * legacy list of tool-call objects (first with a string `id`).\n */\n const recordPendingToolCalls = (data: unknown): void => {\n if (!isRecord(data)) return;\n const taskId = data.id;\n if (typeof taskId !== \"string\") return;\n const input = data.input;\n let toolCallId: string | undefined;\n if (isRecord(input) && isRecord(input.tool_call)) {\n const candidate = input.tool_call.id;\n if (typeof candidate === \"string\") toolCallId = candidate;\n } else if (Array.isArray(input)) {\n for (const toolCall of input) {\n if (isRecord(toolCall) && typeof toolCall.id === \"string\") {\n toolCallId = toolCall.id;\n break;\n }\n }\n }\n if (toolCallId != null) pendingToolCalls.set(taskId, toolCallId);\n };\n\n /**\n * Derive a `toolCall` cause for a named subagent namespace by joining the\n * namespace segment's task id (`node:<task_id>`) to a previously harvested\n * `tool_call_id`. Only fires for namespaces carrying an `lc_agent_name`, so\n * plain subgraphs never get a spurious cause.\n */\n const deriveToolCallCause = (ns: Namespace): LifecycleCause | undefined => {\n if (ns.length === 0) return undefined;\n const lc = lcByNs.get(nsKey(ns));\n if (typeof lc !== \"string\" || lc.length === 0) return undefined;\n const segment = ns[ns.length - 1];\n const colon = segment.indexOf(\":\");\n if (colon === -1) return undefined;\n const triggerCallId = segment.slice(colon + 1);\n if (triggerCallId.length === 0) return undefined;\n const toolCallId = pendingToolCalls.get(triggerCallId);\n if (typeof toolCallId !== \"string\" || toolCallId.length === 0) {\n return undefined;\n }\n return { type: \"toolCall\", tool_call_id: toolCallId };\n };\n\n /**\n * Resolve the `cause` to attach to a namespace's `started`. An upstream\n * `cause` stashed from a product-specific transformer (e.g. deepagents'\n * SubagentTransformer) wins; otherwise a tool-call cause is recovered for\n * named subagents.\n */\n const resolveStartCause = (ns: Namespace): LifecycleCause | undefined =>\n namespaceCause.get(nsKey(ns)) ?? deriveToolCallCause(ns);\n\n const emit = (\n ns: Namespace,\n status: AgentStatus,\n extras?: { cause?: LifecycleCause; error?: string }\n ): void => {\n const key = nsKey(ns);\n let current = namespaces.get(key);\n const graphName = current?.graphName ?? resolveGraphName(ns);\n\n // Dedup: identical status + graph name + no error override => skip.\n if (\n current != null &&\n current.status === status &&\n current.graphName === graphName &&\n extras?.error == null\n ) {\n return;\n }\n\n if (current == null) {\n current = { namespace: ns, graphName, status };\n namespaces.set(key, current);\n } else {\n current.status = status;\n }\n\n const data: LifecycleData = {\n event: status,\n graph_name: graphName,\n ...(extras?.cause != null ? { cause: extras.cause } : {}),\n ...(extras?.error != null ? { error: extras.error } : {}),\n };\n\n const timestamp = Date.now();\n\n log.push({ namespace: ns, timestamp, ...data });\n\n if (ns.length === 0 && !emitRootOnRegister) return;\n\n if (emitter == null) return;\n\n inSelfEmit += 1;\n try {\n emitter.push(ns, {\n type: \"event\",\n seq: 0,\n method: \"lifecycle\",\n params: { namespace: ns, timestamp, data },\n });\n } finally {\n inSelfEmit -= 1;\n }\n };\n\n /**\n * Ensures a record exists for `ns` without mutating its status. Used\n * by hooks that need a canonical `graphName` for lookups before emit\n * writes the first status. Status remains `undefined` until `emit`\n * fires.\n */\n const trackNamespace = (ns: Namespace): NamespaceRecord => {\n const key = nsKey(ns);\n let rec = namespaces.get(key);\n if (rec == null) {\n rec = {\n namespace: ns,\n graphName: resolveGraphName(ns),\n status: undefined,\n };\n namespaces.set(key, rec);\n }\n return rec;\n };\n\n const flushPendingCompletions = (): void => {\n if (pendingCompletions.length === 0) return;\n const toFlush = pendingCompletions.splice(0, pendingCompletions.length);\n for (const completion of toFlush) {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") continue;\n emit(completion.namespace, \"completed\");\n }\n };\n\n const enqueueCompletion = (completion: PendingCompletion): void => {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") return;\n if (\n pendingCompletions.some((pending) => nsKey(pending.namespace) === key)\n ) {\n return;\n }\n pendingCompletions.push(completion);\n };\n\n const removePendingNodeCompletions = (\n parent: Namespace,\n node: string\n ): void => {\n for (let index = pendingCompletions.length - 1; index >= 0; index -= 1) {\n const pending = pendingCompletions[index];\n if (pending.source.type !== \"node\") continue;\n if (pending.source.node !== node) continue;\n if (nsKey(pending.source.parent) !== nsKey(parent)) continue;\n pendingCompletions.splice(index, 1);\n }\n };\n\n const ensureStarted = (ns: Namespace): void => {\n // Synthesize `lifecycle.started` for each unseen prefix of `ns`,\n // outermost first. Deepest-first would force consumers to see a\n // child's started before its parent, which is wrong.\n for (let length = 1; length <= ns.length; length += 1) {\n const prefix = ns.slice(0, length);\n const key = nsKey(prefix);\n if (namespaces.has(key)) continue;\n trackNamespace(prefix);\n const cause = resolveStartCause(prefix);\n emit(prefix, \"started\", cause != null ? { cause } : undefined);\n }\n };\n\n const defaultTerminalStatus = (): AgentStatus =>\n pendingInterruptIds.size > 0 ? \"interrupted\" : \"completed\";\n\n const cascadeTerminalStatus = (status: AgentStatus): void => {\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, status);\n }\n emit([], status);\n log.close();\n };\n\n const resolveTerminalStatusOverride = async (): Promise<AgentStatus> => {\n if (getTerminalStatusOverride == null) return defaultTerminalStatus();\n try {\n return (await getTerminalStatusOverride()) ?? defaultTerminalStatus();\n } catch {\n return defaultTerminalStatus();\n }\n };\n\n const findStartedChildForNode = (\n parentNamespace: Namespace,\n node: string\n ): Namespace | undefined => {\n const prefix = `${node}:`;\n for (const rec of namespaces.values()) {\n if (rec.namespace.length !== parentNamespace.length + 1) continue;\n if (rec.status !== \"started\") continue;\n if (!hasPrefix(rec.namespace, parentNamespace)) continue;\n const last = rec.namespace[rec.namespace.length - 1];\n if (last === node || last.startsWith(prefix)) return rec.namespace;\n }\n return undefined;\n };\n\n const findStartedChildForTask = (\n parentNamespace: Namespace,\n task: TaskResultCompletion\n ): Namespace | undefined => {\n const namespace = [...parentNamespace, `${task.name}:${task.id}`];\n const rec = namespaces.get(nsKey(namespace));\n return rec?.status === \"started\" ? namespace : undefined;\n };\n\n const transformer: NativeStreamTransformer<LifecycleProjection> = {\n __native: true,\n\n init() {\n return {\n _lifecycleLog: log,\n lifecycle: filterLifecycleEntries(log, [], 0),\n };\n },\n\n onRegister(handle: StreamEmitter) {\n emitter = handle;\n // Seed root record so cascade logic can see it, even when the\n // outer authority owns root emission.\n trackNamespace([]);\n if (emitRootOnRegister) {\n emit([], initialStatus);\n }\n },\n\n process(event: ProtocolEvent): boolean {\n const ns = event.params.namespace;\n\n // Re-entrant loopback: an event we emitted via `emitter.push`\n // is being routed back through this transformer by the mux.\n // Allow it through the wire unchanged.\n if (inSelfEmit > 0) return true;\n\n const taskCompletion =\n event.method === \"tasks\"\n ? extractTaskResultCompletion(event.params.data)\n : undefined;\n if (taskCompletion != null) {\n // Prefer exact task-result attribution over any ambiguous\n // `updates.node` completion deferred from the previous event.\n removePendingNodeCompletions(ns, taskCompletion.name);\n } else if (event.method === \"tasks\") {\n // Task-start event: record the namespace's subagent identity and any\n // triggering tool call *before* `ensureStarted` synthesizes `started`,\n // so a named subagent's `graph_name`/`cause` are resolved in time.\n // Pregel emits parent-namespace tasks before child-namespace tasks, so\n // the parent's tool-call seed is in place when the child is evaluated.\n recordIdentity(ns, event.params.data);\n recordPendingToolCalls(event.params.data);\n }\n\n // Flush any completions deferred by the previous event so the\n // wire order is [triggering event] -> [deferred completed].\n flushPendingCompletions();\n\n // Upstream `lifecycle` events: stash any `cause` attached by a\n // product-specific transformer (e.g. deepagents' SubagentTransformer),\n // synthesize our authoritative started/... for the namespace, and\n // suppress the original so we are the single source of truth.\n if (event.method === \"lifecycle\") {\n const cause = extractCause(event.params.data);\n if (cause != null) {\n namespaceCause.set(nsKey(ns), cause);\n }\n ensureStarted(ns);\n return false;\n }\n\n // Lifecycle for parent + any unseen prefix => synthesize started.\n ensureStarted(ns);\n\n // Track interrupt ids so `finalize` can decide between\n // `completed` and `interrupted`.\n if (\n event.method === \"input\" &&\n isRecord(event.params.data) &&\n event.params.data.event === \"requested\"\n ) {\n const id = (event.params.data as { id?: unknown }).id;\n if (typeof id === \"string\") {\n pendingInterruptIds.add(id);\n }\n }\n\n if (taskCompletion != null) {\n const childNamespace = findStartedChildForTask(ns, taskCompletion);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"task\" },\n });\n }\n }\n\n // Defer child-node completion: the `updates` event carries the\n // node attribution; the corresponding child namespace is\n // `[...ns, \"<node>:<uuid>\"]`. We pick the oldest still-started\n // matching child (LangGraph emits one updates per completed task\n // so repeated calls drain parallel fan-outs in order).\n if (event.method === \"updates\") {\n const node = event.params.node;\n if (typeof node === \"string\" && !node.startsWith(\"__\")) {\n const childNamespace = findStartedChildForNode(ns, node);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"node\", parent: ns, node },\n });\n }\n }\n }\n\n return true;\n },\n\n finalize(): void | PromiseLike<void> {\n if (finalized) return;\n finalized = true;\n flushPendingCompletions();\n\n if (getTerminalStatusOverride == null) {\n cascadeTerminalStatus(defaultTerminalStatus());\n return;\n }\n\n return resolveTerminalStatusOverride()\n .then(cascadeTerminalStatus)\n .catch((err) => {\n log.fail(err);\n });\n },\n\n fail(err: unknown) {\n if (finalized) return;\n finalized = true;\n const errorMessage = serializeError(err);\n\n // Cascade `failed` to every still-started namespace. Children\n // that had already entered a terminal state are left untouched\n // by the dedup guard in `emit`.\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, \"failed\");\n }\n\n emit([], \"failed\", { error: errorMessage });\n log.fail(err);\n },\n };\n\n return transformer;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsEA,SAAgB,uBACd,KACA,MACA,UAAU,GACqB;AAC/B,QAAO,EACL,CAAC,OAAO,iBAAgD;EACtD,MAAM,OAAO,IAAI,QAAQ,QAAQ;AACjC,SAAO,EACL,MAAM,OAAgD;AAEpD,UAAO,MAAM;IACX,MAAM,SAAS,MAAM,KAAK,MAAM;AAChC,QAAI,OAAO,KACT,QAAO;KACL,OAAO,KAAA;KACP,MAAM;KACP;AAEH,QAAIA,YAAAA,UAAU,OAAO,MAAM,WAAW,KAAK,CACzC,QAAO;KAAE,OAAO,OAAO;KAAO,MAAM;KAAO;;KAIlD;IAEJ;;AAGH,MAAM,0BAA0B;AAEhC,SAAS,sBAAsB,IAAuB;AACpD,KAAI,GAAG,WAAW,EAAG,QAAO;CAC5B,MAAM,OAAO,GAAG,GAAG,SAAS;CAC5B,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC/B,QAAO,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,MAAM;;AAGnD,SAAS,sBAAsB,KAAsB;AAEnD,KAAI,eAAe,MAAO,QAAO,IAAI;AACrC,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;AACF,SAAO,KAAK,UAAU,IAAI;SACpB;AACN,SAAO,OAAO,IAAI;;;AAItB,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;;;;;AAS7E,SAAS,aAAa,MAA2C;AAC/D,KAAI,CAAC,SAAS,KAAK,CAAE,QAAO,KAAA;AAC5B,KAAI,KAAK,UAAU,UAAW,QAAO,KAAA;CACrC,MAAM,QAAQ,KAAK;AACnB,KAAI,CAAC,SAAS,MAAM,CAAE,QAAO,KAAA;AAC7B,KAAI,OAAO,MAAM,SAAS,SAAU,QAAO,KAAA;AAC3C,QAAO;;AAGT,SAAS,4BACP,MACkC;AAClC,KAAI,CAAC,SAAS,KAAK,CAAE,QAAO,KAAA;AAC5B,KAAI,EAAE,YAAY,MAAO,QAAO,KAAA;AAChC,KAAI,OAAO,KAAK,SAAS,SAAU,QAAO,KAAA;AAC1C,KAAI,OAAO,KAAK,OAAO,SAAU,QAAO,KAAA;AACxC,KAAI,KAAK,KAAK,WAAW,KAAK,CAAE,QAAO,KAAA;AACvC,QAAO;EAAE,MAAM,KAAK;EAAM,IAAI,KAAK;EAAI;;;;;;;;;AAiCzC,SAAgB,2BACd,UAAuC,EAAE,EACK;CAC9C,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,gBAA6B,QAAQ,iBAAiB;CAC5D,MAAM,qBAAqB,QAAQ,sBAAsB;CACzD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,4BAA4B,QAAQ;CAE1C,MAAM,MAAMC,uBAAAA,cAAc,OAAuB;CACjD,MAAM,6BAAa,IAAI,KAA8B;CACrD,MAAM,iCAAiB,IAAI,KAA6B;;;;;;;;;CASxD,MAAM,yBAAS,IAAI,KAAiC;;;;;;;;CAQpD,MAAM,mCAAmB,IAAI,KAAqB;CAClD,MAAM,sCAAsB,IAAI,KAAa;;;;;;;;CAQ7C,MAAM,qBAA0C,EAAE;CAElD,IAAI;CACJ,IAAI,aAAa;CACjB,IAAI,YAAY;CAEhB,MAAM,oBAAoB,OAA0B;AAClD,MAAI,GAAG,WAAW,EAAG,QAAO;EAG5B,MAAM,KAAK,OAAO,IAAIC,YAAAA,MAAM,GAAG,CAAC;AAChC,MAAI,OAAO,OAAO,YAAY,GAAG,SAAS,EAAG,QAAO;AACpD,SAAO,aAAa,GAAG;;;;;;;;CASzB,MAAM,kBAAkB,IAAe,SAAwB;EAC7D,MAAM,MAAMA,YAAAA,MAAM,GAAG;AACrB,MAAI,OAAO,IAAI,IAAI,CAAE;EAGrB,MAAM,MADJ,SAAS,KAAK,IAAI,SAAS,KAAK,SAAS,GAAG,KAAK,WAAW,KAAA,IACzC;AACrB,SAAO,IAAI,KAAK,OAAO,OAAO,WAAW,KAAK,KAAA,EAAU;;;;;;;;;CAU1D,MAAM,0BAA0B,SAAwB;AACtD,MAAI,CAAC,SAAS,KAAK,CAAE;EACrB,MAAM,SAAS,KAAK;AACpB,MAAI,OAAO,WAAW,SAAU;EAChC,MAAM,QAAQ,KAAK;EACnB,IAAI;AACJ,MAAI,SAAS,MAAM,IAAI,SAAS,MAAM,UAAU,EAAE;GAChD,MAAM,YAAY,MAAM,UAAU;AAClC,OAAI,OAAO,cAAc,SAAU,cAAa;aACvC,MAAM,QAAQ,MAAM;QACxB,MAAM,YAAY,MACrB,KAAI,SAAS,SAAS,IAAI,OAAO,SAAS,OAAO,UAAU;AACzD,iBAAa,SAAS;AACtB;;;AAIN,MAAI,cAAc,KAAM,kBAAiB,IAAI,QAAQ,WAAW;;;;;;;;CASlE,MAAM,uBAAuB,OAA8C;AACzE,MAAI,GAAG,WAAW,EAAG,QAAO,KAAA;EAC5B,MAAM,KAAK,OAAO,IAAIA,YAAAA,MAAM,GAAG,CAAC;AAChC,MAAI,OAAO,OAAO,YAAY,GAAG,WAAW,EAAG,QAAO,KAAA;EACtD,MAAM,UAAU,GAAG,GAAG,SAAS;EAC/B,MAAM,QAAQ,QAAQ,QAAQ,IAAI;AAClC,MAAI,UAAU,GAAI,QAAO,KAAA;EACzB,MAAM,gBAAgB,QAAQ,MAAM,QAAQ,EAAE;AAC9C,MAAI,cAAc,WAAW,EAAG,QAAO,KAAA;EACvC,MAAM,aAAa,iBAAiB,IAAI,cAAc;AACtD,MAAI,OAAO,eAAe,YAAY,WAAW,WAAW,EAC1D;AAEF,SAAO;GAAE,MAAM;GAAY,cAAc;GAAY;;;;;;;;CASvD,MAAM,qBAAqB,OACzB,eAAe,IAAIA,YAAAA,MAAM,GAAG,CAAC,IAAI,oBAAoB,GAAG;CAE1D,MAAM,QACJ,IACA,QACA,WACS;EACT,MAAM,MAAMA,YAAAA,MAAM,GAAG;EACrB,IAAI,UAAU,WAAW,IAAI,IAAI;EACjC,MAAM,YAAY,SAAS,aAAa,iBAAiB,GAAG;AAG5D,MACE,WAAW,QACX,QAAQ,WAAW,UACnB,QAAQ,cAAc,aACtB,QAAQ,SAAS,KAEjB;AAGF,MAAI,WAAW,MAAM;AACnB,aAAU;IAAE,WAAW;IAAI;IAAW;IAAQ;AAC9C,cAAW,IAAI,KAAK,QAAQ;QAE5B,SAAQ,SAAS;EAGnB,MAAM,OAAsB;GAC1B,OAAO;GACP,YAAY;GACZ,GAAI,QAAQ,SAAS,OAAO,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE;GACxD,GAAI,QAAQ,SAAS,OAAO,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE;GACzD;EAED,MAAM,YAAY,KAAK,KAAK;AAE5B,MAAI,KAAK;GAAE,WAAW;GAAI;GAAW,GAAG;GAAM,CAAC;AAE/C,MAAI,GAAG,WAAW,KAAK,CAAC,mBAAoB;AAE5C,MAAI,WAAW,KAAM;AAErB,gBAAc;AACd,MAAI;AACF,WAAQ,KAAK,IAAI;IACf,MAAM;IACN,KAAK;IACL,QAAQ;IACR,QAAQ;KAAE,WAAW;KAAI;KAAW;KAAM;IAC3C,CAAC;YACM;AACR,iBAAc;;;;;;;;;CAUlB,MAAM,kBAAkB,OAAmC;EACzD,MAAM,MAAMA,YAAAA,MAAM,GAAG;EACrB,IAAI,MAAM,WAAW,IAAI,IAAI;AAC7B,MAAI,OAAO,MAAM;AACf,SAAM;IACJ,WAAW;IACX,WAAW,iBAAiB,GAAG;IAC/B,QAAQ,KAAA;IACT;AACD,cAAW,IAAI,KAAK,IAAI;;AAE1B,SAAO;;CAGT,MAAM,gCAAsC;AAC1C,MAAI,mBAAmB,WAAW,EAAG;EACrC,MAAM,UAAU,mBAAmB,OAAO,GAAG,mBAAmB,OAAO;AACvE,OAAK,MAAM,cAAc,SAAS;GAChC,MAAM,MAAMA,YAAAA,MAAM,WAAW,UAAU;GACvC,MAAM,MAAM,WAAW,IAAI,IAAI;AAC/B,OAAI,OAAO,QAAQ,IAAI,WAAW,UAAW;AAC7C,QAAK,WAAW,WAAW,YAAY;;;CAI3C,MAAM,qBAAqB,eAAwC;EACjE,MAAM,MAAMA,YAAAA,MAAM,WAAW,UAAU;EACvC,MAAM,MAAM,WAAW,IAAI,IAAI;AAC/B,MAAI,OAAO,QAAQ,IAAI,WAAW,UAAW;AAC7C,MACE,mBAAmB,MAAM,YAAYA,YAAAA,MAAM,QAAQ,UAAU,KAAK,IAAI,CAEtE;AAEF,qBAAmB,KAAK,WAAW;;CAGrC,MAAM,gCACJ,QACA,SACS;AACT,OAAK,IAAI,QAAQ,mBAAmB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;GACtE,MAAM,UAAU,mBAAmB;AACnC,OAAI,QAAQ,OAAO,SAAS,OAAQ;AACpC,OAAI,QAAQ,OAAO,SAAS,KAAM;AAClC,OAAIA,YAAAA,MAAM,QAAQ,OAAO,OAAO,KAAKA,YAAAA,MAAM,OAAO,CAAE;AACpD,sBAAmB,OAAO,OAAO,EAAE;;;CAIvC,MAAM,iBAAiB,OAAwB;AAI7C,OAAK,IAAI,SAAS,GAAG,UAAU,GAAG,QAAQ,UAAU,GAAG;GACrD,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO;GAClC,MAAM,MAAMA,YAAAA,MAAM,OAAO;AACzB,OAAI,WAAW,IAAI,IAAI,CAAE;AACzB,kBAAe,OAAO;GACtB,MAAM,QAAQ,kBAAkB,OAAO;AACvC,QAAK,QAAQ,WAAW,SAAS,OAAO,EAAE,OAAO,GAAG,KAAA,EAAU;;;CAIlE,MAAM,8BACJ,oBAAoB,OAAO,IAAI,gBAAgB;CAEjD,MAAM,yBAAyB,WAA8B;AAC3D,OAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,OAAI,IAAI,UAAU,WAAW,EAAG;AAChC,OAAI,IAAI,WAAW,UAAW;AAC9B,QAAK,IAAI,WAAW,OAAO;;AAE7B,OAAK,EAAE,EAAE,OAAO;AAChB,MAAI,OAAO;;CAGb,MAAM,gCAAgC,YAAkC;AACtE,MAAI,6BAA6B,KAAM,QAAO,uBAAuB;AACrE,MAAI;AACF,UAAQ,MAAM,2BAA2B,IAAK,uBAAuB;UAC/D;AACN,UAAO,uBAAuB;;;CAIlC,MAAM,2BACJ,iBACA,SAC0B;EAC1B,MAAM,SAAS,GAAG,KAAK;AACvB,OAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,OAAI,IAAI,UAAU,WAAW,gBAAgB,SAAS,EAAG;AACzD,OAAI,IAAI,WAAW,UAAW;AAC9B,OAAI,CAACF,YAAAA,UAAU,IAAI,WAAW,gBAAgB,CAAE;GAChD,MAAM,OAAO,IAAI,UAAU,IAAI,UAAU,SAAS;AAClD,OAAI,SAAS,QAAQ,KAAK,WAAW,OAAO,CAAE,QAAO,IAAI;;;CAK7D,MAAM,2BACJ,iBACA,SAC0B;EAC1B,MAAM,YAAY,CAAC,GAAG,iBAAiB,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK;AAEjE,SADY,WAAW,IAAIE,YAAAA,MAAM,UAAU,CAAC,EAChC,WAAW,YAAY,YAAY,KAAA;;AAqJjD,QAlJkE;EAChE,UAAU;EAEV,OAAO;AACL,UAAO;IACL,eAAe;IACf,WAAW,uBAAuB,KAAK,EAAE,EAAE,EAAE;IAC9C;;EAGH,WAAW,QAAuB;AAChC,aAAU;AAGV,kBAAe,EAAE,CAAC;AAClB,OAAI,mBACF,MAAK,EAAE,EAAE,cAAc;;EAI3B,QAAQ,OAA+B;GACrC,MAAM,KAAK,MAAM,OAAO;AAKxB,OAAI,aAAa,EAAG,QAAO;GAE3B,MAAM,iBACJ,MAAM,WAAW,UACb,4BAA4B,MAAM,OAAO,KAAK,GAC9C,KAAA;AACN,OAAI,kBAAkB,KAGpB,8BAA6B,IAAI,eAAe,KAAK;YAC5C,MAAM,WAAW,SAAS;AAMnC,mBAAe,IAAI,MAAM,OAAO,KAAK;AACrC,2BAAuB,MAAM,OAAO,KAAK;;AAK3C,4BAAyB;AAMzB,OAAI,MAAM,WAAW,aAAa;IAChC,MAAM,QAAQ,aAAa,MAAM,OAAO,KAAK;AAC7C,QAAI,SAAS,KACX,gBAAe,IAAIA,YAAAA,MAAM,GAAG,EAAE,MAAM;AAEtC,kBAAc,GAAG;AACjB,WAAO;;AAIT,iBAAc,GAAG;AAIjB,OACE,MAAM,WAAW,WACjB,SAAS,MAAM,OAAO,KAAK,IAC3B,MAAM,OAAO,KAAK,UAAU,aAC5B;IACA,MAAM,KAAM,MAAM,OAAO,KAA0B;AACnD,QAAI,OAAO,OAAO,SAChB,qBAAoB,IAAI,GAAG;;AAI/B,OAAI,kBAAkB,MAAM;IAC1B,MAAM,iBAAiB,wBAAwB,IAAI,eAAe;AAClE,QAAI,kBAAkB,KACpB,mBAAkB;KAChB,WAAW;KACX,QAAQ,EAAE,MAAM,QAAQ;KACzB,CAAC;;AASN,OAAI,MAAM,WAAW,WAAW;IAC9B,MAAM,OAAO,MAAM,OAAO;AAC1B,QAAI,OAAO,SAAS,YAAY,CAAC,KAAK,WAAW,KAAK,EAAE;KACtD,MAAM,iBAAiB,wBAAwB,IAAI,KAAK;AACxD,SAAI,kBAAkB,KACpB,mBAAkB;MAChB,WAAW;MACX,QAAQ;OAAE,MAAM;OAAQ,QAAQ;OAAI;OAAM;MAC3C,CAAC;;;AAKR,UAAO;;EAGT,WAAqC;AACnC,OAAI,UAAW;AACf,eAAY;AACZ,4BAAyB;AAEzB,OAAI,6BAA6B,MAAM;AACrC,0BAAsB,uBAAuB,CAAC;AAC9C;;AAGF,UAAO,+BAA+B,CACnC,KAAK,sBAAsB,CAC3B,OAAO,QAAQ;AACd,QAAI,KAAK,IAAI;KACb;;EAGN,KAAK,KAAc;AACjB,OAAI,UAAW;AACf,eAAY;GACZ,MAAM,eAAe,eAAe,IAAI;AAKxC,QAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,QAAI,IAAI,UAAU,WAAW,EAAG;AAChC,QAAI,IAAI,WAAW,UAAW;AAC9B,SAAK,IAAI,WAAW,SAAS;;AAG/B,QAAK,EAAE,EAAE,UAAU,EAAE,OAAO,cAAc,CAAC;AAC3C,OAAI,KAAK,IAAI;;EAEhB"}
|
|
@@ -97,6 +97,23 @@ function createLifecycleTransformer(options = {}) {
|
|
|
97
97
|
const log = StreamChannel.local();
|
|
98
98
|
const namespaces = /* @__PURE__ */ new Map();
|
|
99
99
|
const namespaceCause = /* @__PURE__ */ new Map();
|
|
100
|
+
/**
|
|
101
|
+
* `lc_agent_name` observed at each namespace (first task event wins). A
|
|
102
|
+
* nested run carrying an `lc_agent_name` (set by `createAgent`) is treated
|
|
103
|
+
* as a named subagent: its `graph_name` becomes that name and a tool-call
|
|
104
|
+
* `cause` is recovered (see {@link deriveToolCallCause}). Namespaces without
|
|
105
|
+
* one fall back to the parsed namespace segment, preserving the prior
|
|
106
|
+
* product-agnostic behavior for plain subgraphs.
|
|
107
|
+
*/
|
|
108
|
+
const lcByNs = /* @__PURE__ */ new Map();
|
|
109
|
+
/**
|
|
110
|
+
* Pregel task id -> triggering LLM `tool_call_id`, harvested from a task
|
|
111
|
+
* whose `input` is a `tool_call_with_context` dict (current shape) or a list
|
|
112
|
+
* of tool-call dicts (legacy shape). The child subgraph's namespace segment
|
|
113
|
+
* `node:<task_id>` shares this task id, so a named subagent recovers the tool
|
|
114
|
+
* call that spawned it across payloads.
|
|
115
|
+
*/
|
|
116
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
100
117
|
const pendingInterruptIds = /* @__PURE__ */ new Set();
|
|
101
118
|
/**
|
|
102
119
|
* Child namespaces whose parent just saw an `updates` event with a
|
|
@@ -109,7 +126,77 @@ function createLifecycleTransformer(options = {}) {
|
|
|
109
126
|
let emitter;
|
|
110
127
|
let inSelfEmit = 0;
|
|
111
128
|
let finalized = false;
|
|
112
|
-
const resolveGraphName = (ns) =>
|
|
129
|
+
const resolveGraphName = (ns) => {
|
|
130
|
+
if (ns.length === 0) return rootGraphName;
|
|
131
|
+
const lc = lcByNs.get(nsKey(ns));
|
|
132
|
+
if (typeof lc === "string" && lc.length > 0) return lc;
|
|
133
|
+
return getGraphName(ns);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Record a namespace's `lc_agent_name` from a task-start payload (first
|
|
137
|
+
* event wins). The presence of a name is what marks the namespace a named
|
|
138
|
+
* subagent; the value may be `undefined` for unnamed runs (still recorded so
|
|
139
|
+
* a later event doesn't re-evaluate it).
|
|
140
|
+
*/
|
|
141
|
+
const recordIdentity = (ns, data) => {
|
|
142
|
+
const key = nsKey(ns);
|
|
143
|
+
if (lcByNs.has(key)) return;
|
|
144
|
+
const lc = (isRecord(data) && isRecord(data.metadata) ? data.metadata : void 0)?.lc_agent_name;
|
|
145
|
+
lcByNs.set(key, typeof lc === "string" ? lc : void 0);
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Harvest a task's triggering `tool_call_id` keyed by its task id. The
|
|
149
|
+
* spawned subgraph's namespace segment `node:<task_id>` shares that id, so a
|
|
150
|
+
* subagent can later recover the tool call that caused it. Two input shapes
|
|
151
|
+
* are handled: a `tool_call_with_context` object (`input.tool_call.id`) and a
|
|
152
|
+
* legacy list of tool-call objects (first with a string `id`).
|
|
153
|
+
*/
|
|
154
|
+
const recordPendingToolCalls = (data) => {
|
|
155
|
+
if (!isRecord(data)) return;
|
|
156
|
+
const taskId = data.id;
|
|
157
|
+
if (typeof taskId !== "string") return;
|
|
158
|
+
const input = data.input;
|
|
159
|
+
let toolCallId;
|
|
160
|
+
if (isRecord(input) && isRecord(input.tool_call)) {
|
|
161
|
+
const candidate = input.tool_call.id;
|
|
162
|
+
if (typeof candidate === "string") toolCallId = candidate;
|
|
163
|
+
} else if (Array.isArray(input)) {
|
|
164
|
+
for (const toolCall of input) if (isRecord(toolCall) && typeof toolCall.id === "string") {
|
|
165
|
+
toolCallId = toolCall.id;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (toolCallId != null) pendingToolCalls.set(taskId, toolCallId);
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Derive a `toolCall` cause for a named subagent namespace by joining the
|
|
173
|
+
* namespace segment's task id (`node:<task_id>`) to a previously harvested
|
|
174
|
+
* `tool_call_id`. Only fires for namespaces carrying an `lc_agent_name`, so
|
|
175
|
+
* plain subgraphs never get a spurious cause.
|
|
176
|
+
*/
|
|
177
|
+
const deriveToolCallCause = (ns) => {
|
|
178
|
+
if (ns.length === 0) return void 0;
|
|
179
|
+
const lc = lcByNs.get(nsKey(ns));
|
|
180
|
+
if (typeof lc !== "string" || lc.length === 0) return void 0;
|
|
181
|
+
const segment = ns[ns.length - 1];
|
|
182
|
+
const colon = segment.indexOf(":");
|
|
183
|
+
if (colon === -1) return void 0;
|
|
184
|
+
const triggerCallId = segment.slice(colon + 1);
|
|
185
|
+
if (triggerCallId.length === 0) return void 0;
|
|
186
|
+
const toolCallId = pendingToolCalls.get(triggerCallId);
|
|
187
|
+
if (typeof toolCallId !== "string" || toolCallId.length === 0) return;
|
|
188
|
+
return {
|
|
189
|
+
type: "toolCall",
|
|
190
|
+
tool_call_id: toolCallId
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Resolve the `cause` to attach to a namespace's `started`. An upstream
|
|
195
|
+
* `cause` stashed from a product-specific transformer (e.g. deepagents'
|
|
196
|
+
* SubagentTransformer) wins; otherwise a tool-call cause is recovered for
|
|
197
|
+
* named subagents.
|
|
198
|
+
*/
|
|
199
|
+
const resolveStartCause = (ns) => namespaceCause.get(nsKey(ns)) ?? deriveToolCallCause(ns);
|
|
113
200
|
const emit = (ns, status, extras) => {
|
|
114
201
|
const key = nsKey(ns);
|
|
115
202
|
let current = namespaces.get(key);
|
|
@@ -204,7 +291,7 @@ function createLifecycleTransformer(options = {}) {
|
|
|
204
291
|
const key = nsKey(prefix);
|
|
205
292
|
if (namespaces.has(key)) continue;
|
|
206
293
|
trackNamespace(prefix);
|
|
207
|
-
const cause =
|
|
294
|
+
const cause = resolveStartCause(prefix);
|
|
208
295
|
emit(prefix, "started", cause != null ? { cause } : void 0);
|
|
209
296
|
}
|
|
210
297
|
};
|
|
@@ -258,6 +345,10 @@ function createLifecycleTransformer(options = {}) {
|
|
|
258
345
|
if (inSelfEmit > 0) return true;
|
|
259
346
|
const taskCompletion = event.method === "tasks" ? extractTaskResultCompletion(event.params.data) : void 0;
|
|
260
347
|
if (taskCompletion != null) removePendingNodeCompletions(ns, taskCompletion.name);
|
|
348
|
+
else if (event.method === "tasks") {
|
|
349
|
+
recordIdentity(ns, event.params.data);
|
|
350
|
+
recordPendingToolCalls(event.params.data);
|
|
351
|
+
}
|
|
261
352
|
flushPendingCompletions();
|
|
262
353
|
if (event.method === "lifecycle") {
|
|
263
354
|
const cause = extractCause(event.params.data);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","names":[],"sources":["../../../src/stream/transformers/lifecycle.ts"],"sourcesContent":["/**\n * LifecycleTransformer - synthesizes `lifecycle` channel events that\n * track the status of the root run and every subgraph it spawns.\n *\n * The transformer is registered first in `createGraphRunStream` so that\n * every other transformer / consumer sees a coherent, authoritative\n * lifecycle stream. It is product-agnostic: deeper semantics (e.g.\n * DeepAgents' `SubagentTransformer` tool-call causation) reach the wire\n * by way of the re-entrant {@link StreamEmitter} - the transformer\n * stashes any `cause` attached upstream and re-emits its own\n * authoritative `lifecycle.started` with the correlation in place.\n *\n * Events are also pushed to a local {@link StreamChannel} so in-process\n * consumers can iterate `run.lifecycle` without filtering the main\n * event stream.\n */\n\nimport type {\n AgentStatus,\n LifecycleCause,\n LifecycleData,\n} from \"@langchain/protocol\";\n\nimport { hasPrefix, nsKey } from \"../mux.js\";\nimport { StreamChannel } from \"../stream-channel.js\";\nimport type {\n NativeStreamTransformer,\n Namespace,\n ProtocolEvent,\n StreamEmitter,\n} from \"../types.js\";\nimport type { LifecycleEntry, LifecycleTransformerOptions } from \"./types.js\";\n\n/**\n * Projection returned from the lifecycle transformer's `init()`.\n *\n * The local `StreamChannel` is closed automatically when the transformer\n * finalizes or fails. `_lifecycleLog` is intentionally underscore-prefixed to\n * signal that it is consumed by the run stream wiring\n * (see `run-stream.ts`) and not meant for direct user access -\n * consumers should read `run.lifecycle` instead.\n *\n * The `lifecycle` iterable is the root-scoped projection (prefix\n * `[]`, starting at offset `0`) mirroring the pattern used by the\n * subgraph discovery transformer. Root stream wiring consumes it\n * via `SET_LIFECYCLE_ITERABLE`; child streams are wired with their\n * own path-scoped iterable produced by `filterLifecycleEntries`.\n */\nexport interface LifecycleProjection {\n _lifecycleLog: StreamChannel<LifecycleEntry>;\n lifecycle: AsyncIterable<LifecycleEntry>;\n}\n\n/**\n * Filter a lifecycle {@link StreamChannel} to only the entries whose\n * namespace lies within the subtree rooted at {@link path}.\n *\n * Returns an `AsyncIterable` whose iterator yields every entry whose\n * namespace either equals {@link path} or is a descendant of it.\n * Iteration begins at {@link startAt}, so callers can capture the\n * log's current size at construction time to skip entries emitted\n * before the caller existed (e.g. a subgraph stream discovered\n * mid-run shouldn't replay the root's `started`).\n *\n * @param log - The shared lifecycle log owned by the transformer.\n * @param path - Namespace prefix to scope entries by (use `[]` for\n * the root subtree, i.e. everything).\n * @param startAt - Zero-based index into the log to begin from.\n * @returns An async iterable of matching lifecycle entries.\n */\nexport function filterLifecycleEntries(\n log: StreamChannel<LifecycleEntry>,\n path: Namespace,\n startAt = 0\n): AsyncIterable<LifecycleEntry> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<LifecycleEntry> {\n const base = log.iterate(startAt);\n return {\n async next(): Promise<IteratorResult<LifecycleEntry>> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const result = await base.next();\n if (result.done) {\n return {\n value: undefined as unknown as LifecycleEntry,\n done: true,\n };\n }\n if (hasPrefix(result.value.namespace, path)) {\n return { value: result.value, done: false };\n }\n }\n },\n };\n },\n };\n}\n\nconst DEFAULT_ROOT_GRAPH_NAME = \"root\";\n\nfunction defaultGuessGraphName(ns: Namespace): string {\n if (ns.length === 0) return DEFAULT_ROOT_GRAPH_NAME;\n const last = ns[ns.length - 1];\n const colon = last.indexOf(\":\");\n return colon === -1 ? last : last.slice(0, colon);\n}\n\nfunction defaultSerializeError(err: unknown): string {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (err instanceof Error) return err.message;\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Extract an upstream `cause` from a `lifecycle.started` payload, if\n * the shape matches one of the known variants. Shape validation is\n * intentionally loose: any object with a string `type` is accepted, so\n * future protocol variants flow through unchanged.\n */\nfunction extractCause(data: unknown): LifecycleCause | undefined {\n if (!isRecord(data)) return undefined;\n if (data.event !== \"started\") return undefined;\n const cause = data.cause;\n if (!isRecord(cause)) return undefined;\n if (typeof cause.type !== \"string\") return undefined;\n return cause as unknown as LifecycleCause;\n}\n\nfunction extractTaskResultCompletion(\n data: unknown\n): TaskResultCompletion | undefined {\n if (!isRecord(data)) return undefined;\n if (!(\"result\" in data)) return undefined;\n if (typeof data.name !== \"string\") return undefined;\n if (typeof data.id !== \"string\") return undefined;\n if (data.name.startsWith(\"__\")) return undefined;\n return { name: data.name, id: data.id };\n}\n\ninterface NamespaceRecord {\n readonly namespace: Namespace;\n readonly graphName: string;\n /** Last emitted status; `undefined` until `emit` fires for this namespace. */\n status: AgentStatus | undefined;\n}\n\ninterface TaskResultCompletion {\n readonly name: string;\n readonly id: string;\n}\n\ninterface PendingCompletion {\n readonly namespace: Namespace;\n readonly source:\n | { readonly type: \"task\" }\n | {\n readonly type: \"node\";\n readonly parent: Namespace;\n readonly node: string;\n };\n}\n\n/**\n * Create the built-in lifecycle transformer.\n *\n * Marked as a {@link NativeStreamTransformer} so the run stream\n * factory can expose `_lifecycleLog` via a dedicated getter\n * (`run.lifecycle`) rather than through `run.extensions`.\n */\nexport function createLifecycleTransformer(\n options: LifecycleTransformerOptions = {}\n): NativeStreamTransformer<LifecycleProjection> {\n const rootGraphName = options.rootGraphName ?? DEFAULT_ROOT_GRAPH_NAME;\n const initialStatus: AgentStatus = options.initialStatus ?? \"running\";\n const emitRootOnRegister = options.emitRootOnRegister ?? true;\n const getGraphName = options.getGraphName ?? defaultGuessGraphName;\n const serializeError = options.serializeError ?? defaultSerializeError;\n const getTerminalStatusOverride = options.getTerminalStatusOverride;\n\n const log = StreamChannel.local<LifecycleEntry>();\n const namespaces = new Map<string, NamespaceRecord>();\n const namespaceCause = new Map<string, LifecycleCause>();\n const pendingInterruptIds = new Set<string>();\n /**\n * Child namespaces whose parent just saw an `updates` event with a\n * `node` attribution. We defer the `lifecycle.completed` emission\n * until the *next* inbound event (or `finalize`) so the parent's\n * `updates` lands on the wire before its child is marked complete -\n * matching the previous session behavior.\n */\n const pendingCompletions: PendingCompletion[] = [];\n\n let emitter: StreamEmitter | undefined;\n let inSelfEmit = 0;\n let finalized = false;\n\n const resolveGraphName = (ns: Namespace): string =>\n ns.length === 0 ? rootGraphName : getGraphName(ns);\n\n const emit = (\n ns: Namespace,\n status: AgentStatus,\n extras?: { cause?: LifecycleCause; error?: string }\n ): void => {\n const key = nsKey(ns);\n let current = namespaces.get(key);\n const graphName = current?.graphName ?? resolveGraphName(ns);\n\n // Dedup: identical status + graph name + no error override => skip.\n if (\n current != null &&\n current.status === status &&\n current.graphName === graphName &&\n extras?.error == null\n ) {\n return;\n }\n\n if (current == null) {\n current = { namespace: ns, graphName, status };\n namespaces.set(key, current);\n } else {\n current.status = status;\n }\n\n const data: LifecycleData = {\n event: status,\n graph_name: graphName,\n ...(extras?.cause != null ? { cause: extras.cause } : {}),\n ...(extras?.error != null ? { error: extras.error } : {}),\n };\n\n const timestamp = Date.now();\n\n log.push({ namespace: ns, timestamp, ...data });\n\n if (ns.length === 0 && !emitRootOnRegister) return;\n\n if (emitter == null) return;\n\n inSelfEmit += 1;\n try {\n emitter.push(ns, {\n type: \"event\",\n seq: 0,\n method: \"lifecycle\",\n params: { namespace: ns, timestamp, data },\n });\n } finally {\n inSelfEmit -= 1;\n }\n };\n\n /**\n * Ensures a record exists for `ns` without mutating its status. Used\n * by hooks that need a canonical `graphName` for lookups before emit\n * writes the first status. Status remains `undefined` until `emit`\n * fires.\n */\n const trackNamespace = (ns: Namespace): NamespaceRecord => {\n const key = nsKey(ns);\n let rec = namespaces.get(key);\n if (rec == null) {\n rec = {\n namespace: ns,\n graphName: resolveGraphName(ns),\n status: undefined,\n };\n namespaces.set(key, rec);\n }\n return rec;\n };\n\n const flushPendingCompletions = (): void => {\n if (pendingCompletions.length === 0) return;\n const toFlush = pendingCompletions.splice(0, pendingCompletions.length);\n for (const completion of toFlush) {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") continue;\n emit(completion.namespace, \"completed\");\n }\n };\n\n const enqueueCompletion = (completion: PendingCompletion): void => {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") return;\n if (\n pendingCompletions.some((pending) => nsKey(pending.namespace) === key)\n ) {\n return;\n }\n pendingCompletions.push(completion);\n };\n\n const removePendingNodeCompletions = (\n parent: Namespace,\n node: string\n ): void => {\n for (let index = pendingCompletions.length - 1; index >= 0; index -= 1) {\n const pending = pendingCompletions[index];\n if (pending.source.type !== \"node\") continue;\n if (pending.source.node !== node) continue;\n if (nsKey(pending.source.parent) !== nsKey(parent)) continue;\n pendingCompletions.splice(index, 1);\n }\n };\n\n const ensureStarted = (ns: Namespace): void => {\n // Synthesize `lifecycle.started` for each unseen prefix of `ns`,\n // outermost first. Deepest-first would force consumers to see a\n // child's started before its parent, which is wrong.\n for (let length = 1; length <= ns.length; length += 1) {\n const prefix = ns.slice(0, length);\n const key = nsKey(prefix);\n if (namespaces.has(key)) continue;\n trackNamespace(prefix);\n const cause = namespaceCause.get(key);\n emit(prefix, \"started\", cause != null ? { cause } : undefined);\n }\n };\n\n const defaultTerminalStatus = (): AgentStatus =>\n pendingInterruptIds.size > 0 ? \"interrupted\" : \"completed\";\n\n const cascadeTerminalStatus = (status: AgentStatus): void => {\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, status);\n }\n emit([], status);\n log.close();\n };\n\n const resolveTerminalStatusOverride = async (): Promise<AgentStatus> => {\n if (getTerminalStatusOverride == null) return defaultTerminalStatus();\n try {\n return (await getTerminalStatusOverride()) ?? defaultTerminalStatus();\n } catch {\n return defaultTerminalStatus();\n }\n };\n\n const findStartedChildForNode = (\n parentNamespace: Namespace,\n node: string\n ): Namespace | undefined => {\n const prefix = `${node}:`;\n for (const rec of namespaces.values()) {\n if (rec.namespace.length !== parentNamespace.length + 1) continue;\n if (rec.status !== \"started\") continue;\n if (!hasPrefix(rec.namespace, parentNamespace)) continue;\n const last = rec.namespace[rec.namespace.length - 1];\n if (last === node || last.startsWith(prefix)) return rec.namespace;\n }\n return undefined;\n };\n\n const findStartedChildForTask = (\n parentNamespace: Namespace,\n task: TaskResultCompletion\n ): Namespace | undefined => {\n const namespace = [...parentNamespace, `${task.name}:${task.id}`];\n const rec = namespaces.get(nsKey(namespace));\n return rec?.status === \"started\" ? namespace : undefined;\n };\n\n const transformer: NativeStreamTransformer<LifecycleProjection> = {\n __native: true,\n\n init() {\n return {\n _lifecycleLog: log,\n lifecycle: filterLifecycleEntries(log, [], 0),\n };\n },\n\n onRegister(handle: StreamEmitter) {\n emitter = handle;\n // Seed root record so cascade logic can see it, even when the\n // outer authority owns root emission.\n trackNamespace([]);\n if (emitRootOnRegister) {\n emit([], initialStatus);\n }\n },\n\n process(event: ProtocolEvent): boolean {\n const ns = event.params.namespace;\n\n // Re-entrant loopback: an event we emitted via `emitter.push`\n // is being routed back through this transformer by the mux.\n // Allow it through the wire unchanged.\n if (inSelfEmit > 0) return true;\n\n const taskCompletion =\n event.method === \"tasks\"\n ? extractTaskResultCompletion(event.params.data)\n : undefined;\n if (taskCompletion != null) {\n // Prefer exact task-result attribution over any ambiguous\n // `updates.node` completion deferred from the previous event.\n removePendingNodeCompletions(ns, taskCompletion.name);\n }\n\n // Flush any completions deferred by the previous event so the\n // wire order is [triggering event] -> [deferred completed].\n flushPendingCompletions();\n\n // Upstream `lifecycle` events: stash any `cause` attached by a\n // product-specific transformer (e.g. deepagents' SubagentTransformer),\n // synthesize our authoritative started/... for the namespace, and\n // suppress the original so we are the single source of truth.\n if (event.method === \"lifecycle\") {\n const cause = extractCause(event.params.data);\n if (cause != null) {\n namespaceCause.set(nsKey(ns), cause);\n }\n ensureStarted(ns);\n return false;\n }\n\n // Lifecycle for parent + any unseen prefix => synthesize started.\n ensureStarted(ns);\n\n // Track interrupt ids so `finalize` can decide between\n // `completed` and `interrupted`.\n if (\n event.method === \"input\" &&\n isRecord(event.params.data) &&\n event.params.data.event === \"requested\"\n ) {\n const id = (event.params.data as { id?: unknown }).id;\n if (typeof id === \"string\") {\n pendingInterruptIds.add(id);\n }\n }\n\n if (taskCompletion != null) {\n const childNamespace = findStartedChildForTask(ns, taskCompletion);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"task\" },\n });\n }\n }\n\n // Defer child-node completion: the `updates` event carries the\n // node attribution; the corresponding child namespace is\n // `[...ns, \"<node>:<uuid>\"]`. We pick the oldest still-started\n // matching child (LangGraph emits one updates per completed task\n // so repeated calls drain parallel fan-outs in order).\n if (event.method === \"updates\") {\n const node = event.params.node;\n if (typeof node === \"string\" && !node.startsWith(\"__\")) {\n const childNamespace = findStartedChildForNode(ns, node);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"node\", parent: ns, node },\n });\n }\n }\n }\n\n return true;\n },\n\n finalize(): void | PromiseLike<void> {\n if (finalized) return;\n finalized = true;\n flushPendingCompletions();\n\n if (getTerminalStatusOverride == null) {\n cascadeTerminalStatus(defaultTerminalStatus());\n return;\n }\n\n return resolveTerminalStatusOverride()\n .then(cascadeTerminalStatus)\n .catch((err) => {\n log.fail(err);\n });\n },\n\n fail(err: unknown) {\n if (finalized) return;\n finalized = true;\n const errorMessage = serializeError(err);\n\n // Cascade `failed` to every still-started namespace. Children\n // that had already entered a terminal state are left untouched\n // by the dedup guard in `emit`.\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, \"failed\");\n }\n\n emit([], \"failed\", { error: errorMessage });\n log.fail(err);\n },\n };\n\n return transformer;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecycle.js","names":[],"sources":["../../../src/stream/transformers/lifecycle.ts"],"sourcesContent":["/**\n * LifecycleTransformer - synthesizes `lifecycle` channel events that\n * track the status of the root run and every subgraph it spawns.\n *\n * The transformer is registered first in `createGraphRunStream` so that\n * every other transformer / consumer sees a coherent, authoritative\n * lifecycle stream. It is product-agnostic: deeper semantics (e.g.\n * DeepAgents' `SubagentTransformer` tool-call causation) reach the wire\n * by way of the re-entrant {@link StreamEmitter} - the transformer\n * stashes any `cause` attached upstream and re-emits its own\n * authoritative `lifecycle.started` with the correlation in place.\n *\n * Events are also pushed to a local {@link StreamChannel} so in-process\n * consumers can iterate `run.lifecycle` without filtering the main\n * event stream.\n */\n\nimport type {\n AgentStatus,\n LifecycleCause,\n LifecycleData,\n} from \"@langchain/protocol\";\n\nimport { hasPrefix, nsKey } from \"../mux.js\";\nimport { StreamChannel } from \"../stream-channel.js\";\nimport type {\n NativeStreamTransformer,\n Namespace,\n ProtocolEvent,\n StreamEmitter,\n} from \"../types.js\";\nimport type { LifecycleEntry, LifecycleTransformerOptions } from \"./types.js\";\n\n/**\n * Projection returned from the lifecycle transformer's `init()`.\n *\n * The local `StreamChannel` is closed automatically when the transformer\n * finalizes or fails. `_lifecycleLog` is intentionally underscore-prefixed to\n * signal that it is consumed by the run stream wiring\n * (see `run-stream.ts`) and not meant for direct user access -\n * consumers should read `run.lifecycle` instead.\n *\n * The `lifecycle` iterable is the root-scoped projection (prefix\n * `[]`, starting at offset `0`) mirroring the pattern used by the\n * subgraph discovery transformer. Root stream wiring consumes it\n * via `SET_LIFECYCLE_ITERABLE`; child streams are wired with their\n * own path-scoped iterable produced by `filterLifecycleEntries`.\n */\nexport interface LifecycleProjection {\n _lifecycleLog: StreamChannel<LifecycleEntry>;\n lifecycle: AsyncIterable<LifecycleEntry>;\n}\n\n/**\n * Filter a lifecycle {@link StreamChannel} to only the entries whose\n * namespace lies within the subtree rooted at {@link path}.\n *\n * Returns an `AsyncIterable` whose iterator yields every entry whose\n * namespace either equals {@link path} or is a descendant of it.\n * Iteration begins at {@link startAt}, so callers can capture the\n * log's current size at construction time to skip entries emitted\n * before the caller existed (e.g. a subgraph stream discovered\n * mid-run shouldn't replay the root's `started`).\n *\n * @param log - The shared lifecycle log owned by the transformer.\n * @param path - Namespace prefix to scope entries by (use `[]` for\n * the root subtree, i.e. everything).\n * @param startAt - Zero-based index into the log to begin from.\n * @returns An async iterable of matching lifecycle entries.\n */\nexport function filterLifecycleEntries(\n log: StreamChannel<LifecycleEntry>,\n path: Namespace,\n startAt = 0\n): AsyncIterable<LifecycleEntry> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<LifecycleEntry> {\n const base = log.iterate(startAt);\n return {\n async next(): Promise<IteratorResult<LifecycleEntry>> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const result = await base.next();\n if (result.done) {\n return {\n value: undefined as unknown as LifecycleEntry,\n done: true,\n };\n }\n if (hasPrefix(result.value.namespace, path)) {\n return { value: result.value, done: false };\n }\n }\n },\n };\n },\n };\n}\n\nconst DEFAULT_ROOT_GRAPH_NAME = \"root\";\n\nfunction defaultGuessGraphName(ns: Namespace): string {\n if (ns.length === 0) return DEFAULT_ROOT_GRAPH_NAME;\n const last = ns[ns.length - 1];\n const colon = last.indexOf(\":\");\n return colon === -1 ? last : last.slice(0, colon);\n}\n\nfunction defaultSerializeError(err: unknown): string {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (err instanceof Error) return err.message;\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Extract an upstream `cause` from a `lifecycle.started` payload, if\n * the shape matches one of the known variants. Shape validation is\n * intentionally loose: any object with a string `type` is accepted, so\n * future protocol variants flow through unchanged.\n */\nfunction extractCause(data: unknown): LifecycleCause | undefined {\n if (!isRecord(data)) return undefined;\n if (data.event !== \"started\") return undefined;\n const cause = data.cause;\n if (!isRecord(cause)) return undefined;\n if (typeof cause.type !== \"string\") return undefined;\n return cause as unknown as LifecycleCause;\n}\n\nfunction extractTaskResultCompletion(\n data: unknown\n): TaskResultCompletion | undefined {\n if (!isRecord(data)) return undefined;\n if (!(\"result\" in data)) return undefined;\n if (typeof data.name !== \"string\") return undefined;\n if (typeof data.id !== \"string\") return undefined;\n if (data.name.startsWith(\"__\")) return undefined;\n return { name: data.name, id: data.id };\n}\n\ninterface NamespaceRecord {\n readonly namespace: Namespace;\n readonly graphName: string;\n /** Last emitted status; `undefined` until `emit` fires for this namespace. */\n status: AgentStatus | undefined;\n}\n\ninterface TaskResultCompletion {\n readonly name: string;\n readonly id: string;\n}\n\ninterface PendingCompletion {\n readonly namespace: Namespace;\n readonly source:\n | { readonly type: \"task\" }\n | {\n readonly type: \"node\";\n readonly parent: Namespace;\n readonly node: string;\n };\n}\n\n/**\n * Create the built-in lifecycle transformer.\n *\n * Marked as a {@link NativeStreamTransformer} so the run stream\n * factory can expose `_lifecycleLog` via a dedicated getter\n * (`run.lifecycle`) rather than through `run.extensions`.\n */\nexport function createLifecycleTransformer(\n options: LifecycleTransformerOptions = {}\n): NativeStreamTransformer<LifecycleProjection> {\n const rootGraphName = options.rootGraphName ?? DEFAULT_ROOT_GRAPH_NAME;\n const initialStatus: AgentStatus = options.initialStatus ?? \"running\";\n const emitRootOnRegister = options.emitRootOnRegister ?? true;\n const getGraphName = options.getGraphName ?? defaultGuessGraphName;\n const serializeError = options.serializeError ?? defaultSerializeError;\n const getTerminalStatusOverride = options.getTerminalStatusOverride;\n\n const log = StreamChannel.local<LifecycleEntry>();\n const namespaces = new Map<string, NamespaceRecord>();\n const namespaceCause = new Map<string, LifecycleCause>();\n /**\n * `lc_agent_name` observed at each namespace (first task event wins). A\n * nested run carrying an `lc_agent_name` (set by `createAgent`) is treated\n * as a named subagent: its `graph_name` becomes that name and a tool-call\n * `cause` is recovered (see {@link deriveToolCallCause}). Namespaces without\n * one fall back to the parsed namespace segment, preserving the prior\n * product-agnostic behavior for plain subgraphs.\n */\n const lcByNs = new Map<string, string | undefined>();\n /**\n * Pregel task id -> triggering LLM `tool_call_id`, harvested from a task\n * whose `input` is a `tool_call_with_context` dict (current shape) or a list\n * of tool-call dicts (legacy shape). The child subgraph's namespace segment\n * `node:<task_id>` shares this task id, so a named subagent recovers the tool\n * call that spawned it across payloads.\n */\n const pendingToolCalls = new Map<string, string>();\n const pendingInterruptIds = new Set<string>();\n /**\n * Child namespaces whose parent just saw an `updates` event with a\n * `node` attribution. We defer the `lifecycle.completed` emission\n * until the *next* inbound event (or `finalize`) so the parent's\n * `updates` lands on the wire before its child is marked complete -\n * matching the previous session behavior.\n */\n const pendingCompletions: PendingCompletion[] = [];\n\n let emitter: StreamEmitter | undefined;\n let inSelfEmit = 0;\n let finalized = false;\n\n const resolveGraphName = (ns: Namespace): string => {\n if (ns.length === 0) return rootGraphName;\n // A nested run that carried an `lc_agent_name` is a named subagent; its\n // agent name wins over the parsed namespace segment.\n const lc = lcByNs.get(nsKey(ns));\n if (typeof lc === \"string\" && lc.length > 0) return lc;\n return getGraphName(ns);\n };\n\n /**\n * Record a namespace's `lc_agent_name` from a task-start payload (first\n * event wins). The presence of a name is what marks the namespace a named\n * subagent; the value may be `undefined` for unnamed runs (still recorded so\n * a later event doesn't re-evaluate it).\n */\n const recordIdentity = (ns: Namespace, data: unknown): void => {\n const key = nsKey(ns);\n if (lcByNs.has(key)) return;\n const metadata =\n isRecord(data) && isRecord(data.metadata) ? data.metadata : undefined;\n const lc = metadata?.lc_agent_name;\n lcByNs.set(key, typeof lc === \"string\" ? lc : undefined);\n };\n\n /**\n * Harvest a task's triggering `tool_call_id` keyed by its task id. The\n * spawned subgraph's namespace segment `node:<task_id>` shares that id, so a\n * subagent can later recover the tool call that caused it. Two input shapes\n * are handled: a `tool_call_with_context` object (`input.tool_call.id`) and a\n * legacy list of tool-call objects (first with a string `id`).\n */\n const recordPendingToolCalls = (data: unknown): void => {\n if (!isRecord(data)) return;\n const taskId = data.id;\n if (typeof taskId !== \"string\") return;\n const input = data.input;\n let toolCallId: string | undefined;\n if (isRecord(input) && isRecord(input.tool_call)) {\n const candidate = input.tool_call.id;\n if (typeof candidate === \"string\") toolCallId = candidate;\n } else if (Array.isArray(input)) {\n for (const toolCall of input) {\n if (isRecord(toolCall) && typeof toolCall.id === \"string\") {\n toolCallId = toolCall.id;\n break;\n }\n }\n }\n if (toolCallId != null) pendingToolCalls.set(taskId, toolCallId);\n };\n\n /**\n * Derive a `toolCall` cause for a named subagent namespace by joining the\n * namespace segment's task id (`node:<task_id>`) to a previously harvested\n * `tool_call_id`. Only fires for namespaces carrying an `lc_agent_name`, so\n * plain subgraphs never get a spurious cause.\n */\n const deriveToolCallCause = (ns: Namespace): LifecycleCause | undefined => {\n if (ns.length === 0) return undefined;\n const lc = lcByNs.get(nsKey(ns));\n if (typeof lc !== \"string\" || lc.length === 0) return undefined;\n const segment = ns[ns.length - 1];\n const colon = segment.indexOf(\":\");\n if (colon === -1) return undefined;\n const triggerCallId = segment.slice(colon + 1);\n if (triggerCallId.length === 0) return undefined;\n const toolCallId = pendingToolCalls.get(triggerCallId);\n if (typeof toolCallId !== \"string\" || toolCallId.length === 0) {\n return undefined;\n }\n return { type: \"toolCall\", tool_call_id: toolCallId };\n };\n\n /**\n * Resolve the `cause` to attach to a namespace's `started`. An upstream\n * `cause` stashed from a product-specific transformer (e.g. deepagents'\n * SubagentTransformer) wins; otherwise a tool-call cause is recovered for\n * named subagents.\n */\n const resolveStartCause = (ns: Namespace): LifecycleCause | undefined =>\n namespaceCause.get(nsKey(ns)) ?? deriveToolCallCause(ns);\n\n const emit = (\n ns: Namespace,\n status: AgentStatus,\n extras?: { cause?: LifecycleCause; error?: string }\n ): void => {\n const key = nsKey(ns);\n let current = namespaces.get(key);\n const graphName = current?.graphName ?? resolveGraphName(ns);\n\n // Dedup: identical status + graph name + no error override => skip.\n if (\n current != null &&\n current.status === status &&\n current.graphName === graphName &&\n extras?.error == null\n ) {\n return;\n }\n\n if (current == null) {\n current = { namespace: ns, graphName, status };\n namespaces.set(key, current);\n } else {\n current.status = status;\n }\n\n const data: LifecycleData = {\n event: status,\n graph_name: graphName,\n ...(extras?.cause != null ? { cause: extras.cause } : {}),\n ...(extras?.error != null ? { error: extras.error } : {}),\n };\n\n const timestamp = Date.now();\n\n log.push({ namespace: ns, timestamp, ...data });\n\n if (ns.length === 0 && !emitRootOnRegister) return;\n\n if (emitter == null) return;\n\n inSelfEmit += 1;\n try {\n emitter.push(ns, {\n type: \"event\",\n seq: 0,\n method: \"lifecycle\",\n params: { namespace: ns, timestamp, data },\n });\n } finally {\n inSelfEmit -= 1;\n }\n };\n\n /**\n * Ensures a record exists for `ns` without mutating its status. Used\n * by hooks that need a canonical `graphName` for lookups before emit\n * writes the first status. Status remains `undefined` until `emit`\n * fires.\n */\n const trackNamespace = (ns: Namespace): NamespaceRecord => {\n const key = nsKey(ns);\n let rec = namespaces.get(key);\n if (rec == null) {\n rec = {\n namespace: ns,\n graphName: resolveGraphName(ns),\n status: undefined,\n };\n namespaces.set(key, rec);\n }\n return rec;\n };\n\n const flushPendingCompletions = (): void => {\n if (pendingCompletions.length === 0) return;\n const toFlush = pendingCompletions.splice(0, pendingCompletions.length);\n for (const completion of toFlush) {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") continue;\n emit(completion.namespace, \"completed\");\n }\n };\n\n const enqueueCompletion = (completion: PendingCompletion): void => {\n const key = nsKey(completion.namespace);\n const rec = namespaces.get(key);\n if (rec == null || rec.status !== \"started\") return;\n if (\n pendingCompletions.some((pending) => nsKey(pending.namespace) === key)\n ) {\n return;\n }\n pendingCompletions.push(completion);\n };\n\n const removePendingNodeCompletions = (\n parent: Namespace,\n node: string\n ): void => {\n for (let index = pendingCompletions.length - 1; index >= 0; index -= 1) {\n const pending = pendingCompletions[index];\n if (pending.source.type !== \"node\") continue;\n if (pending.source.node !== node) continue;\n if (nsKey(pending.source.parent) !== nsKey(parent)) continue;\n pendingCompletions.splice(index, 1);\n }\n };\n\n const ensureStarted = (ns: Namespace): void => {\n // Synthesize `lifecycle.started` for each unseen prefix of `ns`,\n // outermost first. Deepest-first would force consumers to see a\n // child's started before its parent, which is wrong.\n for (let length = 1; length <= ns.length; length += 1) {\n const prefix = ns.slice(0, length);\n const key = nsKey(prefix);\n if (namespaces.has(key)) continue;\n trackNamespace(prefix);\n const cause = resolveStartCause(prefix);\n emit(prefix, \"started\", cause != null ? { cause } : undefined);\n }\n };\n\n const defaultTerminalStatus = (): AgentStatus =>\n pendingInterruptIds.size > 0 ? \"interrupted\" : \"completed\";\n\n const cascadeTerminalStatus = (status: AgentStatus): void => {\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, status);\n }\n emit([], status);\n log.close();\n };\n\n const resolveTerminalStatusOverride = async (): Promise<AgentStatus> => {\n if (getTerminalStatusOverride == null) return defaultTerminalStatus();\n try {\n return (await getTerminalStatusOverride()) ?? defaultTerminalStatus();\n } catch {\n return defaultTerminalStatus();\n }\n };\n\n const findStartedChildForNode = (\n parentNamespace: Namespace,\n node: string\n ): Namespace | undefined => {\n const prefix = `${node}:`;\n for (const rec of namespaces.values()) {\n if (rec.namespace.length !== parentNamespace.length + 1) continue;\n if (rec.status !== \"started\") continue;\n if (!hasPrefix(rec.namespace, parentNamespace)) continue;\n const last = rec.namespace[rec.namespace.length - 1];\n if (last === node || last.startsWith(prefix)) return rec.namespace;\n }\n return undefined;\n };\n\n const findStartedChildForTask = (\n parentNamespace: Namespace,\n task: TaskResultCompletion\n ): Namespace | undefined => {\n const namespace = [...parentNamespace, `${task.name}:${task.id}`];\n const rec = namespaces.get(nsKey(namespace));\n return rec?.status === \"started\" ? namespace : undefined;\n };\n\n const transformer: NativeStreamTransformer<LifecycleProjection> = {\n __native: true,\n\n init() {\n return {\n _lifecycleLog: log,\n lifecycle: filterLifecycleEntries(log, [], 0),\n };\n },\n\n onRegister(handle: StreamEmitter) {\n emitter = handle;\n // Seed root record so cascade logic can see it, even when the\n // outer authority owns root emission.\n trackNamespace([]);\n if (emitRootOnRegister) {\n emit([], initialStatus);\n }\n },\n\n process(event: ProtocolEvent): boolean {\n const ns = event.params.namespace;\n\n // Re-entrant loopback: an event we emitted via `emitter.push`\n // is being routed back through this transformer by the mux.\n // Allow it through the wire unchanged.\n if (inSelfEmit > 0) return true;\n\n const taskCompletion =\n event.method === \"tasks\"\n ? extractTaskResultCompletion(event.params.data)\n : undefined;\n if (taskCompletion != null) {\n // Prefer exact task-result attribution over any ambiguous\n // `updates.node` completion deferred from the previous event.\n removePendingNodeCompletions(ns, taskCompletion.name);\n } else if (event.method === \"tasks\") {\n // Task-start event: record the namespace's subagent identity and any\n // triggering tool call *before* `ensureStarted` synthesizes `started`,\n // so a named subagent's `graph_name`/`cause` are resolved in time.\n // Pregel emits parent-namespace tasks before child-namespace tasks, so\n // the parent's tool-call seed is in place when the child is evaluated.\n recordIdentity(ns, event.params.data);\n recordPendingToolCalls(event.params.data);\n }\n\n // Flush any completions deferred by the previous event so the\n // wire order is [triggering event] -> [deferred completed].\n flushPendingCompletions();\n\n // Upstream `lifecycle` events: stash any `cause` attached by a\n // product-specific transformer (e.g. deepagents' SubagentTransformer),\n // synthesize our authoritative started/... for the namespace, and\n // suppress the original so we are the single source of truth.\n if (event.method === \"lifecycle\") {\n const cause = extractCause(event.params.data);\n if (cause != null) {\n namespaceCause.set(nsKey(ns), cause);\n }\n ensureStarted(ns);\n return false;\n }\n\n // Lifecycle for parent + any unseen prefix => synthesize started.\n ensureStarted(ns);\n\n // Track interrupt ids so `finalize` can decide between\n // `completed` and `interrupted`.\n if (\n event.method === \"input\" &&\n isRecord(event.params.data) &&\n event.params.data.event === \"requested\"\n ) {\n const id = (event.params.data as { id?: unknown }).id;\n if (typeof id === \"string\") {\n pendingInterruptIds.add(id);\n }\n }\n\n if (taskCompletion != null) {\n const childNamespace = findStartedChildForTask(ns, taskCompletion);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"task\" },\n });\n }\n }\n\n // Defer child-node completion: the `updates` event carries the\n // node attribution; the corresponding child namespace is\n // `[...ns, \"<node>:<uuid>\"]`. We pick the oldest still-started\n // matching child (LangGraph emits one updates per completed task\n // so repeated calls drain parallel fan-outs in order).\n if (event.method === \"updates\") {\n const node = event.params.node;\n if (typeof node === \"string\" && !node.startsWith(\"__\")) {\n const childNamespace = findStartedChildForNode(ns, node);\n if (childNamespace != null) {\n enqueueCompletion({\n namespace: childNamespace,\n source: { type: \"node\", parent: ns, node },\n });\n }\n }\n }\n\n return true;\n },\n\n finalize(): void | PromiseLike<void> {\n if (finalized) return;\n finalized = true;\n flushPendingCompletions();\n\n if (getTerminalStatusOverride == null) {\n cascadeTerminalStatus(defaultTerminalStatus());\n return;\n }\n\n return resolveTerminalStatusOverride()\n .then(cascadeTerminalStatus)\n .catch((err) => {\n log.fail(err);\n });\n },\n\n fail(err: unknown) {\n if (finalized) return;\n finalized = true;\n const errorMessage = serializeError(err);\n\n // Cascade `failed` to every still-started namespace. Children\n // that had already entered a terminal state are left untouched\n // by the dedup guard in `emit`.\n for (const rec of namespaces.values()) {\n if (rec.namespace.length === 0) continue;\n if (rec.status !== \"started\") continue;\n emit(rec.namespace, \"failed\");\n }\n\n emit([], \"failed\", { error: errorMessage });\n log.fail(err);\n },\n };\n\n return transformer;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsEA,SAAgB,uBACd,KACA,MACA,UAAU,GACqB;AAC/B,QAAO,EACL,CAAC,OAAO,iBAAgD;EACtD,MAAM,OAAO,IAAI,QAAQ,QAAQ;AACjC,SAAO,EACL,MAAM,OAAgD;AAEpD,UAAO,MAAM;IACX,MAAM,SAAS,MAAM,KAAK,MAAM;AAChC,QAAI,OAAO,KACT,QAAO;KACL,OAAO,KAAA;KACP,MAAM;KACP;AAEH,QAAI,UAAU,OAAO,MAAM,WAAW,KAAK,CACzC,QAAO;KAAE,OAAO,OAAO;KAAO,MAAM;KAAO;;KAIlD;IAEJ;;AAGH,MAAM,0BAA0B;AAEhC,SAAS,sBAAsB,IAAuB;AACpD,KAAI,GAAG,WAAW,EAAG,QAAO;CAC5B,MAAM,OAAO,GAAG,GAAG,SAAS;CAC5B,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC/B,QAAO,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,MAAM;;AAGnD,SAAS,sBAAsB,KAAsB;AAEnD,KAAI,eAAe,MAAO,QAAO,IAAI;AACrC,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;AACF,SAAO,KAAK,UAAU,IAAI;SACpB;AACN,SAAO,OAAO,IAAI;;;AAItB,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;;;;;AAS7E,SAAS,aAAa,MAA2C;AAC/D,KAAI,CAAC,SAAS,KAAK,CAAE,QAAO,KAAA;AAC5B,KAAI,KAAK,UAAU,UAAW,QAAO,KAAA;CACrC,MAAM,QAAQ,KAAK;AACnB,KAAI,CAAC,SAAS,MAAM,CAAE,QAAO,KAAA;AAC7B,KAAI,OAAO,MAAM,SAAS,SAAU,QAAO,KAAA;AAC3C,QAAO;;AAGT,SAAS,4BACP,MACkC;AAClC,KAAI,CAAC,SAAS,KAAK,CAAE,QAAO,KAAA;AAC5B,KAAI,EAAE,YAAY,MAAO,QAAO,KAAA;AAChC,KAAI,OAAO,KAAK,SAAS,SAAU,QAAO,KAAA;AAC1C,KAAI,OAAO,KAAK,OAAO,SAAU,QAAO,KAAA;AACxC,KAAI,KAAK,KAAK,WAAW,KAAK,CAAE,QAAO,KAAA;AACvC,QAAO;EAAE,MAAM,KAAK;EAAM,IAAI,KAAK;EAAI;;;;;;;;;AAiCzC,SAAgB,2BACd,UAAuC,EAAE,EACK;CAC9C,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,gBAA6B,QAAQ,iBAAiB;CAC5D,MAAM,qBAAqB,QAAQ,sBAAsB;CACzD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,4BAA4B,QAAQ;CAE1C,MAAM,MAAM,cAAc,OAAuB;CACjD,MAAM,6BAAa,IAAI,KAA8B;CACrD,MAAM,iCAAiB,IAAI,KAA6B;;;;;;;;;CASxD,MAAM,yBAAS,IAAI,KAAiC;;;;;;;;CAQpD,MAAM,mCAAmB,IAAI,KAAqB;CAClD,MAAM,sCAAsB,IAAI,KAAa;;;;;;;;CAQ7C,MAAM,qBAA0C,EAAE;CAElD,IAAI;CACJ,IAAI,aAAa;CACjB,IAAI,YAAY;CAEhB,MAAM,oBAAoB,OAA0B;AAClD,MAAI,GAAG,WAAW,EAAG,QAAO;EAG5B,MAAM,KAAK,OAAO,IAAI,MAAM,GAAG,CAAC;AAChC,MAAI,OAAO,OAAO,YAAY,GAAG,SAAS,EAAG,QAAO;AACpD,SAAO,aAAa,GAAG;;;;;;;;CASzB,MAAM,kBAAkB,IAAe,SAAwB;EAC7D,MAAM,MAAM,MAAM,GAAG;AACrB,MAAI,OAAO,IAAI,IAAI,CAAE;EAGrB,MAAM,MADJ,SAAS,KAAK,IAAI,SAAS,KAAK,SAAS,GAAG,KAAK,WAAW,KAAA,IACzC;AACrB,SAAO,IAAI,KAAK,OAAO,OAAO,WAAW,KAAK,KAAA,EAAU;;;;;;;;;CAU1D,MAAM,0BAA0B,SAAwB;AACtD,MAAI,CAAC,SAAS,KAAK,CAAE;EACrB,MAAM,SAAS,KAAK;AACpB,MAAI,OAAO,WAAW,SAAU;EAChC,MAAM,QAAQ,KAAK;EACnB,IAAI;AACJ,MAAI,SAAS,MAAM,IAAI,SAAS,MAAM,UAAU,EAAE;GAChD,MAAM,YAAY,MAAM,UAAU;AAClC,OAAI,OAAO,cAAc,SAAU,cAAa;aACvC,MAAM,QAAQ,MAAM;QACxB,MAAM,YAAY,MACrB,KAAI,SAAS,SAAS,IAAI,OAAO,SAAS,OAAO,UAAU;AACzD,iBAAa,SAAS;AACtB;;;AAIN,MAAI,cAAc,KAAM,kBAAiB,IAAI,QAAQ,WAAW;;;;;;;;CASlE,MAAM,uBAAuB,OAA8C;AACzE,MAAI,GAAG,WAAW,EAAG,QAAO,KAAA;EAC5B,MAAM,KAAK,OAAO,IAAI,MAAM,GAAG,CAAC;AAChC,MAAI,OAAO,OAAO,YAAY,GAAG,WAAW,EAAG,QAAO,KAAA;EACtD,MAAM,UAAU,GAAG,GAAG,SAAS;EAC/B,MAAM,QAAQ,QAAQ,QAAQ,IAAI;AAClC,MAAI,UAAU,GAAI,QAAO,KAAA;EACzB,MAAM,gBAAgB,QAAQ,MAAM,QAAQ,EAAE;AAC9C,MAAI,cAAc,WAAW,EAAG,QAAO,KAAA;EACvC,MAAM,aAAa,iBAAiB,IAAI,cAAc;AACtD,MAAI,OAAO,eAAe,YAAY,WAAW,WAAW,EAC1D;AAEF,SAAO;GAAE,MAAM;GAAY,cAAc;GAAY;;;;;;;;CASvD,MAAM,qBAAqB,OACzB,eAAe,IAAI,MAAM,GAAG,CAAC,IAAI,oBAAoB,GAAG;CAE1D,MAAM,QACJ,IACA,QACA,WACS;EACT,MAAM,MAAM,MAAM,GAAG;EACrB,IAAI,UAAU,WAAW,IAAI,IAAI;EACjC,MAAM,YAAY,SAAS,aAAa,iBAAiB,GAAG;AAG5D,MACE,WAAW,QACX,QAAQ,WAAW,UACnB,QAAQ,cAAc,aACtB,QAAQ,SAAS,KAEjB;AAGF,MAAI,WAAW,MAAM;AACnB,aAAU;IAAE,WAAW;IAAI;IAAW;IAAQ;AAC9C,cAAW,IAAI,KAAK,QAAQ;QAE5B,SAAQ,SAAS;EAGnB,MAAM,OAAsB;GAC1B,OAAO;GACP,YAAY;GACZ,GAAI,QAAQ,SAAS,OAAO,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE;GACxD,GAAI,QAAQ,SAAS,OAAO,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE;GACzD;EAED,MAAM,YAAY,KAAK,KAAK;AAE5B,MAAI,KAAK;GAAE,WAAW;GAAI;GAAW,GAAG;GAAM,CAAC;AAE/C,MAAI,GAAG,WAAW,KAAK,CAAC,mBAAoB;AAE5C,MAAI,WAAW,KAAM;AAErB,gBAAc;AACd,MAAI;AACF,WAAQ,KAAK,IAAI;IACf,MAAM;IACN,KAAK;IACL,QAAQ;IACR,QAAQ;KAAE,WAAW;KAAI;KAAW;KAAM;IAC3C,CAAC;YACM;AACR,iBAAc;;;;;;;;;CAUlB,MAAM,kBAAkB,OAAmC;EACzD,MAAM,MAAM,MAAM,GAAG;EACrB,IAAI,MAAM,WAAW,IAAI,IAAI;AAC7B,MAAI,OAAO,MAAM;AACf,SAAM;IACJ,WAAW;IACX,WAAW,iBAAiB,GAAG;IAC/B,QAAQ,KAAA;IACT;AACD,cAAW,IAAI,KAAK,IAAI;;AAE1B,SAAO;;CAGT,MAAM,gCAAsC;AAC1C,MAAI,mBAAmB,WAAW,EAAG;EACrC,MAAM,UAAU,mBAAmB,OAAO,GAAG,mBAAmB,OAAO;AACvE,OAAK,MAAM,cAAc,SAAS;GAChC,MAAM,MAAM,MAAM,WAAW,UAAU;GACvC,MAAM,MAAM,WAAW,IAAI,IAAI;AAC/B,OAAI,OAAO,QAAQ,IAAI,WAAW,UAAW;AAC7C,QAAK,WAAW,WAAW,YAAY;;;CAI3C,MAAM,qBAAqB,eAAwC;EACjE,MAAM,MAAM,MAAM,WAAW,UAAU;EACvC,MAAM,MAAM,WAAW,IAAI,IAAI;AAC/B,MAAI,OAAO,QAAQ,IAAI,WAAW,UAAW;AAC7C,MACE,mBAAmB,MAAM,YAAY,MAAM,QAAQ,UAAU,KAAK,IAAI,CAEtE;AAEF,qBAAmB,KAAK,WAAW;;CAGrC,MAAM,gCACJ,QACA,SACS;AACT,OAAK,IAAI,QAAQ,mBAAmB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;GACtE,MAAM,UAAU,mBAAmB;AACnC,OAAI,QAAQ,OAAO,SAAS,OAAQ;AACpC,OAAI,QAAQ,OAAO,SAAS,KAAM;AAClC,OAAI,MAAM,QAAQ,OAAO,OAAO,KAAK,MAAM,OAAO,CAAE;AACpD,sBAAmB,OAAO,OAAO,EAAE;;;CAIvC,MAAM,iBAAiB,OAAwB;AAI7C,OAAK,IAAI,SAAS,GAAG,UAAU,GAAG,QAAQ,UAAU,GAAG;GACrD,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO;GAClC,MAAM,MAAM,MAAM,OAAO;AACzB,OAAI,WAAW,IAAI,IAAI,CAAE;AACzB,kBAAe,OAAO;GACtB,MAAM,QAAQ,kBAAkB,OAAO;AACvC,QAAK,QAAQ,WAAW,SAAS,OAAO,EAAE,OAAO,GAAG,KAAA,EAAU;;;CAIlE,MAAM,8BACJ,oBAAoB,OAAO,IAAI,gBAAgB;CAEjD,MAAM,yBAAyB,WAA8B;AAC3D,OAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,OAAI,IAAI,UAAU,WAAW,EAAG;AAChC,OAAI,IAAI,WAAW,UAAW;AAC9B,QAAK,IAAI,WAAW,OAAO;;AAE7B,OAAK,EAAE,EAAE,OAAO;AAChB,MAAI,OAAO;;CAGb,MAAM,gCAAgC,YAAkC;AACtE,MAAI,6BAA6B,KAAM,QAAO,uBAAuB;AACrE,MAAI;AACF,UAAQ,MAAM,2BAA2B,IAAK,uBAAuB;UAC/D;AACN,UAAO,uBAAuB;;;CAIlC,MAAM,2BACJ,iBACA,SAC0B;EAC1B,MAAM,SAAS,GAAG,KAAK;AACvB,OAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,OAAI,IAAI,UAAU,WAAW,gBAAgB,SAAS,EAAG;AACzD,OAAI,IAAI,WAAW,UAAW;AAC9B,OAAI,CAAC,UAAU,IAAI,WAAW,gBAAgB,CAAE;GAChD,MAAM,OAAO,IAAI,UAAU,IAAI,UAAU,SAAS;AAClD,OAAI,SAAS,QAAQ,KAAK,WAAW,OAAO,CAAE,QAAO,IAAI;;;CAK7D,MAAM,2BACJ,iBACA,SAC0B;EAC1B,MAAM,YAAY,CAAC,GAAG,iBAAiB,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK;AAEjE,SADY,WAAW,IAAI,MAAM,UAAU,CAAC,EAChC,WAAW,YAAY,YAAY,KAAA;;AAqJjD,QAlJkE;EAChE,UAAU;EAEV,OAAO;AACL,UAAO;IACL,eAAe;IACf,WAAW,uBAAuB,KAAK,EAAE,EAAE,EAAE;IAC9C;;EAGH,WAAW,QAAuB;AAChC,aAAU;AAGV,kBAAe,EAAE,CAAC;AAClB,OAAI,mBACF,MAAK,EAAE,EAAE,cAAc;;EAI3B,QAAQ,OAA+B;GACrC,MAAM,KAAK,MAAM,OAAO;AAKxB,OAAI,aAAa,EAAG,QAAO;GAE3B,MAAM,iBACJ,MAAM,WAAW,UACb,4BAA4B,MAAM,OAAO,KAAK,GAC9C,KAAA;AACN,OAAI,kBAAkB,KAGpB,8BAA6B,IAAI,eAAe,KAAK;YAC5C,MAAM,WAAW,SAAS;AAMnC,mBAAe,IAAI,MAAM,OAAO,KAAK;AACrC,2BAAuB,MAAM,OAAO,KAAK;;AAK3C,4BAAyB;AAMzB,OAAI,MAAM,WAAW,aAAa;IAChC,MAAM,QAAQ,aAAa,MAAM,OAAO,KAAK;AAC7C,QAAI,SAAS,KACX,gBAAe,IAAI,MAAM,GAAG,EAAE,MAAM;AAEtC,kBAAc,GAAG;AACjB,WAAO;;AAIT,iBAAc,GAAG;AAIjB,OACE,MAAM,WAAW,WACjB,SAAS,MAAM,OAAO,KAAK,IAC3B,MAAM,OAAO,KAAK,UAAU,aAC5B;IACA,MAAM,KAAM,MAAM,OAAO,KAA0B;AACnD,QAAI,OAAO,OAAO,SAChB,qBAAoB,IAAI,GAAG;;AAI/B,OAAI,kBAAkB,MAAM;IAC1B,MAAM,iBAAiB,wBAAwB,IAAI,eAAe;AAClE,QAAI,kBAAkB,KACpB,mBAAkB;KAChB,WAAW;KACX,QAAQ,EAAE,MAAM,QAAQ;KACzB,CAAC;;AASN,OAAI,MAAM,WAAW,WAAW;IAC9B,MAAM,OAAO,MAAM,OAAO;AAC1B,QAAI,OAAO,SAAS,YAAY,CAAC,KAAK,WAAW,KAAK,EAAE;KACtD,MAAM,iBAAiB,wBAAwB,IAAI,KAAK;AACxD,SAAI,kBAAkB,KACpB,mBAAkB;MAChB,WAAW;MACX,QAAQ;OAAE,MAAM;OAAQ,QAAQ;OAAI;OAAM;MAC3C,CAAC;;;AAKR,UAAO;;EAGT,WAAqC;AACnC,OAAI,UAAW;AACf,eAAY;AACZ,4BAAyB;AAEzB,OAAI,6BAA6B,MAAM;AACrC,0BAAsB,uBAAuB,CAAC;AAC9C;;AAGF,UAAO,+BAA+B,CACnC,KAAK,sBAAsB,CAC3B,OAAO,QAAQ;AACd,QAAI,KAAK,IAAI;KACb;;EAGN,KAAK,KAAc;AACjB,OAAI,UAAW;AACf,eAAY;GACZ,MAAM,eAAe,eAAe,IAAI;AAKxC,QAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,QAAI,IAAI,UAAU,WAAW,EAAG;AAChC,QAAI,IAAI,WAAW,UAAW;AAC9B,SAAK,IAAI,WAAW,SAAS;;AAG/B,QAAK,EAAE,EAAE,UAAU,EAAE,OAAO,cAAc,CAAC;AAC3C,OAAI,KAAK,IAAI;;EAEhB"}
|
package/dist/web.cjs
CHANGED
|
@@ -24,6 +24,7 @@ const require_untracked_value = require("./channels/untracked_value.cjs");
|
|
|
24
24
|
require("./channels/index.cjs");
|
|
25
25
|
const require_reduced = require("./state/values/reduced.cjs");
|
|
26
26
|
const require_untracked = require("./state/values/untracked.cjs");
|
|
27
|
+
const require_delta$1 = require("./state/values/delta.cjs");
|
|
27
28
|
const require_schema = require("./state/schema.cjs");
|
|
28
29
|
const require_messages_reducer = require("./graph/messages_reducer.cjs");
|
|
29
30
|
const require_messages$1 = require("./state/prebuilt/messages.cjs");
|
|
@@ -69,6 +70,7 @@ exports.Command = require_constants.Command;
|
|
|
69
70
|
exports.CommandInstance = require_constants.CommandInstance;
|
|
70
71
|
exports.CompiledStateGraph = require_state.CompiledStateGraph;
|
|
71
72
|
exports.DeltaChannel = require_delta.DeltaChannel;
|
|
73
|
+
exports.DeltaValue = require_delta$1.DeltaValue;
|
|
72
74
|
exports.END = require_constants.END;
|
|
73
75
|
exports.EmptyChannelError = require_errors.EmptyChannelError;
|
|
74
76
|
exports.EmptyInputError = require_errors.EmptyInputError;
|
|
@@ -96,6 +98,7 @@ Object.defineProperty(exports, "MemorySaver", {
|
|
|
96
98
|
});
|
|
97
99
|
exports.MessageGraph = require_message.MessageGraph;
|
|
98
100
|
exports.MessagesAnnotation = require_messages_annotation.MessagesAnnotation;
|
|
101
|
+
exports.MessagesDeltaValue = require_messages$1.MessagesDeltaValue;
|
|
99
102
|
exports.MessagesValue = require_messages$1.MessagesValue;
|
|
100
103
|
exports.MessagesZodMeta = require_messages_annotation.MessagesZodMeta;
|
|
101
104
|
exports.MessagesZodState = require_messages_annotation.MessagesZodState;
|
package/dist/web.d.cts
CHANGED
|
@@ -31,6 +31,7 @@ import { BaseLangGraphError, BaseLangGraphErrorFields, EmptyChannelError, EmptyI
|
|
|
31
31
|
import { isSerializableSchema, isStandardSchema } from "./state/types.cjs";
|
|
32
32
|
import { ReducedValue, ReducedValueInit } from "./state/values/reduced.cjs";
|
|
33
33
|
import { UntrackedValue, UntrackedValueInit } from "./state/values/untracked.cjs";
|
|
34
|
+
import { DeltaValue, DeltaValueInit } from "./state/values/delta.cjs";
|
|
34
35
|
import { AnyStateSchema, InferStateSchemaUpdate, InferStateSchemaValue, StateSchema, StateSchemaField, StateSchemaFieldToChannel, StateSchemaFields, StateSchemaFieldsToStateDefinition } from "./state/schema.cjs";
|
|
35
36
|
import { ConditionalEdgeRouter, ConditionalEdgeRouterTypes, ContextSchemaInit, ExtractStateType, ExtractUpdateType, GraphNode, GraphNodeReturnValue, GraphNodeTypes, StateDefinitionInit, StateGraphInit, StateGraphOptions, ToStateDefinition } from "./graph/types.cjs";
|
|
36
37
|
import { AddNodeOptions, CompiledGraph, CompiledGraphType, Graph, NodeSpec } from "./graph/graph.cjs";
|
|
@@ -42,7 +43,7 @@ import { MessageGraph, pushMessage } from "./graph/message.cjs";
|
|
|
42
43
|
import { EntrypointOptions, TaskOptions, entrypoint, getPreviousState, task } from "./func/index.cjs";
|
|
43
44
|
import { MessagesAnnotation, MessagesZodMeta, MessagesZodState } from "./graph/messages_annotation.cjs";
|
|
44
45
|
import { getJsonSchemaFromSchema, getSchemaDefaultGetter } from "./state/adapter.cjs";
|
|
45
|
-
import { MessagesValue } from "./state/prebuilt/messages.cjs";
|
|
46
|
+
import { MessagesDeltaValue, MessagesValue } from "./state/prebuilt/messages.cjs";
|
|
46
47
|
import { getConfig, getCurrentTaskInput, getStore, getWriter } from "./pregel/utils/config.cjs";
|
|
47
48
|
import { AsyncBatchedStore, BaseCheckpointSaver, BaseStore, Checkpoint, CheckpointMetadata, CheckpointTuple, GetOperation, InMemoryStore, Item, ListNamespacesOperation, MatchCondition, MemorySaver, NameSpacePath, NamespaceMatchType, Operation, OperationResults, PutOperation, SearchOperation, copyCheckpoint, emptyCheckpoint } from "@langchain/langgraph-checkpoint";
|
|
48
|
-
export { type AddNodeOptions, type AgentStatus, Annotation, type AnnotationRoot, AnyStateSchema, type AnyValue, AsyncBatchedStore, BaseChannel, BaseCheckpointSaver, BaseLangGraphError, BaseLangGraphErrorFields, BaseStore, type BinaryOperator, BinaryOperatorAggregate, COMMAND_SYMBOL, type CachePolicy, type ChatModelStream, ChatModelStreamImpl, type Checkpoint, type CheckpointMetadata, type CheckpointTuple, Command, CommandInstance, type CommandParams, type CompiledGraph, type CompiledGraphType, CompiledStateGraph, type ConditionalEdgeRouter, type ConditionalEdgeRouterTypes, type ContextSchemaInit, type ConvertToProtocolEventOptions, type CreateGraphRunStreamOptions, DeltaChannel, type DeltaReducer, type DynamicBarrierValue, END, EmptyChannelError, EmptyInputError, type EntrypointOptions, type EphemeralValue, StreamChannel as EventLog, type ExecutionInfo, type ExtractStateType, type ExtractUpdateType, type GetOperation, type GetStateOptions, Graph, GraphBubbleUp, GraphDrained, GraphInterrupt, type GraphNode, type GraphNodeReturnValue, type GraphNodeTypes, GraphRecursionError, GraphRunStream, GraphValueError, INTERRUPT, InMemoryStore, type InferExtensions, type InferInterruptInputType, type InferInterruptResumeType, InferStateSchemaUpdate, InferStateSchemaValue, type InferWriterType, type Interrupt, type InterruptPayload, InvalidUpdateError, type Item, type LangGraphRunnableConfig, type LastValue, type LifecycleCause, type LifecycleData, type LifecycleEntry, type LifecycleProjection, type LifecycleTransformerOptions, type ListNamespacesOperation, type MatchCondition, MemorySaver, MessageGraph, type Messages, MessagesAnnotation, type MessagesEventData, MessagesValue, MessagesZodMeta, MessagesZodState, type MultipleChannelSubscriptionOptions, MultipleSubgraphsError, type NameSpacePath, type NamedBarrierValue, type Namespace, type NamespaceMatchType, type NativeStreamTransformer, NodeError, NodeInterrupt, type NodePolicyOptions, type NodeSpec, NodeTimeoutError, type NodeType, type Operation, type OperationResults, Overwrite, type OverwriteValue, ParentCommand, type Pregel, type PregelNode, type PregelOptions, type PregelParams, type ProtocolEvent, type PutOperation, REMOVE_ALL_MESSAGES, ReducedValue, ReducedValueInit, RemoteException, type RetryPolicy, RunControl, type Runtime, START, STREAM_EVENTS_V3_MODES, type SearchOperation, Send, type SendOptions, type ServerInfo, type SingleChannelSubscriptionOptions, type SingleReducer, type StateDefinition, type StateDefinitionInit, StateGraph, type StateGraphAddNodeOptions, type StateGraphArgs, type StateGraphArgsWithInputOutputSchemas, type StateGraphArgsWithStateSchema, type StateGraphInit, StateGraphInputError, type StateGraphNodeSpec, type StateGraphOptions, StateSchema, StateSchemaField, StateSchemaFieldToChannel, StateSchemaFields, StateSchemaFieldsToStateDefinition, type StateSnapshot, type StateType, StreamChannel, type StreamEmitter, type StreamMode, type StreamOutputMap, type StreamTransformer, type SubgraphDiscoveryProjection, type SubgraphDiscoveryTransformerOptions, SubgraphRunStream, type TaskOptions, type TimeoutPolicy, type ToStateDefinition, type ToolCallStatus, type ToolCallStream, type ToolsEventData, type Topic, UnreachableNodeError, UntrackedValue, UntrackedValueChannel, UntrackedValueInit, type UpdateType, type UpdatesEventData, type UsageInfo, type WaitForNames, messagesStateReducer as addMessages, convertToProtocolEvent, copyCheckpoint, createGraphRunStream, createLifecycleTransformer, createMessagesTransformer, createSubgraphDiscoveryTransformer, createValuesTransformer, emptyCheckpoint, entrypoint, filterLifecycleEntries, filterSubgraphHandles, getConfig, getCurrentTaskInput, getJsonSchemaFromSchema, getPreviousState, getSchemaDefaultGetter, getStore, getSubgraphsSeenSet, getWriter, interrupt, isCheckpointEnvelope, isCommand, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isInterrupted, isNativeTransformer, isNodeError, isNodeTimeoutError, isParentCommand, isSerializableSchema, isStandardSchema, messagesDeltaReducer, messagesStateReducer, pushMessage, task, writer };
|
|
49
|
+
export { type AddNodeOptions, type AgentStatus, Annotation, type AnnotationRoot, AnyStateSchema, type AnyValue, AsyncBatchedStore, BaseChannel, BaseCheckpointSaver, BaseLangGraphError, BaseLangGraphErrorFields, BaseStore, type BinaryOperator, BinaryOperatorAggregate, COMMAND_SYMBOL, type CachePolicy, type ChatModelStream, ChatModelStreamImpl, type Checkpoint, type CheckpointMetadata, type CheckpointTuple, Command, CommandInstance, type CommandParams, type CompiledGraph, type CompiledGraphType, CompiledStateGraph, type ConditionalEdgeRouter, type ConditionalEdgeRouterTypes, type ContextSchemaInit, type ConvertToProtocolEventOptions, type CreateGraphRunStreamOptions, DeltaChannel, type DeltaReducer, DeltaValue, DeltaValueInit, type DynamicBarrierValue, END, EmptyChannelError, EmptyInputError, type EntrypointOptions, type EphemeralValue, StreamChannel as EventLog, type ExecutionInfo, type ExtractStateType, type ExtractUpdateType, type GetOperation, type GetStateOptions, Graph, GraphBubbleUp, GraphDrained, GraphInterrupt, type GraphNode, type GraphNodeReturnValue, type GraphNodeTypes, GraphRecursionError, GraphRunStream, GraphValueError, INTERRUPT, InMemoryStore, type InferExtensions, type InferInterruptInputType, type InferInterruptResumeType, InferStateSchemaUpdate, InferStateSchemaValue, type InferWriterType, type Interrupt, type InterruptPayload, InvalidUpdateError, type Item, type LangGraphRunnableConfig, type LastValue, type LifecycleCause, type LifecycleData, type LifecycleEntry, type LifecycleProjection, type LifecycleTransformerOptions, type ListNamespacesOperation, type MatchCondition, MemorySaver, MessageGraph, type Messages, MessagesAnnotation, MessagesDeltaValue, type MessagesEventData, MessagesValue, MessagesZodMeta, MessagesZodState, type MultipleChannelSubscriptionOptions, MultipleSubgraphsError, type NameSpacePath, type NamedBarrierValue, type Namespace, type NamespaceMatchType, type NativeStreamTransformer, NodeError, NodeInterrupt, type NodePolicyOptions, type NodeSpec, NodeTimeoutError, type NodeType, type Operation, type OperationResults, Overwrite, type OverwriteValue, ParentCommand, type Pregel, type PregelNode, type PregelOptions, type PregelParams, type ProtocolEvent, type PutOperation, REMOVE_ALL_MESSAGES, ReducedValue, ReducedValueInit, RemoteException, type RetryPolicy, RunControl, type Runtime, START, STREAM_EVENTS_V3_MODES, type SearchOperation, Send, type SendOptions, type ServerInfo, type SingleChannelSubscriptionOptions, type SingleReducer, type StateDefinition, type StateDefinitionInit, StateGraph, type StateGraphAddNodeOptions, type StateGraphArgs, type StateGraphArgsWithInputOutputSchemas, type StateGraphArgsWithStateSchema, type StateGraphInit, StateGraphInputError, type StateGraphNodeSpec, type StateGraphOptions, StateSchema, StateSchemaField, StateSchemaFieldToChannel, StateSchemaFields, StateSchemaFieldsToStateDefinition, type StateSnapshot, type StateType, StreamChannel, type StreamEmitter, type StreamMode, type StreamOutputMap, type StreamTransformer, type SubgraphDiscoveryProjection, type SubgraphDiscoveryTransformerOptions, SubgraphRunStream, type TaskOptions, type TimeoutPolicy, type ToStateDefinition, type ToolCallStatus, type ToolCallStream, type ToolsEventData, type Topic, UnreachableNodeError, UntrackedValue, UntrackedValueChannel, UntrackedValueInit, type UpdateType, type UpdatesEventData, type UsageInfo, type WaitForNames, messagesStateReducer as addMessages, convertToProtocolEvent, copyCheckpoint, createGraphRunStream, createLifecycleTransformer, createMessagesTransformer, createSubgraphDiscoveryTransformer, createValuesTransformer, emptyCheckpoint, entrypoint, filterLifecycleEntries, filterSubgraphHandles, getConfig, getCurrentTaskInput, getJsonSchemaFromSchema, getPreviousState, getSchemaDefaultGetter, getStore, getSubgraphsSeenSet, getWriter, interrupt, isCheckpointEnvelope, isCommand, isGraphBubbleUp, isGraphDrained, isGraphInterrupt, isInterrupted, isNativeTransformer, isNodeError, isNodeTimeoutError, isParentCommand, isSerializableSchema, isStandardSchema, messagesDeltaReducer, messagesStateReducer, pushMessage, task, writer };
|