A terminal coding agent powered by mellea. Supports any OpenAI-compatible API (OpenRouter, OpenAI, local LM Studio/Ollama) and on-device inference via LiteRT LM.
The screenshot above shows a typical session (OpenRouter provider, qwen/qwen3.6-flash). Asked to "Find information about IBM Bob Partner and compare this solution with the GitHub copilot", the agent autonomously chains tool calls — duckduckgo_search to find sources, then scrape_webpage to pull detailed content from official pages — narrating its reasoning between each step before compiling the final comparison. Each tool invocation is printed inline with its arguments, so you can follow exactly what the agent is doing.
This agent uses the mellea library as its core LLM orchestration framework:
- Session management:
mellea.start_session()creates chat sessions with configurable backends, system prompts, and model options - Tool integration: mellea's
ModelOption.TOOLSenables function calling with automatic tool registration and execution via the@tooldecorator - Requirements system: mellea's
Requirementclass provides validation hooks for safety checks (e.g., preventing writes to system directories) - Multi-backend support: mellea's backend abstraction handles OpenAI-compatible APIs; LiteRT uses its native
litert_lmAPI directly - MCP integration: mellea's
discover_mcp_tools()andhttp_connection()load tools from MCP servers at startup
The agent maintains two execution paths:
- API providers (local, openrouter, openai, anthropic): Uses mellea's
session.instruct()with tool calling - LiteRT provider: Uses
litert_lm.Enginedirectly with a custom tool handler, since mellea doesn't yet wrap LiteRT's tool format
Key mellea imports used:
mellea.start_session— creates configured chat sessionsmellea.backends.ModelOption— configures tools, temperature, max tokens, system promptmellea.backends.tool— decorator for registering tool functionsmellea.core.Requirement— validation for tool argumentsmellea.stdlib.tools.mcp— MCP server discovery and tool loadingmellea.stdlib.tools.local_code_interpreter— safe Python execution for thepython_exectool
- Python 3.13+
- uv package manager
git clone https://github.com/0ndrec/mellea-agent.git
cd mellea-agent
uv syncThe scrape_webpage tool drives a real Chromium browser via Patchright. Install the browser once:
uv run patchright install chromiumEverything else works without this step — the tool just returns an error message if Chromium is missing.
uv run python agent.pyThe prompt supports command history (arrow keys) and exits on Ctrl+C, Ctrl+D, or typing exit.
The agent keeps conversation history across turns (the last 10 exchanges are fed back as context), so follow-up requests like "now add tests for that" work as expected.
Single-shot mode (no interactive loop):
uv run python agent.py "refactor main.py to use dataclasses"Set the LLM_PROVIDER environment variable to switch providers. The default is local.
LLM_PROVIDER |
What it connects to |
|---|---|
local |
LM Studio / Ollama at http://127.0.0.1:1234/v1 |
openrouter |
openrouter.ai |
openai |
OpenAI API |
anthropic |
Anthropic models via OpenRouter |
litert |
Local .litertlm model file (offline, no API key) |
export LLM_PROVIDER=openrouter
export OPENROUTER_API_KEY=sk-or-...
uv run python agent.pyDefault model: qwen/qwen3.6-flash. Override:
export LLM_MODEL=deepseek/deepseek-r1export LLM_PROVIDER=openai
export OPENAI_API_KEY=sk-...
uv run python agent.pyStart your local server, then:
export LLM_PROVIDER=local
export LLM_MODEL=your-model-name
uv run python agent.pyThe default base URL is http://127.0.0.1:1234/v1. Override with LLM_BASE_URL if your server listens elsewhere.
export LLM_PROVIDER=anthropic
export OPENROUTER_API_KEY=sk-or-...
uv run python agent.pyDefault model: anthropic/claude-sonnet-4-6.
LiteRT runs models locally from a .litertlm file with no API key, no network, and no server. Models run on CPU, GPU (Vulkan/Metal), or NPU.
uv sync --extra litertModels are distributed as .litertlm files. Download one using the huggingface_hub library:
uv add huggingface_hub # one-timefrom huggingface_hub import hf_hub_download
# ~2.8 GB — Qwen3 4B INT4, good general-purpose coding model
path = hf_hub_download(
repo_id="DuoNeural/Qwen3-4B-LiteRT",
filename="model.litertlm",
)
print(path) # prints the local cache pathRun this once; hf_hub_download caches the file and returns the local path on subsequent calls.
Recommended models (all INT4 quantized):
| Model | Repo | Size | Notes |
|---|---|---|---|
| Qwen3 4B | DuoNeural/Qwen3-4B-LiteRT |
~2.8 GB | Good coding, fast on CPU |
| DeepSeek-R1 7B | litert-community/DeepSeek-R1-Distill-Qwen-7B |
~4.2 GB | Reasoning chains, needs GPU for speed |
| Granite 4.1 3B | DuoNeural/Granite-4.1-3B-LiteRT |
~2 GB | IBM code model, small footprint |
| Llama 3.2 3B | mlboydaisuke/Llama-3.2-3B-Instruct-LiteRT |
~2 GB | Versatile instruction model |
| DeepSeek-R1 1.5B | mlboydaisuke/DeepSeek-R1-Distill-Qwen-1.5B-LiteRT |
~1 GB | Minimal footprint |
Browse all 280+ models at huggingface.co/models?library=litert.
export LLM_PROVIDER=litert
export LITERT_MODEL_PATH=/path/to/model.litertlm # path printed by hf_hub_download
uv run python agent.pyOr inline:
LLM_PROVIDER=litert LITERT_MODEL_PATH=$(python -c "
from huggingface_hub import hf_hub_download
print(hf_hub_download('DuoNeural/Qwen3-4B-LiteRT', 'model.litertlm'))
") uv run python agent.pyexport LITERT_BACKEND=cpu # default — works everywhere
export LITERT_BACKEND=gpu # Vulkan (Linux/Android) or Metal (macOS)
export LITERT_BACKEND=npu # Qualcomm Hexagon or similarGPU is recommended for models ≥3 B parameters. On a Mac M-series, GPU gives ~60–70 tokens/second for a 7B model.
The agent has access to these built-in tools:
| Tool | Description |
|---|---|
read_file(path) |
Read a file with line numbers |
write_file(path, content) |
Write or overwrite a file |
list_dir(path) |
List directory contents |
run_command(command, cwd, timeout) |
Execute a shell command |
search_text(pattern, path, file_glob) |
Regex search across files |
python_exec(code) |
Run Python in the current directory |
duckduckgo_search(query, max_results) |
Web search via DuckDuckGo |
scrape_webpage(url, selector, wait_for, timeout, headless) |
Extract text from a web page with a stealth Chromium browser (Patchright) — handles JavaScript-rendered pages and basic bot detection. Optional CSS selector targets specific elements; wait_for waits for a selector before extracting |
ask_user(question, options) |
Pause and ask the user a question |
change_provider(provider, model) |
Switch the active LLM provider at runtime |
The agent calls ask_user before making ambiguous decisions, and change_provider only when you explicitly request a different provider or model — for example: "switch to OpenAI" or "use deepseek/deepseek-r1".
Additional tools are loaded from MCP servers configured in config.py. The default config connects to the MDN documentation server. To add more servers, edit the MCP_SERVERS list.
| Variable | Default | Description |
|---|---|---|
LLM_PROVIDER |
local |
Active provider (local, openrouter, openai, anthropic, litert) |
LLM_MODEL |
provider default | Override the model ID or path |
LLM_BASE_URL |
provider default | Override the API base URL |
LLM_API_KEY |
provider default | Override the API key |
OPENROUTER_API_KEY |
— | API key for OpenRouter and Anthropic providers |
OPENAI_API_KEY |
— | API key for OpenAI provider |
LITERT_MODEL_PATH |
model.litertlm |
Path to the .litertlm model file |
LITERT_BACKEND |
cpu |
LiteRT compute backend (cpu, gpu, npu) |
