English | δΈζ
Agentflow is a distributed, event-driven Agent orchestration framework which is dedicated to make agent system creating and editing as efficient as docx editing in office.
Every builder who is interested in of event driven agent workflow is warmly welcomed, please directly message me at github or email wjluo57@gmail.com
π Full documentation: https://nft-maker-one.github.io/agentflow/ β guides, SDK reference, deployment, and CLI (δΈζ / English).
Most agent frameworks orchestrate agents as a graph you invoke: nodes and edges over a shared state object, traversed once per request. That's a great fit for a structured, one-shot request β response.
Agentflow has a different center of gravity: agents on an event bus. Each agent simply subscribes to topics and publishes results β fully decoupled. External events (a Telegram message, an email, a webhook) are injected onto the bus as first-class sources, and an event-driven mode keeps the workflow continuously listening.
In one line: graph frameworks invoke a graph; Agentflow lets events flow on a bus.
| Graph-based (e.g. LangGraph) | Agentflow | |
|---|---|---|
| Orchestration model | Graph traversal over shared state | Topic pub/sub on an event bus |
| Agent β agent | State passed along edges | Decoupled envelopes on the bus (fan-in / fan-out) |
| Add an agent | Rewire the graph / edit edges | Subscribe to a topic β nothing else changes |
| Inbound trigger | You call the API to start a run (+ cron) | External sources inject events onto the bus (hot-pluggable) |
| Webhooks | Outbound β notify after a run completes | Inbound events drive agents directly |
| Running shape | One run per invocation | Single run or always-on event-driven mode |
| Transport | In-process (+ hosted platform) | Pluggable broker: Redis Streams (default) / Kafka / in-process β one env var, auto-degrades if offline |
| Editing | Code-first | Live in-browser topology + prompt editing, hot redeploy (zero downtime) |
Graph frameworks are excellent β this is a difference in design center, not a "more features" claim. Persistence, durable execution, and visualization exist on both sides.
- π Decoupled by design β add or replace an agent = one subscription; the rest of the workflow is untouched.
- π¨ External events are first-class β Telegram / email / webhook sources inject onto the bus without editing the workflow.
- π±οΈ Edit it like a document β drag the topology, edit prompts, hot-redeploy live in the browser.
- β‘ Millisecond deploys β Redis Streams consumer groups are
O(1)(no rebalance); creating / redeploying a workflow is milliseconds, not seconds. - π§± Pluggable backends + graceful degrade β Redis Streams / Kafka / in-process bus, Postgres / in-memory store, Redis / in-memory guardrail; selected by one env var, auto-degrade when the middleware is offline.
- π§Ύ Every run is replayable β a per-run topology snapshot + full event timeline is persisted; an archived run renders exactly as it ran.
- π Operable out of the box β per-run / per-agent token & cycle guardrails, OpenTelemetry traces, Prometheus + Grafana.
Real agent systems aren't one-shot Q&A β they are always-on and reactive, responding to streams of events: messages, emails, webhooks, schedules, and each other's outputs. Microservices made exactly this move β from RPC spaghetti to event streaming β for the same reasons: loose coupling, fan-in / fan-out, backpressure, durability, replay. Agents are the next microservices, and they need an event backbone β not a bigger graph.
# 1) Install (Python 3.11+, uv: https://docs.astral.sh/uv/)
uv sync --all-extras
# 2) Run the in-process demo (no docker needed)
.venv/bin/python -m agentkit.cli.main version
.venv/bin/python -m agentkit.cli.main init /tmp/my-bot
cd /tmp/my-bot
agentkit run workflows/wf_hello.yaml --input '{"q":"hi"}' --handlers handlersOutput:
β run.Succeeded run_id=run_01KST... (2 branch event(s))
last event on agent.echo.out.reply:
{ "text": "hi" }
from agentkit import Event, agent, workflow
from agentkit.testing import LocalRuntime, MockLLMGateway
@agent(role="thinking", subscribe=["q"], publish=["reply"])
async def echo(ctx, event):
text = await ctx.llm.chat(f"Echo: {event.payload['q']}")
return [Event(topic="reply", payload={"text": text})]
wf = workflow("wf_demo")
wf.add(echo)
wf.connect("__start__", "echo", via="q")
wf.connect("echo", "__end__", via="reply")
async with LocalRuntime(wf, llm=MockLLMGateway(reply="hi from mock")) as rt:
run = await rt.run(input={"q": "hello"})
assert run.status.value == "Succeeded"id: wf_demo
agents:
echo:
role: thinking
subscribe: [{ topic: q }]
publish: [{ topic: reply }]
edges:
e_in: { from: __start__, to: echo, via: q }
e_out: { from: echo, to: __end__, via: reply }agentkit run workflows/wf_demo.yaml --input '{"q":"hi"}' --handlers handlersBoth compile to the same WorkflowIR through the same 6-step Compiler.
make up # Redpanda + Redis + PG + Prometheus + Grafana + OTel
make ps # check service status
make down # tear down| Service | URL | Notes |
|---|---|---|
| Redpanda (Kafka) | localhost:9092 |
EventBus broker |
| Redis | localhost:6379 |
Guardrail quotas, dedup |
| Postgres | localhost:5432 |
agentkit/agentkit |
| Prometheus | http://localhost:9090 | Scrapes AgentKit /metrics |
| Grafana | http://localhost:3000 | admin/admin, AgentKit Overview dashboard |
| OTel Collector | grpc://localhost:4317 |
Receives OTLP traces |
| AgentKit probe | http://localhost:9100/metrics | Started by your agentkit process |
make test-unit # 475 fast tests, no docker (~7s)
make test-integration # real Kafka + Redis (requires `make up-core`)
make test-e2e # full stack: Kafka + Prometheus query (requires `make up`)
make test-perf # perf benchmarksTest layout:
| Directory | Marker | What it tests |
|---|---|---|
tests/unit/ |
(none) | All logic with InProcessEventBus + mocks |
tests/integration/ |
integration |
Real Kafka / Redis / OpenAI compat endpoint |
tests/e2e/ |
e2e |
Real Kafka + Prometheus scrape verification |
tests/perf/ |
perf |
Throughput / latency benchmarks |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β cli agentkit init / run / validate / compile / schema β L6
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β sdk + testing @agent / @judge / IRBuilder / LocalRuntime β L5
β orchestrator Run + Switch + Terminal + Branch β L5
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β runtime FSM + 4-Gate + Worker + AgentInstance β L4
β notifier Rule DSL + Channel + Template (Jinja2) β L4
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β workflow IR + 6-step Compiler β L3
β llm 9-step Gateway + Provider + Tokenizer β L3
β guardrail Lua atomic precheck/consume/release on Redis β L3
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β bus EventBus Protocol + Kafka + InProcess adapters β L2
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β models Envelope + enums (Role / AgentState / RunStatus) β L1
β observability Metrics + Tracing + Audit + ProbeServer β L1
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β common config / ids (ULID) / time / logging (structlog) β L0
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Strictly layered: lower layers MUST NOT import upper layers. Verified by an AST-based make check in CI.
agentkit version
agentkit init <project> # scaffold a project (handlers.py + workflows/wf_hello.yaml)
agentkit validate <yaml> # static IR validation
agentkit compile <yaml> # produce canonical IR JSON
agentkit schema export # dump the WorkflowIR JSON Schema
agentkit run <yaml> --input <json> --handlers <module>make lint # ruff check
make format # ruff format + auto-fix
make typecheck # mypy strictfrom agentkit.llm.provider import LLMProvider
class MyProvider: # satisfy the Protocol structurally
name = "myco"; capabilities = ...
async def complete(self, req): ...
async def stream(self, req): ...
def count_tokens(self, content, model): ...Plug it into the Gateway via LLMGatewayClient(providers={"myco": MyProvider()}).
src/agentkit/
common/ # L0 β config, ids, time, logging, errors
models/ # L1 β Pydantic data models
observability/ # L1 β metrics, tracing, audit, probe server
bus/ # L2 β EventBus Protocol + Kafka + InProcess adapters
llm/ # L3 β Gateway pipeline + tokenizer + ratelimit
workflow/ # L3 β IR + Compiler (parse/expand/resolve/inject/validate/lower/plan)
guardrail/ # L3 β Resolver + Redis Lua backend
runtime/ # L4 β FSM + 4-Gate + AgentInstance + Worker
notifier/ # L4 β Rule DSL + matcher + channels + templates
orchestrator/ # L5 β Run + Switch + Terminal routing
sdk/ # L5 β @agent / @judge / IRBuilder / WorkflowDef
testing/ # L5 β LocalRuntime + MockLLMGateway + run_agent_locally
cli/ # L6 β Typer app
MIT