Skip to content

Repository files navigation

AgentForge

A low-code framework for generating agentic AI systems from a prompt or spec. You describe what you want; meta-agents design the system and emit runnable LangGraph code. The LLM runs through OpenRouter — no local GPU required.

Runtime backend: LangGraph only for now. CrewAI is a planned second backend (the DSL and compiler are structured to add it without touching the meta-agents).


The core idea: separate generation from compilation

User prompt
↓ (LLM via OpenRouter, meta-agents)
DSL (SystemSpec) ← humans can read & edit this; it's the contract
↓ (deterministic compiler — NO LLM)
LangGraph Python ← reproducible, byte-identical for a given DSL
↓
Running agentic system (SQLite-checkpointed, resumable)

LLM creativity is confined to producing the DSL. Turning DSL into code is pure, testable machinery — so generated systems are reproducible and debuggable.


Installation

pip install agentsynth

Quick start

# 1. Set your OpenRouter API keyecho"OPENROUTER_API_KEY=sk-or-..."> .env
# 2. Generate a spec from a prompt
agentforge generate "Build a research assistant that reads docs and summarises them"# 3. Validate the generated spec
agentforge validate research_assistant.yaml
# 4. Compile to a runnable LangGraph app
agentforge compile research_assistant.yaml -o research_app.py
# 5. Run it
python research_app.py "What is retrieval-augmented generation?"

CLI reference

CommandDescriptionNeeds API key?
generate "<prompt>" [-o spec.yaml] [--model MODEL] [--no-review]Run meta-pipeline: prompt → DSL spec
compile <spec.yaml> [-o out.py]Deterministically compile a DSL to LangGraph Python
validate <spec.yaml>Static-check a DSL (reachability, routing, tools)
# Override the model (any OpenRouter model ID)
agentforge generate "..." --model qwen/qwen3-coder:free
# Skip human review checkpoints (fully autonomous)
agentforge generate "..." --no-review

Pipeline stages

generate runs six stages automatically. Three pause for human review.

StageWhat it doesHuman checkpoint
parseprompt → structured requirements + open questions
architectchoose topology, agent roles, patterns
designconcrete agents, prompts, graph wiring
resolve_toolsmap capabilities to local tool registry, flag gaps
compileDSL → LangGraph (deterministic)
validatestatic checks + convergence smoke test

At each checkpoint the full intermediate artifact is printed as YAML. Paste edited YAML then press Enter twice to override, or just Enter to accept.


The DSL

name: research_assistant # snake_case system identifierruntime: langgraphllm:
provider: openrouter # "openrouter" (default) or "ollama"model: qwen/qwen3-coder:free # any model available on the providertemperature: 0.1base_url: https://openrouter.ai/api/v1agents:
- id: researcher # snake_case node namerole: "Gather information and draft a summary."tools: [doc_loader] # names from the tool registrymemory: vector # none | buffer | vectormodel: null # optional per-agent model override
- id: criticrole: > Review the draft for accuracy and gaps. If revision is needed, emit 'ROUTE: needs_revision'. If the draft is good, emit 'ROUTE: approved'.memory: buffergraph:
entry: researcheredges:
- { from: researcher, to: critic }
- { from: critic, to: researcher, condition: needs_revision }
- { from: critic, to: END, condition: approved }success_criteria:
- "Final answer addresses the user's question"
- "Critic approved the draft"

DSL fields

llm (system-wide default; overridable per agent via model:)

FieldDefaultNotes
provideropenrouter"openrouter" or "ollama"
modelqwen/qwen3-coder:freeAny model ID valid for the provider
temperature0.10.0 – 2.0
base_urlhttps://openrouter.ai/api/v1Override for self-hosted or Ollama

agents[]

FieldRequiredNotes
id[a-z][a-z0-9_]*
roleNatural-language role; becomes the system prompt seed
toolsNames from the tool registry (see below)
memorynone (default) | buffer | vector
modelPer-agent model override; falls back to llm.model

graph

FieldNotes
entryStarting agent ID
edges[].fromSource agent ID
edges[].toTarget agent ID or END
edges[].conditionRouting signal (optional). Matches ROUTE: <signal> emitted by a router agent. The ROUTE: prefix is stripped automatically.

Graph validation (enforced at load time)

  • No duplicate agent IDs
  • entry must name a defined agent
  • All edge sources/targets must be defined agents or END
  • All agents must be reachable from entry (no orphans)
  • At least one path to END (the graph must be able to terminate)

Routing

Conditional control flow uses a lightweight signal convention:

Router agent output: "... ROUTE: needs_revision ..."
Matching edge: { from: critic, to: researcher, condition: needs_revision }

A router agent just emits a line starting with ROUTE: anywhere in its response. The runtime scans for it and dispatches to the matching edge. The ROUTE: prefix in a condition value is stripped automatically so both needs_revision and ROUTE: needs_revision work as condition strings.


Memory modes

ModeBehaviour
noneNo persistent memory; each agent sees the shared message history
bufferIn-state conversation buffer (full message list in graph state)
vectorHook in build_messages for local Chroma/LanceDB retrieval (wired but not yet fully implemented)

Tool registry

Tools are named capabilities that agents can call. Only registered tools can be referenced in a spec; unknown tools are flagged at the resolve_tools checkpoint.

Built-in tools

NameSignatureWhat it does
doc_loaderdoc_loader(path: str) → strReads and returns the contents of a local text/markdown file
calculatorcalculator(expression: str) → strEvaluates a safe arithmetic expression (AST-based; supports +, -, *, /, **, unary negation)

Adding a custom tool

# agentforge/tools/registry.pyfrom . importregistry@registry.registerdefmy_tool(arg: str) ->str:
"""Description shown to the model."""
...

Then reference it in the DSL: tools: [my_tool].


LLM provider configuration

OpenRouter (default)

OpenRouter gives access to hundreds of models through one API key.

# .env
OPENROUTER_API_KEY=sk-or-...

The default model is qwen/qwen3-coder:free (free tier, rate-limited). For reliable throughput drop :free and add credit at openrouter.ai:

llm:
provider: openroutermodel: qwen/qwen3-coder # paid — no upstream throttling

Free-tier 429s are handled automatically (up to 5 retries with the server-suggested Retry-After delay).

Ollama (local)

llm:
provider: ollamamodel: qwen2.5:14bbase_url: http://localhost:11434

Requires a local Ollama instance. Pass --model <name> on the CLI too if using generate.


What the compiler generates

compile produces a single self-contained Python file:

<name>_app.py
├── State (TypedDict) messages list + scratch dict + last_agent str
├── agent_<id>(state) → dict one function per agent (LLM call + tool loop)
├── route_<id>(state) → str one router per set of conditional edges
├── build_graph() → app wires StateGraph, adds SQLite checkpointer
└── run(prompt, thread_id) entry point; initialises state and invokes graph

Key properties:

  • No LLM during compilation → output is byte-identical for the same DSL
  • SQLite checkpointing is automatic; every run is resumable via thread_id
  • Tools are resolved at runtime from the local registry, not hardcoded

Validation and smoke tests

validate runs two layers of checks without calling any LLM:

Static checks (validator.py)

  • Schema integrity (duplicate IDs, orphan agents, missing END)
  • Conditional edge signals match router outputs
  • All referenced tools exist in the registry

Smoke tests (smoke.py)

  • Graph convergence (every path eventually reaches END)
  • Dead-router detection (router emits a signal that no edge handles)
  • Progress-discard warnings (cycles that could loop forever)

Project layout

agentforge/
cli.py entry point (compile / validate / generate)
dsl/
schema.py the DSL contract (Pydantic models)
loader.py YAML/JSON → validated SystemSpec
compiler/
langgraph_compiler.py deterministic DSL → LangGraph code
meta_agents/
pipeline.py 6-stage generation pipeline + human checkpoints
validator.py static checks
smoke.py convergence + dead-router detection
runtime/
support.py LLM client (_OpenRouterLLM), tool resolution, agent loop
tools/
registry.py built-in tools (doc_loader, calculator)
examples/
research_assistant.yaml
tests/
test_core.py deterministic-core tests (no LLM required)

Extending to CrewAI later

Add a crewai_compiler.py alongside the LangGraph one and switch on spec.runtime. The DSL, meta-agents, and validator stay unchanged — only the compile step branches.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages