Metadata-Version: 2.4
Name: agentgraph-compiler
Version: 0.2.0
Summary: Compile structured YAML configurations into production-grade LangGraph multi-agent architectures.
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/your-org/GraphForge
Project-URL: Repository, https://github.com/your-org/GraphForge
Project-URL: Bug Tracker, https://github.com/your-org/GraphForge/issues
Project-URL: Documentation, https://github.com/your-org/GraphForge/blob/main/WIKI.md
Keywords: langgraph,langchain,multi-agent,ai,llm,compiler,yaml
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: langchain>=0.3.0
Requires-Dist: langchain-community>=0.3.0
Requires-Dist: langchain-core>=0.3.0
Requires-Dist: langchain-anthropic>=0.3.0
Requires-Dist: langchain-groq>=0.2.0
Requires-Dist: langchain-ollama>=0.2.0
Requires-Dist: langchain-openai>=0.2.0
Requires-Dist: langchain-qdrant>=0.1.0
Requires-Dist: langchain-tavily>=0.1.0
Requires-Dist: langgraph>=0.2.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: pinecone
Requires-Dist: langchain-pinecone>=0.2.0; extra == "pinecone"
Provides-Extra: qdrant
Requires-Dist: qdrant-client>=1.7.0; extra == "qdrant"
Requires-Dist: langchain-qdrant>=0.1.0; extra == "qdrant"
Provides-Extra: tavily
Requires-Dist: tavily-python>=0.3.0; extra == "tavily"
Requires-Dist: langchain-tavily>=0.1.0; extra == "tavily"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: isort>=5.13.0; extra == "dev"
Requires-Dist: ruff>=0.3.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# GraphForge 🛠️🦜🔗

**Compile structured YAML configurations into production‑grade LangGraph multi‑agent architectures.**

GraphForge eliminates LangGraph boilerplate by letting you declare your agent topology in YAML. Define nodes, chains, tools, edges, sub‑agents, and supervisors — the compiler scaffolds a complete, modular, runnable Python codebase ready for production.

📖 **[Full Developer Wiki →](WIKI.md)** — complete reference for every YAML field, node type, edge type, and generated output.

---

## 🚀 Key Features

- **Declarative Multi‑Agent Workflows** — Define the full agent graph (nodes, edges, sub‑agents, supervisor routing) in simple YAML.
- **TypedDict State (LangGraph‑native)** — Generates `TypedDict` classes with `Annotated[..., add_messages]` reducers by default. Pydantic `BaseModel` is available via `state_type: pydantic`.
- **Supervisor Orchestration** — `type: supervisor` nodes generate an LLM-driven routing scaffold with configurable `route_field` and compile-time validation.
- **Hierarchical Parent-Scoped Output** — Sub-agent code is generated inside subdirectories under the parent `source_dir` (e.g. `my_agent/adaptive_rag/`).
- **All LangGraph Edge Types** — `standard`, `conditional`, `supervisor_route`, `tool_loop`, `fan_out` (Send API), and `interrupt_before` human‑in‑the‑loop.
- **Parallel Fan-Out via `Send` API** — `type: fan_out` dispatches one node to multiple inputs simultaneously using `langgraph.types.Send`.
- **Async Node Scaffolding** — `async_fn: true` generates `async def` node functions with notes on awaiting LLM/tool calls.
- **Multi-Model LLM Support** — `provider: openai | anthropic | ollama | groq` per chain or supervisor node with model-specific imports scaffolded.
- **MCP Tool Client Stubs** — `source: mcp` in the `tools` block scaffolds a Model Context Protocol client.
- **Checkpointing** — `memory.type: sqlite | in_memory` wires `SqliteSaver` / `MemorySaver` into `workflow.compile()`.
- **Real-time Streaming** — Generated `main.py` uses `app.stream()` with thread config for node-by-node event output.
- **Mermaid Flowcharts** — Auto-generates `flowchart.md` with nested subgraph rendering and distinct supervisor styling.
- **CLI** — `forge compile`, `forge validate`, `forge init`, `forge ingest`, plus `--dry-run` preview.

---

## 🛠️ Quick Start

### 1. Install

**Option A — PyPI** *(once published)*
```bash
pip install graphforge
# or
uv add graphforge
```

**Option B — Directly from GitHub** *(available now, no clone needed)*
```bash
pip install git+https://github.com/your-org/GraphForge.git
```

**Option C — Clone for local development**
```bash
git clone https://github.com/your-org/GraphForge.git
cd GraphForge
uv sync
```

After any install, the `forge` CLI is available in your environment:

```bash
forge --help
```

### 2. Initialize a Project

```bash
uv run forge init
```

Creates:
- `configs/config.yaml` — Global settings (models, vector store, embedding)
- `configs/agents/agent.yaml` — Starter agent workflow spec

### 3. Configure Environment

```bash
cp .env.example .env
# Fill in OPENAI_API_KEY (and optionally LANGCHAIN_API_KEY for tracing)
```

### 4. Validate Configuration

```bash
uv run forge validate configs/agents/agent.yaml
```

Runs Pydantic schema validation and checks all edge targets exist as declared nodes — without writing any files.

### 5. Compile Agent Topology

```bash
# Preview without writing files
uv run forge compile configs/agents/agent.yaml --dry-run

# Compile Python scaffold
uv run forge compile configs/agents/agent.yaml
```

### 6. Run the Agent

```bash
uv run python my_agent/main.py "How do I build multi-agent graphs with GraphForge?"
```

---

## 💡 Try an Example

Six ready-to-compile examples cover every supported LangGraph pattern — all configs live in `configs/agents/examples/`:

| Example | Pattern |
|---|---|
| `simple_rag/` | Single-agent RAG with conditional edges |
| `multi_agent/` | Supervisor + 2 sub-agents via `graphRef` |
| `react_agent/` | ReAct `tool_loop` + MCP tool client |
| `parallel_fanout/` | Parallel `fan_out` via Send API |
| `human_in_loop/` | `interrupt_before` + approve/revise cycle |
| `async_agent/` | `async_fn: true` async nodes |

```bash
# Example: compile and run the ReAct agent
uv run forge compile configs/agents/examples/react_agent/agent.yaml
uv run python react_agent/main.py "What is the current price of Bitcoin?"
```

See [`configs/agents/examples/README.md`](configs/agents/examples/README.md) for compile/run instructions for all examples.

---

## 📖 CLI Reference

| Command | Usage | Description |
|---|---|---|
| `compile` | `forge compile <path> [--dry-run]` | Compiles YAML into Python scaffolds under `source_dir`. |
| `validate` | `forge validate <path>` | Schema validation + edge target reference checks. |
| `init` | `forge init [directory]` | Scaffolds starter `configs/config.yaml` and `agent.yaml`. |
| `ingest` | `forge ingest [--config path]` | Ingests URLs from `config.yaml` into Qdrant vector store. |

---

## ⚙️ Global Configuration (`configs/config.yaml`)

Centralize model providers, vector store settings, and ingestion URLs:

```yaml
models:
  chat:
    name: gpt-4o
    temperature: 0.5
  embedding:
    name: text-embedding-3-small
    provider: openai

vector_store:
  name: qdrant
  url: "http://localhost:6333"
  collection: "agent"

ingestion:
  urls:
    - "https://lilianweng.github.io/posts/2023-06-23-agent/"
```

---

## 📖 YAML Reference

### Graph Config

```yaml
version: "1.0"

graph:
  source_dir: "my_agent"               # Output directory for scaffolded Python code
  state_type: typeddict                 # "typeddict" (default, LangGraph-native) | "pydantic"
  state_schema: "graphs.state.AgentState"
  state_fields:
    messages: "List[BaseMessage]"       # → Annotated[List[BaseMessage], add_messages]
    next: "str"                         # Supervisor routing field
    context: "dict"
  shared_fields: [messages, context]    # Fields readable/writable by sub-agents
  memory:
    type: sqlite                        # "sqlite" | "in_memory" | omit for stateless
    db_path: ".checkpoints/agent.db"
```

### Node Types

```yaml
nodes:
  # Standard node — calls a Python function
  my_node:
    module: "graphs.nodes.my_node"
    function: "my_node"
    chains: ["my_chain"]              # Chains to import into the node
    description: "Does something useful."

  # Async node
  async_node:
    module: "graphs.nodes.async_node"
    async_fn: true                    # Scaffolds `async def async_node(state)`

  # Supervisor node — LLM-driven router
  supervisor:
    type: supervisor
    provider: openai                  # openai | anthropic | ollama | groq
    llm: gpt-4o
    route_field: next                 # State field the supervisor writes to (default: "next")
    system_prompt: "templates/supervisor.prompt"
    routes_to: [rag_agent, code_agent]

  # Sub-agent reference — compiles recursively, nested under parent source_dir
  rag_agent:
    graphRef: "sub-agents/adaptive-rag.yaml"
    description: "Adaptive RAG sub-agent."
```

### Chain Config

```yaml
chains:
  retrieval_grader:
    module: "graphs.chains.retrieval_grader"
    runnable: "retrieval_grader"
    provider: anthropic                         # Per-chain provider
    llm: claude-3-5-haiku-20241022
    temperature: 0.0
    prompt: "retrieval_grader"                  # Loads templates/retrieval_grader.prompt
    tools: [web_search]                         # Binds tool imports into chain scaffold
    description: "Binary relevance grader."
```

### Edge Types

```yaml
edges:
  # Standard directed edge
  - type: standard
    start: retrieve
    end: grade_documents

  # Conditional edge with a router function
  - type: conditional
    start: grade_documents
    router:
      module: "routers.router"
      function: "route_after_grading"
    mappings:
      web_search: web_search
      generate: generate

  # Supervisor routing — dispatches based on state[route_field]
  - type: supervisor_route
    start: supervisor
    routes_to: [rag_agent, code_agent]
    end: post_process

  # Tool loop — LLM node ↔ ToolNode
  - type: tool_loop
    start: llm_node
    tool_node: tools
    end: END

  # Fan-out — parallel dispatch via Send API
  - type: fan_out
    start: coordinator
    target: worker              # Node to fan out to (runs in parallel)
    field: tasks                # State field (iterable) to fan out over
    key: task                   # Key name in each Send payload
    end: aggregator

  # Human-in-the-loop — pause before this node
  - type: standard
    start: generate
    end: human_review
    interrupt_before: true
```

### Tool Config

```yaml
tools:
  web_search:
    module: "graphs.tools.web_search"
    function: "web_search"
    description: "Queries Tavily for web results."

  # MCP Tool Client stub
  my_mcp_tool:
    module: "graphs.tools.my_mcp_tool"
    function: "my_mcp_tool"
    source: mcp
    server_url: "http://localhost:8000/mcp"
    description: "Calls remote MCP server."
```

---

## 📊 Generated Flowchart

GraphForge auto-generates `flowchart.md` for every compiled agent:

```mermaid
flowchart TD
    START([START]) --> supervisor{{"Supervisor: supervisor\n(Routes request to sub-agent)"}}
    supervisor -.->|rag_agent| rag_agent__START
    supervisor -.->|code_agent| code_agent__START

    subgraph rag_agent ["rag_agent (Adaptive RAG Sub-Agent)"]
        direction TB
        rag_agent__START --> retrieve["retrieve\n(Pulls document chunks from vector store)"]
        retrieve --> grade_documents["grade_documents"]
        grade_documents --> generate["generate"]
    end

    subgraph code_agent ["code_agent (Code Generator Sub-Agent)"]
        direction TB
        code_agent__START --> plan["plan\n(Breaks task into plan)"]
        plan --> write_code["write_code"]
    end

    rag_agent__END --> post_process["post_process\n(Formats final response)"]
    code_agent__END --> post_process
    post_process --> END([END])

    classDef supervisorStyle fill:#d35400,stroke:#fff,stroke-width:2px,color:#fff;
    class supervisor supervisorStyle;
    classDef nodeStyle fill:#2980b9,stroke:#fff,stroke-width:2px,color:#fff;
    class post_process nodeStyle;
```

---

## 📁 Generated Output Structure

`forge compile configs/agents/agent.yaml` scaffolds the full hierarchy under `source_dir`:

```text
my_agent/                               ← Parent source_dir
├── flowchart.md                        ← Mermaid diagram of the multi-agent DAG
├── main.py                             ← Runnable entrypoint with app.stream()
├── graphs/
│   ├── __init__.py
│   ├── graph.py                        ← Compiled StateGraph + checkpointer
│   ├── state.py                        ← TypedDict AgentState with add_messages reducer
│   ├── chains/
│   │   └── post_process_chain.py
│   └── nodes/
│       ├── supervisor.py               ← LLM routing scaffold
│       └── post_process.py
│
├── adaptive_rag/                       ← Sub-agent nested under my_agent/
│   ├── graphs/
│   │   ├── graph.py
│   │   ├── state.py
│   │   └── nodes/
│   └── routers/
│
└── code_agent/                         ← Sub-agent nested under my_agent/
    ├── graphs/
    └── routers/
```

---

## 🔍 Observability (LangSmith)

Enable full step-by-step tracing in `.env`:

```bash
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=your_langchain_api_key
LANGCHAIN_PROJECT=GraphForge-Agents
```

---

## 🧪 Tests

```bash
uv run pytest -v
```

CI runs on every push via `.github/workflows/ci.yml`.

---

## 🤝 Contributing

See [`CONTRIBUTING.md`](CONTRIBUTING.md) for dev setup, how to add new edge/node types, and the PR process.

---

## 📦 License

Released under the [Apache 2.0 License](LICENSE). Version `0.2.0`.
