3.7 KiB
focus
An LLM agent framework in Rust, structured as a Cargo workspace. Built to learn the architecture of pi by reimplementing its core layers with a minimal dependency surface (tokio + rustls only).
This milestone focuses on calling Z.ai / 智谱 GLM coding models
(glm-5.2, domestic endpoint) end-to-end.
Quick start
1. Create a config file
Copy the example (it lists providers but no API keys — those go in
auth.json via /login):
mkdir -p ~/.focus
cp examples/config.example.json ~/.focus/config.json
The config (~/.focus/config.json) selects a default provider and lists
available ones (host, model). Override the config dir with FOCUS_CONFIG_DIR.
2. Log in (save your API key)
Run focus with no arguments to enter the interactive REPL, then use the
/login slash command:
./target/debug/focus
> /login zai-coding-cn
Enter API key for zai-coding-cn: <paste your 智谱 API key>
Credentials saved to ~/.focus/auth.json
> /quit
Your key is stored in ~/.focus/auth.json (mode 0600). Log out with
/logout [provider].
3. Run
cargo build --workspace
# Interactive REPL (multi-turn conversation):
./target/debug/focus
> 你好
你好!有什么可以帮你的?
> /quit
# Single prompt (one-shot):
./target/debug/focus "用一句话解释什么是 Rust"
# Or pipe via stdin:
echo "写一个快排" | ./target/debug/focus
# Override the model:
./target/debug/focus --model glm-5.2 "hello"
# One-off API key (in-memory only, not saved):
./target/debug/focus --api-key YOUR_KEY "hello"
# Print the resolved config:
./target/debug/focus --config
focus --help shows all options.
REPL slash commands
Inside the REPL (focus with no prompt, on a TTY):
| Command | Action |
|---|---|
/login [provider] |
store an API key in ~/.focus/auth.json |
/logout [provider] |
remove a stored credential |
/provider [name] |
show or switch the active provider |
/model [name] |
show or switch the active model |
/system [text] |
show or set the system prompt |
/clear / /new |
clear the conversation transcript |
/config |
print the resolved provider config |
/help |
list commands |
/quit |
exit focus |
Plain text is sent to the model as a prompt; the conversation is multi-turn (the transcript persists across prompts).
Credential resolution order
When running a prompt, the API key is resolved in this order (highest first):
--api-keyCLI flag (in-memory only, never persisted)~/.focus/auth.jsonentry (written byfocus login)config.jsonproviderapiKeyfield (if present)
3. Run the real-call smoke test (optional)
ZAI_API_KEY=<key> cargo test -p focus-providers --test zai_smoke -- --ignored --nocapture
Architecture
See docs/architecture/ for the pi reference analysis.
The workspace mirrors pi's layering:
focus-json minimal JSON parser/serializer (zero deps)
focus-core domain types, agent loop, Tool/StreamProvider traits
focus-transport HTTP/1.1, TLS (rustls), SSE parser
focus-providers Z.ai / OpenAI-compat + Anthropic providers
focus-cli config loading + single-prompt runner
focus-tools (placeholder) file/shell tools
focus-harness (placeholder) session persistence + compaction
Dependency flow is strictly one-way: core never depends on transport,
providers, or tools. All I/O crosses trait boundaries.
Verification
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
All 95 unit/integration tests pass with zero clippy warnings. See
AGENTS.md for the full engineering spec.