{"version":3,"file":"graph.cjs","names":["id: string | undefined","data: RunnableInterface | RunnableIOSchema","isRunnableInterface","node: Node","toJsonSchema","params?: { nodes: Record<string, Node>; edges: Edge[] }","stableNodeIds: Record<string, string | number>","item: Record<string, unknown>","id?: string","metadata?: Record<string, any>","source: Node","target: Node","data?: string","conditional?: boolean","edge: Edge","graph: Graph","isUuid","id: string","nodeLabels: Record<string, string>","nodeId: string","params?: {\n    withStyles?: boolean;\n    curveStyle?: string;\n    nodeColors?: Record<string, string>;\n    wrapLabelNWords?: number;\n  }","drawMermaid","params?: {\n    withStyles?: boolean;\n    curveStyle?: string;\n    nodeColors?: Record<string, string>;\n    wrapLabelNWords?: number;\n    backgroundColor?: string;\n  }","drawMermaidImage","exclude: string[]","found: Node[]"],"sources":["../../src/runnables/graph.ts"],"sourcesContent":["import { v4 as uuidv4, validate as isUuid } from \"uuid\";\nimport type {\n  RunnableInterface,\n  RunnableIOSchema,\n  Node,\n  Edge,\n} from \"./types.js\";\nimport { isRunnableInterface } from \"./utils.js\";\nimport { drawMermaid, drawMermaidImage } from \"./graph_mermaid.js\";\nimport { toJsonSchema } from \"../utils/json_schema.js\";\n\nexport { Node, Edge };\n\nfunction nodeDataStr(\n  id: string | undefined,\n  data: RunnableInterface | RunnableIOSchema\n): string {\n  if (id !== undefined && !isUuid(id)) {\n    return id;\n  } else if (isRunnableInterface(data)) {\n    try {\n      let dataStr = data.getName();\n      dataStr = dataStr.startsWith(\"Runnable\")\n        ? dataStr.slice(\"Runnable\".length)\n        : dataStr;\n      return dataStr;\n    } catch {\n      return data.getName();\n    }\n  } else {\n    return data.name ?? \"UnknownSchema\";\n  }\n}\n\nfunction nodeDataJson(node: Node) {\n  // if node.data implements Runnable\n  if (isRunnableInterface(node.data)) {\n    return {\n      type: \"runnable\",\n      data: {\n        id: node.data.lc_id,\n        name: node.data.getName(),\n      },\n    };\n  } else {\n    return {\n      type: \"schema\",\n      data: { ...toJsonSchema(node.data.schema), title: node.data.name },\n    };\n  }\n}\n\nexport class Graph {\n  nodes: Record<string, Node> = {};\n\n  edges: Edge[] = [];\n\n  constructor(params?: { nodes: Record<string, Node>; edges: Edge[] }) {\n    this.nodes = params?.nodes ?? this.nodes;\n    this.edges = params?.edges ?? this.edges;\n  }\n\n  // Convert the graph to a JSON-serializable format.\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  toJSON(): Record<string, any> {\n    const stableNodeIds: Record<string, string | number> = {};\n    Object.values(this.nodes).forEach((node, i) => {\n      stableNodeIds[node.id] = isUuid(node.id) ? i : node.id;\n    });\n\n    return {\n      nodes: Object.values(this.nodes).map((node) => ({\n        id: stableNodeIds[node.id],\n        ...nodeDataJson(node),\n      })),\n      edges: this.edges.map((edge) => {\n        const item: Record<string, unknown> = {\n          source: stableNodeIds[edge.source],\n          target: stableNodeIds[edge.target],\n        };\n\n        if (typeof edge.data !== \"undefined\") {\n          item.data = edge.data;\n        }\n\n        if (typeof edge.conditional !== \"undefined\") {\n          item.conditional = edge.conditional;\n        }\n        return item;\n      }),\n    };\n  }\n\n  addNode(\n    data: RunnableInterface | RunnableIOSchema,\n    id?: string,\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    metadata?: Record<string, any>\n  ): Node {\n    if (id !== undefined && this.nodes[id] !== undefined) {\n      throw new Error(`Node with id ${id} already exists`);\n    }\n    const nodeId = id ?? uuidv4();\n    const node: Node = {\n      id: nodeId,\n      data,\n      name: nodeDataStr(id, data),\n      metadata,\n    };\n    this.nodes[nodeId] = node;\n    return node;\n  }\n\n  removeNode(node: Node): void {\n    // Remove the node from the nodes map\n    delete this.nodes[node.id];\n\n    // Filter out edges connected to the node\n    this.edges = this.edges.filter(\n      (edge) => edge.source !== node.id && edge.target !== node.id\n    );\n  }\n\n  addEdge(\n    source: Node,\n    target: Node,\n    data?: string,\n    conditional?: boolean\n  ): Edge {\n    if (this.nodes[source.id] === undefined) {\n      throw new Error(`Source node ${source.id} not in graph`);\n    }\n    if (this.nodes[target.id] === undefined) {\n      throw new Error(`Target node ${target.id} not in graph`);\n    }\n    const edge: Edge = {\n      source: source.id,\n      target: target.id,\n      data,\n      conditional,\n    };\n    this.edges.push(edge);\n    return edge;\n  }\n\n  firstNode(): Node | undefined {\n    return _firstNode(this);\n  }\n\n  lastNode(): Node | undefined {\n    return _lastNode(this);\n  }\n\n  /**\n   * Add all nodes and edges from another graph.\n   * Note this doesn't check for duplicates, nor does it connect the graphs.\n   */\n  extend(graph: Graph, prefix = \"\") {\n    let finalPrefix = prefix;\n    const nodeIds = Object.values(graph.nodes).map((node) => node.id);\n    if (nodeIds.every(isUuid)) {\n      finalPrefix = \"\";\n    }\n\n    const prefixed = (id: string) => {\n      return finalPrefix ? `${finalPrefix}:${id}` : id;\n    };\n\n    Object.entries(graph.nodes).forEach(([key, value]) => {\n      this.nodes[prefixed(key)] = { ...value, id: prefixed(key) };\n    });\n\n    const newEdges = graph.edges.map((edge) => {\n      return {\n        ...edge,\n        source: prefixed(edge.source),\n        target: prefixed(edge.target),\n      };\n    });\n    // Add all edges from the other graph\n    this.edges = [...this.edges, ...newEdges];\n    const first = graph.firstNode();\n    const last = graph.lastNode();\n    return [\n      first ? { id: prefixed(first.id), data: first.data } : undefined,\n      last ? { id: prefixed(last.id), data: last.data } : undefined,\n    ];\n  }\n\n  trimFirstNode(): void {\n    const firstNode = this.firstNode();\n    if (firstNode && _firstNode(this, [firstNode.id])) {\n      this.removeNode(firstNode);\n    }\n  }\n\n  trimLastNode(): void {\n    const lastNode = this.lastNode();\n    if (lastNode && _lastNode(this, [lastNode.id])) {\n      this.removeNode(lastNode);\n    }\n  }\n\n  /**\n   * Return a new graph with all nodes re-identified,\n   * using their unique, readable names where possible.\n   */\n  reid(): Graph {\n    const nodeLabels: Record<string, string> = Object.fromEntries(\n      Object.values(this.nodes).map((node) => [node.id, node.name])\n    );\n    const nodeLabelCounts = new Map<string, number>();\n    Object.values(nodeLabels).forEach((label) => {\n      nodeLabelCounts.set(label, (nodeLabelCounts.get(label) || 0) + 1);\n    });\n\n    const getNodeId = (nodeId: string): string => {\n      const label = nodeLabels[nodeId];\n      if (isUuid(nodeId) && nodeLabelCounts.get(label) === 1) {\n        return label;\n      } else {\n        return nodeId;\n      }\n    };\n\n    return new Graph({\n      nodes: Object.fromEntries(\n        Object.entries(this.nodes).map(([id, node]) => [\n          getNodeId(id),\n          { ...node, id: getNodeId(id) },\n        ])\n      ),\n      edges: this.edges.map((edge) => ({\n        ...edge,\n        source: getNodeId(edge.source),\n        target: getNodeId(edge.target),\n      })),\n    });\n  }\n\n  drawMermaid(params?: {\n    withStyles?: boolean;\n    curveStyle?: string;\n    nodeColors?: Record<string, string>;\n    wrapLabelNWords?: number;\n  }): string {\n    const {\n      withStyles,\n      curveStyle,\n      nodeColors = {\n        default: \"fill:#f2f0ff,line-height:1.2\",\n        first: \"fill-opacity:0\",\n        last: \"fill:#bfb6fc\",\n      },\n      wrapLabelNWords,\n    } = params ?? {};\n    const graph = this.reid();\n    const firstNode = graph.firstNode();\n\n    const lastNode = graph.lastNode();\n\n    return drawMermaid(graph.nodes, graph.edges, {\n      firstNode: firstNode?.id,\n      lastNode: lastNode?.id,\n      withStyles,\n      curveStyle,\n      nodeColors,\n      wrapLabelNWords,\n    });\n  }\n\n  async drawMermaidPng(params?: {\n    withStyles?: boolean;\n    curveStyle?: string;\n    nodeColors?: Record<string, string>;\n    wrapLabelNWords?: number;\n    backgroundColor?: string;\n  }): Promise<Blob> {\n    const mermaidSyntax = this.drawMermaid(params);\n    return drawMermaidImage(mermaidSyntax, {\n      backgroundColor: params?.backgroundColor,\n    });\n  }\n}\n/**\n * Find the single node that is not a target of any edge.\n * Exclude nodes/sources with ids in the exclude list.\n * If there is no such node, or there are multiple, return undefined.\n * When drawing the graph, this node would be the origin.\n */\nfunction _firstNode(graph: Graph, exclude: string[] = []): Node | undefined {\n  const targets = new Set(\n    graph.edges\n      .filter((edge) => !exclude.includes(edge.source))\n      .map((edge) => edge.target)\n  );\n\n  const found: Node[] = [];\n  for (const node of Object.values(graph.nodes)) {\n    if (!exclude.includes(node.id) && !targets.has(node.id)) {\n      found.push(node);\n    }\n  }\n  return found.length === 1 ? found[0] : undefined;\n}\n\n/**\n * Find the single node that is not a source of any edge.\n * Exclude nodes/targets with ids in the exclude list.\n * If there is no such node, or there are multiple, return undefined.\n * When drawing the graph, this node would be the destination.\n */\nfunction _lastNode(graph: Graph, exclude: string[] = []): Node | undefined {\n  const sources = new Set(\n    graph.edges\n      .filter((edge) => !exclude.includes(edge.target))\n      .map((edge) => edge.source)\n  );\n\n  const found: Node[] = [];\n  for (const node of Object.values(graph.nodes)) {\n    if (!exclude.includes(node.id) && !sources.has(node.id)) {\n      found.push(node);\n    }\n  }\n  return found.length === 1 ? found[0] : undefined;\n}\n"],"mappings":"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"}