Update docs: fast tools, routecheck service, commute tool

- Request flow: add fast_tool_runner.run_matching() to pre-flight gather
- New Fast Tools section: WeatherTool + CommuteTool table, extension guide
- New routecheck section: captcha UI, internal API, proxy requirements
- Services table: add routecheck:8090
- Files tree: add fast_tools.py, routecheck/, updated .env note

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alvis
2026-03-13 07:10:30 +00:00
parent 32089ed596
commit eba805f787
2 changed files with 67 additions and 10 deletions

View File

@@ -54,9 +54,11 @@ Autonomous personal assistant with a multi-channel gateway. Three-tier model rou
3. 202 Accepted immediately
4. Background: run_agent_task(message, session_id, channel)
5. Parallel IO (asyncio.gather):
a. _fetch_urls_from_message() — Crawl4AI fetches any URLs in message
b. _retrieve_memories() — openmemory semantic search for context
6. router.route() with enriched history (url_context + memories as system msgs)
a. _fetch_urls_from_message() — Crawl4AI fetches any URLs in message
b. _retrieve_memories() — openmemory semantic search for context
c. _fast_tool_runner.run_matching() — FastTools (weather, commute) if pattern matches
6. router.route() with enriched history (url_context + fast_context + memories)
- fast tool match → force medium (real-time data, no point routing to light)
- if URL content fetched and tier=light → upgrade to medium
7. Invoke agent for tier with url_context + memories in system prompt
8. Token streaming:
@@ -90,6 +92,33 @@ Adolf uses LangChain's tool interface but only the complex agent actually invoke
Complex tier is locked out unless the message starts with `/think` — any LLM classification of "complex" is downgraded to medium.
## Fast Tools (`fast_tools.py`)
Pre-flight tools that run concurrently with URL fetch and memory retrieval before any LLM call. Each tool has two methods:
- `matches(message) → bool` — regex classifier; also used by `Router` to force medium tier
- `run(message) → str` — async fetch returning a context block injected into system prompt
`FastToolRunner` holds all tools. `any_matches()` is called by the Router at step 0a; `run_matching()` is called in the pre-flight `asyncio.gather` in `run_agent_task()`.
| Tool | Pattern | Source | Context returned |
|------|---------|--------|-----------------|
| `WeatherTool` | weather/forecast/temperature/snow/rain | SearXNG `"погода Балашиха сейчас"` | Current conditions in °C from Russian weather sites |
| `CommuteTool` | commute/traffic/arrival/пробки | `routecheck:8090/api/route` (Yandex Routing API) | Drive time with/without traffic, Balashikha→Moscow |
**To add a new fast tool:** subclass `FastTool` in `fast_tools.py`, implement `name`/`matches`/`run`, add an instance to `_fast_tool_runner` in `agent.py`.
## routecheck Service (`routecheck/`)
Local web service on port 8090. Exists because Yandex Routing API free tier requires a web UI that uses the API.
**Web UI** (`http://localhost:8090`): PIL-generated arithmetic captcha → lat/lon form → travel time result.
**Internal API**: `GET /api/route?from=lat,lon&to=lat,lon&token=ROUTECHECK_TOKEN` — bypasses captcha, used by `CommuteTool`. The `ROUTECHECK_TOKEN` shared secret is set in `.env` and passed to both `routecheck` and `deepagents` containers.
Yandex API calls are routed through the host HTTPS proxy (`host.docker.internal:56928`) since the container has no direct external internet access.
**Requires** `.env`: `YANDEX_ROUTING_KEY` (free from `developer.tech.yandex.ru`) + `ROUTECHECK_TOKEN`.
## Crawl4AI Integration
Crawl4AI runs as a Docker service (`crawl4ai:11235`) providing JS-rendered, bot-bypass page fetching.
@@ -135,20 +164,24 @@ Conversation history is keyed by session_id (5-turn buffer).
```
adolf/
├── docker-compose.yml Services: bifrost, deepagents, openmemory, grammy, crawl4ai, cli (profile:tools)
├── docker-compose.yml Services: bifrost, deepagents, openmemory, grammy, crawl4ai, routecheck, cli
├── Dockerfile deepagents container (Python 3.12)
├── Dockerfile.cli CLI container (python:3.12-slim + rich)
├── agent.py FastAPI gateway, run_agent_task, Crawl4AI pre-fetch, memory pipeline, /stream/ SSE
├── agent.py FastAPI gateway, run_agent_task, Crawl4AI pre-fetch, fast tools, memory pipeline
├── fast_tools.py FastTool base, FastToolRunner, WeatherTool, CommuteTool
├── channels.py Channel registry + deliver() + pending_replies
├── router.py Router class — regex + LLM tier classification
├── router.py Router class — regex + LLM tier classification, FastToolRunner integration
├── vram_manager.py VRAMManager — flush/prewarm/poll Ollama VRAM
├── agent_factory.py _DirectModel (medium) / create_deep_agent (complex)
├── cli.py Interactive CLI REPL — Rich Live streaming + Markdown render
├── wiki_research.py Batch wiki research pipeline (uses /message + SSE)
├── .env TELEGRAM_BOT_TOKEN, ROUTECHECK_TOKEN, YANDEX_ROUTING_KEY (not committed)
├── routecheck/
│ ├── app.py FastAPI: image captcha + /api/route Yandex proxy
│ └── Dockerfile
├── tests/
│ ├── integration/ Standalone integration test scripts (common.py + test_*.py)
│ └── use_cases/ Claude Code skill markdown files — Claude acts as user + evaluator
├── .env TELEGRAM_BOT_TOKEN (not committed)
├── openmemory/
│ ├── server.py FastMCP + mem0: add_memory, search_memory, get_all_memories
│ └── Dockerfile

View File

@@ -46,10 +46,12 @@ Channel adapter → POST /message {text, session_id, channel, user_id}
→ 202 Accepted (immediate)
→ background: run_agent_task()
→ asyncio.gather(
_fetch_urls_from_message() ← Crawl4AI, concurrent
_retrieve_memories() ← openmemory search, concurrent
_fetch_urls_from_message() ← Crawl4AI, concurrent
_retrieve_memories() ← openmemory search, concurrent
_fast_tool_runner.run_matching() ← FastTools (weather, commute), concurrent
)
→ router.route() → tier decision (light/medium/complex)
fast tool match → force medium
if URL content fetched → upgrade light→medium
→ invoke agent for tier via Bifrost (url_context + memories in system prompt)
deepagents:8000 → bifrost:8080/v1 → ollama:11436
@@ -112,6 +114,7 @@ Session IDs: `tg-<chat_id>` for Telegram, `cli-<username>` for CLI. Conversation
| `openmemory` | 8765 | FastMCP server + mem0 memory tools (Qdrant-backed) |
| `grammy` | 3001 | grammY Telegram bot + `/send` HTTP endpoint |
| `crawl4ai` | 11235 | JS-rendered page fetching |
| `routecheck` | 8090 | Local routing web service — image captcha UI + Yandex Routing API backend |
| `cli` | — | Interactive CLI container (`profiles: [tools]`), Rich streaming display |
External (from `openai/` stack, host ports):
@@ -134,6 +137,25 @@ Crawl4AI is embedded at all levels of the pipeline:
MCP tools from openmemory (`add_memory`, `search_memory`, `get_all_memories`) are **excluded** from agent tools — memory management is handled outside the agent loop.
### Fast Tools (`fast_tools.py`)
Pre-flight tools that run before the LLM in the `asyncio.gather` alongside URL fetch and memory retrieval. Each tool has a regex `matches()` classifier and an async `run()` that returns a context string injected into the system prompt. The router uses `FastToolRunner.any_matches()` to force medium tier when a tool matches.
| Tool | Trigger | Data source |
|------|---------|-------------|
| `WeatherTool` | weather/forecast/temperature keywords | SearXNG query `"погода Балашиха сейчас"` — Russian sources return °C |
| `CommuteTool` | commute/traffic/arrival time keywords | `routecheck:8090/api/route` — Yandex Routing API, Balashikha→Moscow center |
To add a new fast tool: subclass `FastTool` in `fast_tools.py`, add an instance to `_fast_tool_runner` in `agent.py`.
### `routecheck` service (`routecheck/app.py`)
Local web service that exposes Yandex Routing API behind an image captcha. Two access paths:
- **Web UI** (`localhost:8090`): solve PIL-generated arithmetic captcha → query any two lat/lon points
- **Internal API**: `GET /api/route?from=lat,lon&to=lat,lon&token=ROUTECHECK_TOKEN` — bypasses captcha, used by `CommuteTool`
Requires `.env`: `YANDEX_ROUTING_KEY` (free tier from `developer.tech.yandex.ru`) and `ROUTECHECK_TOKEN`. The container routes Yandex API calls through the host HTTPS proxy (`host.docker.internal:56928`).
### Medium vs Complex agent
| Agent | Builder | Speed | Use case |
@@ -143,7 +165,9 @@ MCP tools from openmemory (`add_memory`, `search_memory`, `get_all_memories`) ar
### Key files
- `agent.py` — FastAPI app, lifespan wiring, `run_agent_task()`, Crawl4AI pre-fetch, memory pipeline, all endpoints
- `agent.py` — FastAPI app, lifespan wiring, `run_agent_task()`, Crawl4AI pre-fetch, fast tools, memory pipeline, all endpoints
- `fast_tools.py``FastTool` base class, `FastToolRunner`, `WeatherTool`, `CommuteTool`
- `routecheck/app.py` — captcha UI + `/api/route` Yandex proxy
- `bifrost-config.json` — Bifrost provider config (Ollama GPU, retries, timeouts)
- `channels.py` — channel registry and `deliver()` dispatcher
- `router.py``Router` class: regex + LLM classification, light-tier reply generation