/** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type { BaseAgent } from '../agents/base_agent.js'; import { BaseTool } from '../tools/base_tool.js'; import { BaseNode } from './base_node.js'; /** * A unique symbol branding {@link Edge} instances. * * `isEdge` matches on this brand rather than `instanceof` so an edge built * by another copy of adk-js in the same runtime is still recognised (an * `instanceof` check fails across package copies) — mirroring the * `Symbol.for('google.adk.*')` brands used across ADK. */ declare const EDGE_SIGNATURE_SYMBOL: unique symbol; /** Valid routing values used in conditional graph edges. */ export type RouteValue = boolean | number | string; /** The fallback route key used when no specific route matches. */ export declare const DEFAULT_ROUTE = "__DEFAULT__"; /** * Any value that can be converted to a workflow node: a node, a tool, a plain * function, or the `'START'` sentinel literal. (Agent wrapping is added in * Phase 3 via `build_node`.) */ export type NodeLike = BaseNode | BaseAgent | BaseTool | ((...args: never[]) => unknown) | 'START'; /** * What `ctx.runNode()` accepts: everything an edge accepts except the `'START'` * sentinel, which marks a graph entry point rather than something runnable. */ export type RunnableNode = Exclude; /** * A mapping from route values to destination node(s). A value may be a single * node or an array of nodes (fan-out). * * @example * {question: answerNode, statement: commentNode} * {retry: [nodeA, nodeB]} // fan-out: both triggered * * @remarks * JavaScript object keys are always strings, so a numeric key (`{2: node}`) and * a boolean key (`{true: node}`) are reconstructed to their typed * {@link RouteValue} (`2`, `true`) when parsed — mirroring Python dict keys. * Because of this, routes are matched **by string value** * ({@link Graph.getNextPendingNodes} compares `String(route)` on both sides), so * a node emitting `2` and one emitting `'2'` both fire a `{2: node}` edge. The * flip side is that a numeric/boolean-looking route and its string spelling * cannot be distinguished in a routing map; use distinct, non-ambiguous route * keys when that matters. */ export type RoutingMap = Record; /** An element within a workflow chain. */ export type ChainElement = NodeLike | readonly NodeLike[] | RoutingMap; /** * An item that can be parsed into workflow edges: an explicit {@link Edge}, or a * chain expressed as an array of {@link ChainElement}s (e.g. * `['START', nodeA, nodeB]`). */ export type EdgeItem = Edge | ChainElement[]; /** * A directed edge in the workflow graph. * * Mirrors `google/adk-python` `workflow/_graph.py::Edge`. */ export declare class Edge { readonly fromNode: BaseNode; readonly toNode: BaseNode; /** * The route(s) this edge is associated with. `null` means unconditional * (always triggered). A single value or a list; the edge fires when the * emitted route matches any listed value. */ readonly route: RouteValue | RouteValue[] | null; /** Brand identifying this object as an {@link Edge} (see `isEdge`). */ readonly [EDGE_SIGNATURE_SYMBOL] = true; constructor(fromNode: BaseNode, toNode: BaseNode, /** * The route(s) this edge is associated with. `null` means unconditional * (always triggered). A single value or a list; the edge fires when the * emitted route matches any listed value. */ route?: RouteValue | RouteValue[] | null); } /** * Type guard for {@link Edge}. * * Matches on the {@link EDGE_SIGNATURE_SYMBOL} brand rather than `instanceof` so * it stays correct across package copies (see the brand's doc). */ export declare function isEdge(value: unknown): value is Edge; /** * A compiled workflow graph. Nodes are inferred (deduped by identity) from the * edges. * * Mirrors `google/adk-python` `workflow/_graph.py::Graph`. */ export declare class Graph { readonly nodes: BaseNode[]; readonly edges: Edge[]; private _terminalNodeNames; constructor(edges: Edge[]); /** Terminal node names (no outgoing edges); populated by {@link validate}. */ get terminalNodeNames(): ReadonlySet; /** * Determines the next nodes to transition to PENDING based on the route(s) * emitted by a completed node. Ported from Python `get_next_pending_nodes`. * * Logs at debug when the node emitted a route, has conditional outgoing * edges, and none of them (nor a `DEFAULT_ROUTE` edge) matched — the branch * stops there, which is easy to mistake for a bug. Behaviour is unchanged. */ getNextPendingNodes(nodeName: string, routesToMatch: RouteValue | RouteValue[] | null | undefined): string[]; /** Validates the graph and computes terminal node names. */ validate(): void; } /** * Builds, validates, and returns a {@link Graph} from a list of edge items. * * Validation runs here (not opt-in) so structural problems a graph can only * have at build time — unreachable nodes, duplicate names/edges, routed edges * from START, unconditional cycles — fail loudly at construction rather than * surfacing as silent mis-routing at run time. It also populates the graph's * {@link Graph.terminalNodeNames}, which is otherwise empty. */ export declare function createGraphFromEdgeItems(edgeItems: EdgeItem[]): Graph; export {};