/** * Surface 3 — `withDarwinEvolution(graph, opts)`. * * Wraps a compiled `StateGraph` with a fire-and-forget post-run hook * that mirrors Darwin's closed-loop evolution pattern (see * `agents/lib/darwin-hook.ts` for the in-tree Nex implementation): * * 1. After `graph.invoke(...)` resolves, we extract trajectories from * the final state and dispatch them to `opts.onTrajectory` per * mapped node. * 2. The same applies to `graph.stream(...)` — we wrap the async * iterator and replay the final-state chunk to the hook once the * consumer finishes iterating. * * Design notes (S1185): * - **Never throws inside the hook.** Caller logic that fails inside * `onTrajectory` is logged once per process and otherwise swallowed. * The graph result the consumer sees is identical with or without * the wrap. * - **No mutation of `graph` if it doesn't expose `invoke`/`stream` * as own properties.** We bind via `Object.defineProperty` and fall * back to a no-op wrap if the graph is frozen. This means future * LangGraph internals that move `invoke` to a hidden prototype slot * won't crash — at worst, the hook silently never fires (the test * suite catches that case). * - **`nodeMap` shape:** either `string` (treated as * `{ agentName: string, trajectoryKey: defaultKey }`) or an object * with explicit `trajectoryKey`. Supports both ergonomic one-liner * and per-node trajectory routing in the same graph. */ import type { ExecutionTrace } from "darwin-agents"; /** Map entry — either a bare agent name or an explicit `{agent, key}` tuple. */ export type DarwinNodeMapEntry = string | { agentName: string; trajectoryKey: string; }; /** Argument passed to {@link DarwinEvolutionOptions.onTrajectory}. */ export interface DarwinTrajectoryEvent { /** Name of the StateGraph node that produced the trajectory. */ nodeName: string; /** Darwin agent name (from the `nodeMap` mapping). */ agentName: string; /** The captured execution trace. */ trajectory: ExecutionTrace; /** * Snapshot of the final graph state. The TOP-LEVEL object is frozen * (shallow), but NESTED objects (incl. the trajectory itself) are NOT * deep-frozen for performance — treat them as logically immutable by * convention. Mutating nested values leaks back into the live graph * state and corrupts subsequent runs (R1 Critic Finding 4, S1185). */ finalState: Readonly>; /** * LangChain runId of the node-chain that produced this trajectory. * Only populated by {@link DarwinCallbackHandler} (v0.2+) where the * runId is part of the LangChain callback contract. Undefined for the * legacy `withDarwinEvolution` monkey-patch path (no runId there). * * Stable identifier suitable for correlation with OTEL spans, Langfuse * traces, LangSmith runs, or custom run-id-based logging. * * NEW V0.3 (S1187). */ runId?: string; /** * LangChain parentRunId — the runId of the chain that invoked this * node-chain. For top-level graph invokes the parent is the graph * itself. For child graphs / nested invocations the parent is the * outer graph's runId. Only populated by {@link DarwinCallbackHandler}. * * Use this to build span/trace hierarchies in OTEL exporters, * Langfuse, etc. * * NEW V0.3 (S1187). */ parentRunId?: string; /** * `true` when the trajectory's serialised size exceeded the configured * `maxTrajectoryBytes` cap and was replaced with a structurally * compatible BUT minimal stub by {@link DarwinCallbackHandler}. The * stub preserves `version`, all aggregate counts (`turnCount` / * `textBlockCount` / `mcpInvocations`), `capturedAt`, and any captured * `tokenUsage`, but replaces `toolCalls` and `errors` with empty * arrays. Use this flag to branch on degraded payloads in OTEL exporters * or alerting. * * Omitted (not `false`) when the trajectory passed through unchanged * — consumers should treat the absence of the field as "intact". * * NEW V0.4 (S1235). */ trajectoryTruncated?: boolean; } /** Options for {@link withDarwinEvolution}. */ export interface DarwinEvolutionOptions { /** * Maps StateGraph node names to either a bare Darwin agent name * (uses `darwinTrajectory` as the state key) or an object specifying * a custom `trajectoryKey` for that node. * * Example: * ```ts * nodeMap: { * research: "researcher", * review: { agentName: "critic", trajectoryKey: "criticTrajectory" }, * } * ``` */ nodeMap: Record; /** * Called once per mapped node whose trajectory was found in the final * state. Errors are swallowed — never breaks the graph result. */ onTrajectory?: (event: DarwinTrajectoryEvent) => void | Promise; /** Default trajectory key when `nodeMap` entry is a bare string. Default: `"darwinTrajectory"`. */ defaultTrajectoryKey?: string; } /** Minimal interface the adapter needs — covers `CompiledStateGraph`. */ interface InvokableGraph { invoke(input: unknown, config?: unknown): Promise; stream(input: unknown, config?: unknown): Promise>; } export declare function withDarwinEvolution(graph: G, opts: DarwinEvolutionOptions): G; export {}; //# sourceMappingURL=with-darwin-evolution.d.ts.map