Minimal agent runtime built with DSPy modules and a thin Python loop.
- Plan/Act/Finalize expressed as DSPy Signatures, with OpenAI-native tool-calling when available.
- Thin runtime (agent.py) handles looping, tool routing, and trace persistence.
- CLI and FastAPI server, plus a tiny eval harness.
uv, or see pip alternative below):uv venv && source .venv/bin/activate
uv pip install -e .
cp .env.example .env # set OPENAI_API_KEY or configure Ollama
# Ask a question (append --utc to nudge UTC use when time is relevant)
micro-agent ask --question "What's 2*(3+5)?" --utc
# Run the API server
uvicorn micro_agent.server:app --reload --port 8000
# Run quick evals (repeat small dataset)
python evals/run_evals.py --n 50
Pip alternative:
python -m venv .venv && source .venv/bin/activate
pip install -e .
.env is loaded automatically (via python-dotenv).OPENAI_API_KEY, OPENAI_MODEL (default gpt-4o-mini)LLM_PROVIDER=ollama, OLLAMA_MODEL (e.g. llama3.2:1b), OLLAMA_HOST (default http://localhost:11434)TEMPERATURE (default 0.2), MAX_TOKENS (default 1024)TOOLS_MODULES="your_pkg.tools,other_pkg.tools" to load extra tools (see Tools below)TRACES_DIR (default traces/)USE_TOOL_CALLS=1|0 to force-enable/disable OpenAI function-calls modeExamples:
# OpenAI
export OPENAI_API_KEY=...
export OPENAI_MODEL=gpt-4o-mini
# Ollama
export LLM_PROVIDER=ollama
export OLLAMA_MODEL=llama3.2:1b
export OLLAMA_HOST=http://localhost:11434
micro-agent ask --question <text> [--utc] [--max-steps N]--utc appends a hint to prefer UTC when time is used.traces/<id>.jsonl and prints the path.--func-calls forces OpenAI-native function-calls when available.--no-func-calls disables function-calls and uses robust JSON planning.micro-agent replay --path traces/<id>.jsonl [--index -1]Examples:
micro-agent ask --question "Add 12345 and 67890, then show the current date (UTC)." --utc
micro-agent ask --question "Compute (7**2 + 14)/5 and explain briefly." --max-steps 4
micro-agent replay --path traces/<id>.jsonl --index -1
uvicorn micro_agent.server:app --reload --port 8000POST /ask{ "question": "...", "max_steps": 6 }{ "answer": str, "trace_id": str, "trace_path": str, "steps": [...] }use_tool_calls: true|false to force function-calls behavior.Example:
curl -s http://localhost:8000/ask \
-H 'content-type: application/json' \
-d '{"question":"What\'s 2*(3+5)?","max_steps":6}' | jq .
OpenAPI:
- FastAPI publishes /openapi.json and interactive docs at /docs.
- Schemas reflect AskRequest and AskResponse models in micro_agent/server.py.
- Health: GET /health returns {status, provider, model, max_steps}.
- Minimal health: GET /healthz returns {status: "ok"}.
- Version: GET /version returns {name, version}.
micro_agent/tools.py:calculator: safe expression evaluator. Supports + - * / ** % // ( ) and ! via rewrite to fact(n).now: current timestamp; {timezone: "utc"|"local"} (default local).Tool(
"name",
"description",
{"type":"object","properties":{...},"required":[...]},
handler_function,
)
TOOLS_MODULES to a comma-separated list of importable modules. Each module should expose either a TOOLS: dict[str, Tool] or a get_tools() -> dict[str, Tool].Runtime validation
- Tool args are validated against the JSON Schema before execution; invalid args add a ⛔️validation_error step and the agent requests a correction in the next loop. See micro_agent/tools.py (run_tool) and micro_agent/agent.py (validation error handling).
PlanWithTools with JSONAdapter to enable native function-calls. The model may return tool_calls or a final answer; tool calls are executed via our registry.json_repair (if installed) and Python-literal parsing.calculator step before finalizing; likewise for time/date with the now tool. Violations are recorded in the trace as ⛔️policy_violation steps and planning continues.Code references (discoverability)
- Replay subcommand: micro_agent/cli.py (subparser replay, printing JSONL)
- Policy enforcement markers: micro_agent/agent.py (look for ⛔️policy_violation and ⛔️validation_error)
- Provider fallback and configuration: micro_agent/config.py (configure_lm tries Ollama → OpenAI → registry fallbacks)
- JSON repair in decision parsing: micro_agent/runtime.py (parse_decision_text uses json_repair if available)
traces/<id>.jsonl with fields: id, ts, question, steps, answer.{tool, args, observation} in order of execution.micro-agent replay --path traces/<id>.jsonl --index -1.GET /trace/{id} (CORS enabled).evals/tasks.yaml (small, mixed math/time tasks). Rubric: evals/rubrics.yaml.python evals/run_evals.py --n 50.success_rate, avg_latency_sec, avg_lm_calls, avg_tool_calls, avg_steps, avg_cost_usd, n.expect_contains (answer substring) and expect_key (key present in any tool observation). Weights come from rubrics.yaml (contains_weight, key_weight).gpt-4o-mini, N=30PlanWithTools planner and save to JSON:micro-agent optimize --n 12 --tasks evals/tasks.yaml --save opt/plan_demos.json
export COMPILED_DEMOS_PATH=opt/plan_demos.json
micro-agent optimize --n 12 --template
The agent loads these demos on OpenAI providers and attaches them to the PlanWithTools predictor to improve tool selection and output consistency.
micro_agent/config.py: configures DSPy LM. Tries Ollama first if requested, else OpenAI; supports dspy.Ollama, dspy.OpenAI, and registry fallbacks like dspy.LM("openai/<model>").micro_agent/signatures.py: DSPy Signatures for plan/act/finalize and OpenAI tool-calls.micro_agent/agent.py: the runtime loop (~100+ LOC). Builds a JSON decision prompt, executes tools, enforces policy, and finalizes.micro_agent/runtime.py: trace format, persistence, and robust JSON decision parsing utilities.micro_agent/cli.py: CLI entry (micro-agent).micro_agent/server.py: FastAPI app exposing POST /ask.evals/: tiny harness to sample tasks, capture metrics, and save traces.make init, make run, make serve, make evals, make test.pytest -q (note: tests are minimal and do not cover all paths).make docker-buildOPENAI_API_KEY=... make docker-run (maps :8000)make docker-run-ollama (uses host.docker.internal:11434)OPENAI_API_KEY, OPENAI_MODEL=gpt-4o-miniLLM_PROVIDER=ollama, OLLAMA_HOST=http://host.docker.internal:11434, OLLAMA_MODEL=llama3.1:8bPOST http://localhost:8000/ask and GET /trace/{id}dspy-ai>=2.5.0. Some adapters (e.g., JSONAdapter, dspy.Ollama) may vary across versions; the code tries multiple backends and falls back to generic registry forms when needed.json_repair is installed, it is used opportunistically to salvage slightly malformed JSON decisions.pip install -e .[repair]Finalize predictor if preferred.dump_trace.Prove: an “agent” can be expressed as DSPy modules plus a thin runtime loop.
$ claude mcp add dspy-micro-agent \
-- python -m otcore.mcp_server <graph>