One choke point in the sanitized client: the flavor is probed once
(the boilerroom wrapper names itself on /health, a bare llama-server
serves /props, Ollama answers neither) and every completion adapts.
The agents' tool_choice "required" survives only on Ollama — advisory
there, enforced by llama-server, an unbreakable tool loop through the
wrapper. Through the wrapper every completion carries webber's session
identity: session webber, eviction_order 20 in the decided ranking,
configurable via settings. The wrapper's balancing and compaction
signals are read from the response body's extra fields — an httpx
event-hook variant was tried and never fires under the openai SDK.
The enabling fix: the sanitized client was never in the request path.
The provider assigned self._openai_client, an attribute nobody reads —
OllamaProvider.client serves self._client — so every completion has
bypassed the null-content sanitizer since the class was introduced.
Exposed when the wrapper 503'd a session-less request the choke point
should have named; the client now goes through the constructor's
official openai_client parameter, and a wiring test pins
provider.client to the sanitized type. The same bug exists in tatlock
(its T-6, filed).
Verified against the live wrapper from the dev server: flavor
boilerroom detected, a tool-using explore run answered in 4.8 s with
no tool loop, webber resident at rank 20, and the wrapper parked
librarian and tatlock-experts to seat it — the ranking doing exactly
its job. Six new tests (227 green), five mutation-checked: the rank
default, the strip condition, the session-add condition, the
no-cache-on-failure rule, and the client wiring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mistral-nemo-large holds ~9.2 GB of the 11 GB card it shares with Speaches,
which starves Whisper and breaks voice transcription. gemma4:e2b holds
1.9 GB and is faster. The deployed stack already overrides this via
OLLAMA_AGENT_MODEL; this aligns the default so a deployment without that
override does not reintroduce the contention.
Co-Authored-By: Claude <noreply@anthropic.com>
The homelab is retiring *.schweitz.internal and will rebind host ports
to 127.0.0.1, so container-to-container traffic must use container
names on the docker-dataplane network. Switch defaults from host
IP:port to http://tatlock:8000 and http://searxng:8080 (SearXNG's
internal port is 8080; 8087 is only the host-published port).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- @with_retry decorator and retry_async() function
- Exponential backoff with jitter
- Retries on: timeout, connection errors, HTTP 429/5xx
- Web search tool now retries on network failures
- Configurable via RETRY_MAX_ATTEMPTS, RETRY_BASE_DELAY, RETRY_MAX_DELAY
- 29 new tests (205 total passing)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add WebSearchTool that queries the self-hosted SearXNG metasearch engine
for current information, documentation, and facts beyond training data.
- Add SEARXNG_URL and SEARXNG_TIMEOUT config settings
- Create WebSearchTool with query, num_results, categories params
- Register web_search tool with explore agent
- Add 10 tests for search functionality
Usage: Agents can now use web_search(query="...") to find current info.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Structure webber into three independent subprojects:
- webber-api/: FastAPI backend server with all agent code
- webber-cli/: Standalone CLI client (renamed from cli/ to webber_cli/)
- webber-sandbox/: Test project for functional testing
Key changes:
- Each subproject has its own .venv (Python 3.12+)
- Added sandbox.sh for managing test project templates
- Created sandbox-templates/ with calculator-cli and empty starter
- Updated CI/CD for prefixed tags (api/v*, cli/v*)
- Added comprehensive AGENTS.md with operational instructions
- Added gitignore filtering to glob and grep tools
- Created pyproject.toml for each subproject
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>