53 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Removed
- Dead delegation stack - deleted the duplicate, never-wired coordination layer so exactly ONE delegation implementation remains (
src/agents/delegation.py):src/agents/coordination.py(CoordinationEngine, its owndelegate_to_librarian,AGENT_EXECUTORS/AGENT_STREAM_EXECUTORS), the broken-by-designrun_librarian_streampath it used (Ollama streaming + tool call bug), thestream_delegate_to_*wrappers with their never-parsed__DELEGATION_RESULT__marker, andHouseholdRegistry.get_streaming_delegation_tools()(no callers) - Orphaned agent protocol models -
src/agents/protocol.pynow contains only the liveAgentError; the coordination wire protocol it carried (AgentRequest,AgentResponse,DelegationIntent,CoordinationResult,DelegationReason,TaskComplexity,ToolCallRecord,AgentTimeoutError,AgentUnavailableError,DelegationError) had no importer left outside its own tests after the coordination stack removal
Added
-
Test-suite tenant guard -
tests/conftest.pyhard-fails the whole pytest session (exit code 1, zero tests run) if the effective tenant resolves to the production tenantjpmschweitzer, mirroring the guard library-desk applies on its side. Suite-level assertions pin that the session runs underllm_testernamespaces (Qdrantmemories_llm_tester, Redissession:llm_tester:*), and the e2e isolation constants now derive from the sharedTEST_TENANT/PRODUCTION_TENANTconfig constants instead of string literals -
Explicit tenant on every library-desk request - the librarian client now resolves and sends the
userparameter explicitly on every request (library-desk is removing its server-side default; a missing user would 422). The content extraction endpoints now carry the tenant too,search_webno longer falls back to a phantomtatlock-librarianuser, and a client-level assertion rejects an empty/whitespace tenant before any bytes hit the wire. A parametrized sweep pins the wire contract for all 15 tenant-scoped client methods -
Tenant isolation guard - non-production environments (development/testing) now FORCE the effective tenant to the reserved test tenant
llm_tester(onlyllm_testeritself or atest_-prefixed override is accepted), regardless ofDEFAULT_USERmisconfiguration, at both config resolution and request-context resolution (get_user()). Startup refuses (clear error) when a non-production environment is explicitly configured with the production tenantjpmschweitzer, and one loud startup log line states the effective/forced tenant -
Conversation context for experts + real-time think messages - direct delegation (streaming and non-streaming) now passes a trimmed conversation history (last 6 turns) as expert context, so follow-up questions keep their referent;
_stream_direct_delegationis now an async generator, so butler think messages ("Allow me to consult the archives, sir.") stream BEFORE the research runs instead of after it completes -
Bounded retries and connection reuse for library-desk - GETs and the read-only
POST /query/*andPOST /rag/searchendpoints retry once (2 attempts, short backoff) on transport errors and retryable 5xx; wiki writes are never retried. The client now honorsLIBRARY_DESK_TIMEOUTinstead of hardcoded 60s/30s, a librarian run holds one shared HTTP connection instead of constructing a client per tool call, and read tools raiseModelRetryon transient HTTP errors so the agent's retry budget engages -
One librarian timeout budget - new
LIBRARIAN_TIMEOUT(default 180s) enforced withasyncio.wait_forinsidedelegate_to_librarian, capping the previously uncapped live paths (steward direct delegation and streaming). The Ollama provider's AsyncOpenAI client now carries an explicitOLLAMA_TIMEOUTinstead of the SDK's ~600s default, and the contradictory unused 60s default inAgentRequest.timeout_secondswas removed (None defers to the configured budget) -
Search degradation signaling - The librarian client parses
source_counts(plus the additivesource_status/degradedfields when a newer library-desk sends them; absence is tolerated), andhybrid_searchappends a one-line coverage note when a search is degraded or an enabled source leg contributed nothing, so outages are visible to the model and the user. Whensource_statusis present it is used exclusively; without it, count-absence is only inferred for the optional legs the request explicitly enabled (web/documents/volatile) - never the always-on vector/graph legs, whose absence from the top-N counts is normal ranking behavior, so healthy searches no longer emit warnings
Fixed
-
Clearing all wiki-page tags is possible again - the Ollama-safe empty-list sentinel in
update_wiki_pagemeans "leave unchanged", which made it impossible to remove all tags; passing exactly["__CLEAR__"]now sends an empty tag list to library-desk (documented in the tool docstring for the local model) -
Text-delegation fallback pairs results strictly - the parallel branch now verifies
asyncio.gatherreturned one result per parsed delegation (zip(..., strict=True)); a count mismatch fails loudly with a curated apology instead of silently attributing outputs to the wrong agent -
Ollama-safe librarian tool schemas -
update_wiki_pageandsmart_create_wiki_pageno longer useX | Noneparameters (Ollama's OpenAI-compatible API mishandlesanyOf[X, null]); empty-string/empty-list sentinels are translated toNoneinside the tools, matching the biographer pattern. A snapshot test pins every librarian tool schema to contain no nullableanyOf -
Honest expert failures -
run_librariannow raises a structuredAgentErrorinstead of returning error text as if it were research output, so delegation correctly reportssuccess=Falseand the streaming error branch is reachable. Failures surface to the user as curated butler-toned sentences; exception detail (including internal URLs) stays in the logs only. Librarian tool errors no longer leakstr(e)into synthesis -
HybridRAG response mapping - The librarian client now parses the field names library-desk actually returns (
source_type/sources,rrf_score,context, per-itemrelated_dossiers, synonyms nested in thekeywordsdict); previously every result rendered as "unknown (score: 0.00)". Source icons now key off the per-itemsourceslist. Requests no longer send zero limits (the service rejects them with 422); legs are disabled viaenable_*flags. Pinned by a contract test against a recorded live response (tests/agents/librarian/fixtures/)
[2.3.0] - 2026-07-13
Changed
- Local-first backend (claudification rollback) - Ollama/gemma4 is now the primary backend; Claude remains as fallback.
PREFER_CLOUD_BACKENDdefaults tofalse, Claude is used automatically when the Ollama startup health check fails, and the Steward retries mid-request failures on the other backend in both directions - Default Claude model
claude-sonnet-5-claude-sonnet-4-20250514was retired by Anthropic on 2026-06-15 and would 404, leaving the fallback dead - Dedicated orchestration prompt -
orchestrate_tool_calls()now uses a terse tool-execution prompt (TATLOCK_ORCHESTRATION_PROMPT); the butler persona prompt suppressed gemma4 tool calling (the model reasoned about the calculator, then answered from memory with wrong arithmetic). Synthesis keeps the persona prompt, so user-visible voice is unchanged
Fixed
- Startup crash with broken anthropic package - Anthropic SDK imports in the model selector are now lazy, so an incompatible
anthropicinstall degrades to Ollama-only operation instead of crashing the app at import time (root cause of the production outage since April) - Claude Sonnet 5 rejects sampling parameters - removed
temperaturefrom the Steward's direct Claude call and made the Housekeeper's temperature setting backend-conditional viaget_sampling_settings() - Pin
anthropic>=0.77,<1.0- the April image resolved an anthropic version incompatible with pydantic-ai 1.27 - Steward timeout configurable - new
STEWARD_TIMEOUT(default 60s) replaces the hardcoded 30s, which gemma4 chronically exceeded (~35s warm analysis), causing every request to fail or fall back
Added
- Ollama startup health check - verifies the server is reachable and
OLLAMA_DEFAULT_MODELis pulled; feeds backend resolution andget_model_info() - Contract tests (
tests/contracts/,make test-contracts) - wire-level tests that send the raw requests the code sends to Ollama (native + OpenAI-compat tool calling), Anthropic (including the pinned temperature-rejection contract), Qdrant, SearXNG, library-desk, and Redis; unreachable services skip, wrong response shapes fail - Backend resolution unit tests (
tests/anthropic/)
[2.2.0] - 2026-04-04
Changed
- Switch default Ollama model to gemma4:e2b - Replaces mistral-nemo as the local LLM backend; gemma4:e2b has native function calling support, faster tool calling (2-4s vs 15-20s), better parameter accuracy on word problems, and uses less VRAM (8GB vs 9.2GB)
Added
- Tool calling benchmark script (
scripts/benchmark_tool_calling.py) - Compares tool calling accuracy and latency across Ollama models via the Tatlock API
2.1.0 - 2026-02-05
Fixed
- Streaming SSE compatibility with Open WebUI - Switch from
exclude_none=Truetoexclude_unset=Truefor SSE chunk serialization;exclude_nonewas too aggressive — it strippedfinish_reason: nullfrom intermediate chunks (which OpenAI includes), whileexclude_unsetcorrectly omits only fields never passed to the constructor (likereasoning_contenton content-only chunks) while preserving explicitly-setfinish_reason: null
Changed
- Project structure consolidation - Moved documentation to
docs/, consolidated all config intopyproject.toml, replacedwakeup.sh/pytest.ini/requirements*.txtwithMakefile+pyproject.toml - CI test gate - Unit tests now gate release and build jobs in Gitea Actions workflow
- Build output organization - Tool caches in
.cache/, generated output (coverage, logs) inbuild/
2.0.5 - 2026-02-05
Fixed
- Streaming JSON compatibility - Exclude null fields from streaming chunks using
exclude_none=True; OpenAI's API omits null fields entirely, and including them (e.g.,content: null,reasoning_content: null) caused parsing issues in Open WebUI
[2.0.4] - 2026-02-05
Fixed
- Open WebUI streaming compatibility - Replaced
sse_starletteEventSourceResponsewith plainStreamingResponsefor chat completions;sse_starletteadded\r\nline endings and extra SSE fields that Open WebUI couldn't parse
[2.0.3] - 2026-02-05
Fixed
- Steward analysis leaking into responses - Removed internal routing analysis (
DELEGATE: tatlock_core...) from user-visible reasoning in both streaming and non-streaming paths
[2.0.2] - 2026-02-05
Fixed
- tool_choice format incompatibility - Removed
extra_bodytool_choice hack for Claude backend; PydanticAI handles tool_choice natively for Anthropic, preventing infinite tool call loops - CI trigger - Changed workflow trigger from
release:publishedtopush:tags:v[0-9]*
[2.0.1] - 2026-02-05
Fixed
- Expert agent registration failure -
AnthropicModeldoes not acceptapi_keydirectly; now passes it viaAnthropicProvider
2.0.0 - 2026-02-05
Added
-
Claude backend support (Claudification Phase 1) - All agents now prefer Claude over Ollama
- New
src/anthropic/module with model selector and health check get_model()factory returns Claude if available, Ollama as fallback- Startup health check caches Claude API availability
- Configuration:
ANTHROPIC_API_KEY,ANTHROPIC_MODEL,PREFER_CLOUD_BACKEND - 200k token context when using Claude backend
- New
-
Steward dual-backend support - Direct API calls to Claude or Ollama
_call_claude(): Anthropic Messages API path_call_ollama(): Existing Ollama generate API path (preserved)- Automatic fallback: if Claude call fails mid-request, retries with Ollama
-
Claudification project tracking -
PROJECT_CLAUDIFICATION.mdwith Phase 1/2 roadmap
Changed
- All PydanticAI agents refactored to use
get_model():- Tatlock (6 instantiation locations)
- Librarian
- Biographer
- Housekeeper
initialize_application()is now async - Supports async Claude health check at startup- Dependencies:
pydantic-ai-slim[openai,anthropic]replacespydantic-ai-slim[openai] - Startup logging now includes backend selection info (claude/ollama)
- Agent creation logging now includes backend and model info
Removed
- Stale
tests/core/test_benchmarks.py(benchmark system was removed in v1.10.0)
1.11.0 - 2025-12-30
Added
-
Paperless document integration - HybridRAG now includes indexed PDFs and scanned documents from Paperless-ngx
- New
include_documentsparameter inhybrid_searchtool - 📑 icon for document sources in search results
- Librarian prompt updated with document awareness
- New
-
Volatile cache integration - HybridRAG now includes pre-fetched real-time data
- New
include_volatileparameter inhybrid_searchtool - ⚡ icon for volatile sources in search results
- Supports weather, forecast, news, stock, crypto, sun, air_quality namespaces
- Librarian prompt updated with volatile cache awareness (user-configured items only)
- New
-
Biographer routing in Steward - Personal memory queries now correctly route to The Biographer
- Added explicit routing rules for "where do I live", "what car do I drive", etc.
- Added biographer delegation examples to Steward prompt
- Location keywords ("live", "where", "home") now trigger profile pre-fetch
Changed
- LibraryDeskClient.hybrid_search - Now passes full config including
document_limit,volatile_limit, and enable flags - Steward guidelines - Clarified that research queries about TOPICS go to Librarian, queries about USER go to Biographer
[1.10.1] - 2025-12-23
Fixed
- Tatlock's excessive apologizing - Strengthened personality prompt to prevent unnecessary apologies after successful Librarian delegations. Added explicit "do NOT apologize" instructions to both system prompt and synthesis prompt.
1.10.0 - 2025-12-22
Added
Lightweight Request Tracing
- JSON-based tracing system for local development debugging
- Captures full request flow through multi-agent architecture
TraceandSpandataclasses with automatic timing and nesting- ContextVar-based propagation for async-safe tracing
trace_spanasync context manager for clean instrumentation- Traces written to
logs/traces/{trace_id}.json - Enabled via
DEBUG=trueenvironment variable
- Trace Viewer UI (
logs/traces/viewer.html)- Standalone HTML viewer with timeline visualization
- Filter by status, search by request text
- Expandable span details with prompts and responses
- Tracing REST API (
/traces)GET /traces- Serve trace viewer UIGET /traces/list- List available traces with filteringGET /traces/{trace_id}- Retrieve specific trace JSON- Only available when
DEBUG=true
- Full pipeline instrumentation
- Router-level trace start/end with context management
- Steward analysis spans in preprocessing
- Tatlock orchestrate/synthesize spans
- Expert delegation spans (librarian/biographer/housekeeper)
- Tool-level spans extracted from PydanticAI messages
Changed
- Replaced Redis benchmarks with file-based tracing - Simpler, more useful for debugging
- Context management moved to service layer - Router simplified, context set in response service
- Server binds to all interfaces -
wakeup.shnow uses0.0.0.0for network access
Removed
- Redis benchmark system (
src/core/benchmarks.py)ENABLE_BENCHMARKSconfig settingREDIS_BENCHMARK_DBconfig settingredis_urlproperty (keptredis_memory_url)- Benchmark recording in Steward service and tool tracking
Fixed
- Librarian fabrication prevention - Added explicit instructions to never invent data when tools fail or sources are unavailable
1.9.0 - 2025-12-18
Changed
- Housekeeper prompt optimization - Rewrote system prompt for Mistral-Nemo function calling with negative constraints, step-by-step process, and explicit entity ID format guidance
- Housekeeper temperature setting - Set temperature to 0.1 for deterministic tool calling behavior
- Device list room group priority - Room groups now appear first in
list_devicesoutput with[ROOM GROUP]marker to address positional bias - Tool docstring improvements - Updated turn_on/turn_off/toggle with explicit
entity_id=parameter examples
Added
- Housekeeper optimization findings - Added
docs/housekeeper-optimization-findings.mddocumenting the experiment journey from 0% to 100% success rate - Housekeeper test script - Added
scripts/test_housekeeper.shfor room group detection regression testing
1.8.6 - 2025-12-17
Fixed
- Housekeeper API paths - Updated all client endpoints to use
/housekeeping/prefix to match core-api routes - Housekeeper entity hallucination - Improved system prompt with critical rule requiring
list_devices()before any control action to prevent guessing entity IDs
Added
- Housekeeping API spec - Added
docs/housekeeping-api-spec.mddocumenting the core-api home automation interface
1.8.5 - 2025-12-16
Fixed
- Redis benchmark boolean storage - Convert booleans to strings for Redis
hset(Redis doesn't accept bool type directly) - Tool tracking capability matching -
delegate_to_librariannow correctly recognized as using "librarian" capability when checking Steward recommendations - E2E test fixture scope - Fixed pytest-asyncio ScopeMismatch error by using
loop_scope="module"for module-scoped async fixtures
1.8.4 - 2025-12-16
Fixed
- Remove
<think>wrappers from think messages - Messages inreasoning_contentshould be plain text - Removed
<think>wrappers from delegation.py household think messages - Removed
<think>wrappers from orchestration.py status messages - Think messages now appear cleanly in Open WebUI's reasoning block
1.8.3 - 2025-12-16
Fixed
- Open WebUI streaming rendering - Use
reasoning_contentfield for thinking (DeepSeek R1 format) instead of<think>tags incontent - Open WebUI now renders thinking as proper collapsible blocks instead of broken HTML
1.8.2 - 2025-12-16
Fixed
- HybridRAG keywords schema mismatch - library-desk now returns
keywordsas dict withcore_keywords, client now handles both formats
1.8.1 - 2025-12-16
Fixed
Ollama Message Sanitization
- Fixed
invalid message content type: <nil>error from Ollama - Created custom
TatlockOllamaProviderthat sanitizes messages before sending to Ollama - Ollama rejects assistant messages with
content: null(tool-only messages from PydanticAI) - Provider converts
nullcontent to empty string""for compatibility - Updated all agents (Librarian, Biographer, Housekeeper, Tatlock) to use sanitized provider
- Added
src/ollama/provider.pywith reusable provider pattern
Streaming Think Message Accumulation
- Fixed repeating think messages in frontend (e.g., 10x "The Librarian has compiled...")
- Frontend was accumulating
ReasoningSummaryDeltaevents expecting concatenation - Added
ReasoningSummaryDone()signal after each think message to indicate completion - Each think slug is now treated as a complete message, not a continuation
1.8.0 - 2025-12-15
Fixed
Steward Routing for Web Search
- Updated Steward guidelines to route web searches, weather, news → Librarian with
search_web - Added URL/article reading → Librarian with
read_urlto routing guidelines - Added examples showing
search_webandread_urltool usage
Librarian Agent Tool Registration
- Registered
search_web,read_url,read_urls_batchtools with the Librarian PydanticAI agent - Updated Librarian system prompt with Web Search & Content Extraction section
- Fixed tool count in agent logger (11 → 14 tools)
Query Enrichment Integration
- Fixed enriched query (with location/timezone context) not being passed to delegations
- Response service now uses
enriched_queryfrom Steward recommendation for all delegations - Weather queries now automatically include user's stored location
Action Type Detection
- Added "read", "fetch", "url", "http" keywords to RESEARCH action type for Librarian
- Ensures proper think messages for URL reading tasks
1.7.0 - 2025-12-15
Added
Web Search Migration to Librarian
search_web()tool in Librarian for web search via library-desk/rag/searchendpointread_url()tool for single URL content extraction via Trafilaturaread_urls_batch()tool for parallel batch URL extraction (max 20 URLs)WebSearchResult,WebSearchResponsemodels in LibraryDeskClientContentExtractionResult,BatchExtractionResponsemodels for content extractionsearch_web(),extract_content(),extract_content_batch()methods in LibraryDeskClient- Comprehensive unit tests for new Librarian tools (
tests/agents/librarian/test_tools.py)
Changed
- Librarian capability updated with web search domains: "web", "url", "internet"
- Tatlock system prompt now delegates web search to Librarian
tatlock_corecapability reduced to computation/datetime only (no longer requires network)
Removed
search_webfunction fromsrc/agents/tatlock_core/tools.pyweb_search_toolfromtatlock_core_toolslistsearch_webfrom legacysrc/agents/tools.py- Search tests from
tests/agents/test_tools.py(moved to Librarian tests)
1.6.0 - 2025-12-15
Added
Two-Phase Tatlock Execution
- Phase 1: Orchestration - Executes tool calls and expert delegations, returns structured results
- Phase 2: Synthesis - Synthesizes butler-toned response from gathered results
orchestrate_tool_calls()method in TatlockAgent for coordination phasesynthesize_from_results()method in TatlockAgent for synthesis phase- Guarantees butler personality in all responses by separating coordination from response generation
Automatic Think Slugs
- Deterministic butler-perspective messages during expert delegation (no LLM involved)
ActionTypeenum: RETRIEVE, RESEARCH, CREATE, CONTROL, RECORDHOUSEHOLD_THINK_MESSAGESmapping with butler-perspective messages for all experts:- Librarian: "Allow me to consult the archives, sir." / "I'm having the Librarian prepare a new entry."
- Biographer: "Let me consult the household records." / "I've asked the Biographer to take note, sir."
- Housekeeper: "I'm instructing the household staff now, sir." / "Allow me to inquire with the household staff."
_detect_action_type()function for keyword-based action detectionget_think_message()helper for retrieving appropriate messages- Streaming delegation wrappers:
stream_delegate_to_librarian(),stream_delegate_to_biographer(),stream_delegate_to_housekeeper() STREAMING_DELEGATION_WRAPPERSmapping in delegation.pyget_streaming_delegation_tools()method in HouseholdRegistry
Steward Query Enrichment
- Auto-fill user context (location, timezone) when not specified in query
_build_enriched_query()function in steward service- Regex word boundary matching for accurate location detection (avoids false positives)
enriched_queryfield added toStewardRecommendationschema- Automatic enrichment for weather queries (location), time queries (timezone), temperature preferences
Documentation
- ORCHESTRATION_SCENARIOS.md completely rewritten with:
- Mermaid flow diagrams for two-phase execution
- 4 new Housekeeper scenarios (light control, device status, parallel delegation)
- Biographer memory recording scenario
- Complete think slug reference tables
- Action type detection tables
- Updated architecture mindmap
- TESTING_IMPROVEMENTS.md - LLM testing best practices for future implementation
Changed
create_response_with_steward()now uses two-phase execution_direct_delegation()routes through synthesis phase for consistent butler tone_execute_single_delegation()now supports housekeeper- Streaming response handler integrated with think slug system
- All 326 unit tests passing
1.5.0 - 2025-12-15
Added
The Housekeeper Agent
- New home automation expert agent following the Librarian pattern
CoreAPIClientfor communicating with core-api service (Home Assistant wrapper)- 13 tools for home automation:
- Discovery:
list_areas,list_devices,get_device_state - Control:
turn_on,turn_off,toggle - Scenes:
list_scenes,activate_scene - Scripts:
list_scripts,run_script - Automations:
list_automations,toggle_automation - History:
get_history
- Discovery:
- PydanticAI agent with system prompt for home automation tasks
HouseholdCapabilityregistration with domains: lights, switches, automation, home, smart home, scene, script, device, climate, fan, cover, blindsdelegate_to_housekeeper()delegation wrapper- Config settings:
CORE_API_HOST,CORE_API_KEY,CORE_API_TIMEOUT
Development Port Change
- Dev server port changed from 8123 to 8777 to avoid conflict with Home Assistant default port
- Updated
wakeup.sh, E2E tests, and documentation
Changed
- All unit tests pass (421 passed, 5 xfailed)
- Housekeeper registered on startup alongside Librarian and Biographer
1.4.0 - 2025-12-14
Added
Environment-Aware Configuration
- Auto-selected logging level: DEBUG for development, WARNING for production
- Auto-selected default user:
llm_testerfor development (isolated test scope),jpmschweitzerfor production - Properties
effective_log_levelandeffective_default_userin config - User context logging at request entry with INFO level
Direct Delegation Bypass
- Pure memory/librarian requests bypass Tatlock: When Steward recommends only biographer/librarian, skip Tatlock LLM call
_direct_delegation()function for immediate expert agent execution- Reduces latency for memory-only requests
Text-Based Delegation Fallback
- Parse text delegation patterns: Handle LLM outputs like
[DELEGATE:biographer] task="..." - Multiple pattern support for delegation parsing
- Sequential and parallel execution with
[PARALLEL]prefix
Comprehensive E2E Test Suite
- 22 new orchestration tests in
tests/e2e/test_orchestration_e2e.py QdrantVerifierhelper class for data verificationassert_llm_behavior()for flexible LLM output pattern matching- Test classes covering:
- Memory storage and recall
- Steward delegation
- Direct delegation bypass
- User context isolation (llm_tester vs production)
- Data verification in Qdrant
- Integration health checks
- Orchestration scenarios (weather, calculator, wiki, multi-expert)
- Error handling
- Evaluation reports
- Updated
tests/e2e/README.mdwith comprehensive documentation
Fixed
- Unit test mocks: Updated Steward streaming tests to mock
run_with_scoped_tools_stream(async generator) - Temporal context in tests: Tests now account for
_inject_temporal_context()appending timestamps - LLM non-determinism: Integration tests use
pytest.xfail()for LLM-dependent assertions - Streaming test timeouts: Increased timeouts (60-90s) for LLM processing time
Changed
- All unit tests now pass (380 passed, 5 xfailed for LLM non-determinism)
- E2E tests use
llm_testeruser for isolation from production data
1.3.3 - 2025-12-14
Fixed
- Memory: Fix Qdrant point IDs - use UUID5 instead of arbitrary strings
1.3.2 - 2025-12-14
Fixed
- Memory: Fix biographer tool type hints for Ollama compatibility (remove
| Noneunion types)
1.3.1 - 2025-12-14
Fixed
- Memory: Add biographer to delegation wrappers (was returning raw tools causing Ollama error)
- Config: Add Qdrant host/port to .env.example
1.3.0 - 2025-12-14
Fixed
- Memory: Update Qdrant client to use
query_pointsAPI (qdrant-client >= 1.10)
Changed
- Config: Rename
REDIS_DBtoREDIS_BENCHMARK_DBfor clarity - Config: Update Redis defaults to match stack allocation (benchmark=6, memory=1)
1.2.5 - 2025-12-14
Fixed
- Dependencies: Add missing
pydantic-settings(not included in pydantic-ai-slim)
1.2.4 - 2025-12-14
Added
- CI: Trigger Watchtower update after successful image push
1.2.3 - 2025-12-14
Fixed
- CI: Upgrade to build-push-action@v6, disable provenance and sbom for Gitea registry
1.2.2 - 2025-12-13
Fixed
- CI: Add
provenance: falseto docker/build-push-action to fix Gitea registry push
1.2.1 - 2025-12-13
Changed
- Dependency slimming: Switched from
pydantic-aitopydantic-ai-slim[openai]- Removes unused LLM provider SDKs (anthropic, boto3, cohere, google-genai, groq, huggingface)
- Production packages: 53 (down from ~158)
- Production footprint: 178MB
- Tatlock uses Ollama via OpenAI-compatible API, so only
openaiextra is needed - See
DEPENDENCY_SLIM.mdfor rollback instructions
1.2.0 - 2025-12-13
Added
Phase F: Memory System (The Biographer)
-
Memory Infrastructure (Phase F.1):
src/core/context.py: ContextVar-based request context for async-safe user/conversation trackingget_user(),get_conversation_id()helpersRequestContextmanager for clean setup/teardown
src/core/multi_tenancy.py: User ID sanitization and collection naming- Per-user collection pattern:
memories_{user} - Redis key patterns:
session:{user}:{conv},entities:{user}:{conv}
- Per-user collection pattern:
src/core/embeddings.py: Ollama embedding client- nomic-embed-text model (768 dimensions)
embed(),embed_batch(),health_check()methods
src/core/qdrant.py: Qdrant vector database clientensure_collection(),upsert_memory(),search_memories(),delete_memory()- Type-based filtering for memory queries
src/core/memory_cache.py: Redis session memory cache- Session context with 24h TTL (db=2, separate from benchmarks)
- Recent entities tracking per conversation
-
Memory Service (Phase F.2a):
src/core/memory_service.py: Direct access layer for fast, LLM-free memory lookups- Profile methods:
get_profile(),set_profile() - Preference methods:
get_preference(),set_preference(),get_all_preferences() - Fact methods:
store_fact(),get_fact() - Session context:
get_session_context(),set_session_context(),update_session_context() - Steward integration:
prefetch_context()for request preprocessing
- Profile methods:
-
The Biographer Agent (Phase F.2b):
src/agents/biographer/: Household memory keeper agent- PydanticAI agent with discreet chronicler personality
- System prompt emphasizes privacy and accurate recall
- Biographer Tools (
src/agents/biographer/tools.py):recall_semantic: Semantic search for memories by meaninglist_memories: Browse stored memories by typestore_insight: Record new facts from conversationupdate_profile: Update core profile fields (name, location, timezone)update_preference: Update user preferences (units, theme)forget_memory: Remove specific memories
- Capability Registration:
BIOGRAPHER_CAPABILITYwith context domain- Automatic registration on startup
- Low cost (vector search, minimal LLM)
-
Delegation Wrapper:
delegate_to_biographer()insrc/agents/delegation.py- Async delegation with error handling
-
Steward Memory Integration:
- Memory context pre-fetch during request analysis
- Profile and preferences included in Steward's note to Butler
- Keyword-based context determination (weather → location, time → timezone)
-
Configuration:
QDRANT_HOST,QDRANT_PORT,QDRANT_EMBEDDING_DIM(768)OLLAMA_EMBEDDING_MODEL(nomic-embed-text)REDIS_MEMORY_DB(2),REDIS_MEMORY_TTL_HOURS(24)
-
Test Suite:
- 34 new tests for memory system
- Biographer capability tests (15 tests)
- Memory service tests (19 tests)
-
OpenAI Standard
userField:- Added
userfield toResponseRequestschema - Request context set at API entry point
- Propagates through async calls via ContextVar
- Added
Changed
- Application startup now registers The Biographer with Household Registry
- Steward analysis includes memory context pre-fetch
- Librarian client methods now use
get_user()from context (12 methods updated) - Request router sets user/conversation context at entry
1.1.0 - 2025-12-11
Added
Phase 3: Butler Orchestration (Multi-Agent Coordination)
-
The Librarian Agent: Expert agent for research and knowledge management
- PydanticAI agent with specialized research assistant personality
- Connects to library-desk API for HybridRAG capabilities
- System prompt emphasizes fetching wiki pages before summarizing
- Streaming support via
run_librarian_stream()
-
Library-Desk API Client (
src/agents/librarian/client.py):- Async HTTP client with httpx for library-desk API integration
- HybridRAG search (vector + graph + web search)
- Wiki operations (search, get, list, create, update pages)
- Smart page creation with HybridRAG research (
POST /wiki/pages/smart-create) - Semantic vector search
- Knowledge graph queries (Cypher execution)
- Dossier (tag collection) browsing
- Health check endpoint
-
Librarian Tools (
src/agents/librarian/tools.py):- Research tools:
hybrid_search: Combined vector, graph, and web searchsearch_wiki: Full-text wiki page searchget_wiki_page: Fetch full wiki page content by IDsemantic_search: Vector similarity searchlist_dossiers: Browse knowledge collectionsget_dossier_pages: Get pages in a dossierexplore_knowledge_graph: Entity and relationship discoveryfind_related_entities: Find connected concepts
- Write tools:
smart_create_wiki_page: Create page with automatic HybridRAG research (PREFERRED for topic-based creation)create_wiki_page: Create page with user-provided contentupdate_wiki_page: Update existing page (partial updates supported)
- Research tools:
-
Agent Communication Protocol (
src/agents/protocol.py):AgentRequest: Standardized task request with context and constraintsAgentResponse: Response with result, reasoning, tool calls, confidenceDelegationIntent: Routing intent with target agent and reasonCoordinationResult: Aggregated multi-agent resultsDelegationReasonenum: domain expertise, tool access, resource efficiency, user preference- Error types:
AgentError,AgentTimeoutError,AgentUnavailableError
-
Coordination Engine (
src/agents/coordination.py):CoordinationEngine: Multi-agent task orchestration- Routing tasks to appropriate expert agents
- Sequential and parallel execution support
- Result aggregation from multiple agents
- Graceful error handling and degradation
- Streaming delegation support
- Convenience functions:
delegate_to_librarian(),delegate_to_librarian_stream()
-
Librarian Capability Registration:
LIBRARIAN_CAPABILITYdefinition with research domains- Automatic registration on application startup
- Integration with Household Registry
-
Configuration:
LIBRARY_DESK_HOST: Library-desk API URL (default:http://localhost:8089)LIBRARY_DESK_API_KEY: Optional API key for authenticationLIBRARY_DESK_TIMEOUT: Request timeout in seconds (default: 60)
-
Test Suite:
- 78 new tests for Phase 3 components
- Protocol model tests (requests, responses, intents, errors)
- Coordination engine tests (delegation, streaming, multi-agent)
- Library-desk client tests (all endpoints with mocked HTTP)
- Wiki write operation tests (update, smart-create)
- Capability registration tests
Changed
- Application startup now registers The Librarian with Household Registry
- Configuration expanded to support library-desk API integration
- Version loading: APP_VERSION now dynamically loaded from pyproject.toml
1.0.0a - 2025-12-11
Added
- CI/CD Pipeline: Release-triggered automated builds
- Dockerfile for containerized deployment (Python 3.12-slim, port 8000)
- Gitea Actions workflow triggered on release publish
- Builds and pushes to git.schweitz.net registry with latest and version tags
- Watchtower integration for automatic container updates
- Portainer Stack: Production deployment configuration
- Connects to docker-dataplane network for service discovery
- Integration with ollama, searxng, and redis-shared services
- Health check endpoint monitoring
- Resource limits (1 CPU, 1GB memory)
Changed
- Version bump to 1.0.0 marking production-ready release
0.2.5 - 2025-12-07
Added
Phase 2: The Steward (Two-Tier Architecture)
-
The Steward Agent: First-tier LLM agent for request analysis and capability recommendation
- Analyzes requests with full conversation context awareness
- Recommends relevant household capabilities for each request
- Detects missing capabilities and provides guidance
- Estimates request complexity (simple/moderate/complex)
- Uses same Ollama model as Tatlock for VRAM efficiency
-
Household Registry: Centralized capability management system
HouseholdRegistryfor registering capabilities and toolsetsHouseholdCapabilityexecutive summaries for coordinationHouseholdMemberspecifications with PydanticAI toolsets- Domain-based tool organization (e.g.,
src/agents/tatlock_core/) - Dynamic tool scoping per request
-
Request Preprocessing Pipeline: Steward → Tatlock flow integration
preprocess_request()orchestrates Steward analysis- Creates scoped toolsets based on recommendations
- Formats Steward notes for Butler (conversation context included)
- Integrated with Responses API via
create_response_with_steward()
-
Tool Usage Tracking: Benchmarking and accuracy analysis
ToolCallTrackerfor monitoring recommended vs. actual tool usage- Tracks recommendation accuracy metrics
- Records benchmarks to Redis for cross-session analysis
- Supports precision/recall/F1 score calculation
-
Streaming Transparency: Real-time Steward analysis visibility
- Streams Steward's reasoning as reasoning summary deltas
- Streams Tatlock's response as output text deltas
- Full SSE support for Steward + Tatlock flow
- Conversation context and missing capabilities visible in stream
-
Structured Logging: Operation timing and metadata tracking
structlog-based JSON logging for machine parsing- Context managers for automatic operation timing
- Metadata enrichment for debugging and analysis
- Integrated with benchmark recording
-
Redis Benchmark Storage: Performance metrics persistence
- Cross-session benchmark storage with 30-day expiry
- Time-series metrics for Steward analysis and tool calls
- Queryable by operation, time range, and metadata
- Support for recommendation accuracy tracking
-
Benchmark Analysis Tools: Performance analysis CLI
scripts/benchmark_analysis.pyfor metric analysis- Steward performance statistics (latency, success rate, recommendations)
- Tool recommendation accuracy analysis (precision, recall, F1)
- Per-tool accuracy breakdown and duration statistics
-
End-to-End Test Suite: Comprehensive API integration tests
- 17 E2E tests making real HTTP requests to running server
- Tests for Chat Completions, Responses API, and streaming endpoints
- OpenAI API spec compliance verification (format validation)
- Steward preprocessing integration verification
- Error handling tests (404, 422 status codes)
- Flexible assertions for LLM output variance
- Tool usage indicators: 🧮 (calculator), 🔍 (search), 🕐 (datetime)
- Full documentation in
tests/e2e/README.md
Phase 1 Enhancements
- Conversation history support: Tatlock now remembers previous turns in multi-turn conversations
- OpenAI-format messages converted to PydanticAI
ModelRequest/ModelResponseobjects - Full conversation context passed to agent via
message_historyparameter - Empty messages filtered to prevent Ollama errors
- OpenAI-format messages converted to PydanticAI
- Tool call logging to reasoning output: Users can see what tools are doing in real-time
ToolCallTrackerdependency system for per-request tool usage logging- Web search queries appear with 🔍 emoji (e.g., "🔍 Searching for: 'Python 3.13'")
- Calculator expressions appear with 🧮 emoji (e.g., "🧮 Calculating: sqrt(144) + 25")
- Date/time operations appear with 🕐 emoji (e.g., "🕐 Calculating date offset: 2 weeks ago")
- Tool usage visible in
<think>tags in Open WebUI
Changed
- Architecture: Two-tier request flow (Steward analysis → Tatlock execution)
- Tool Organization: Tatlock core tools reorganized into domain directory
- Tool Scoping: Tatlock runs with dynamically scoped toolsets per request
- Responses API: Integrated Steward preprocessing for all Tatlock requests
- Streaming: Enhanced to include Steward reasoning transparency
- Enhanced Tatlock agent with conversation memory capabilities
- All tools now log their usage via
RunContextdependencies - Improved debug logging for message history construction
Fixed
- Streaming text repetition: Fixed text accumulation bug causing repetitive output in Open WebUI
- Changed from accumulated text to delta mode (
stream_text(delta=True)) - Implemented proper
run_with_scoped_tools_stream()using PydanticAI'srun_stream() - Replaced artificial word-by-word chunking with real LLM deltas
- Changed from accumulated text to delta mode (
- Broken tool execution in streaming: Tools now execute properly in streaming mode
- Previously showed raw JSON function calls instead of executed results
- Now properly streams tool execution results
- Invalid schema parameter: Removed invalid
thinkingparameter fromReasoningOutputItem - Case sensitivity in model routing: Model comparison now case-insensitive (
.lower()) - Conversation context now properly maintained across multiple turns
- Tool usage transparency - users can see exactly what queries/calculations are being performed
- Schema object handling in usage calculation (_calculate_usage reordered isinstance checks)
0.2.0 - 2025-12-06
Added
PydanticAI Integration (Phase 1)
- Real Tatlock agent using PydanticAI with Ollama backend (mistral-nemo:latest)
- British butler personality with research-oriented mindset
- Lazy agent initialization to avoid connection issues in tests
- Streaming response integration with reasoning output
- Error handling for PydanticAI-specific exceptions
Permanent Tools (Phase 1)
- Calculator tool (
src/agents/tools.py):- Safe mathematical expression evaluation using restricted namespace
- Support for arithmetic, algebra, trigonometry, logarithms
- Math functions: sqrt, sin, cos, tan, log, exp, etc.
- Constants: pi, e
- Integer result formatting (removes unnecessary decimals)
- Date/Time toolkit:
get_current_datetime: Current date/time in multiple formatscalculate_time_offset: Relative date calculations ("1 week ago", "2 months from now")time_difference: Human-readable time differences between dates
- Web Search tool:
- SearXNG integration for privacy-preserving web search
- Automatic fallback from production to localhost in development
- Formatted search results with titles, URLs, and snippets
- Configurable result limits (max 10)
Tool Framework
- PydanticAI tool registration with
@agent.tooldecorator - Tool descriptions visible to LLM for intelligent usage
- Async tool support for I/O operations
- Error handling with string-based error messages
- Tool usage guidelines in system prompt
Configuration
- SearXNG configuration in
src/core/config.py:SEARXNG_HOSTwith development fallbackSEARXNG_TIMEOUTsetting
- Updated
.env.examplewith SearXNG configuration - Ollama configuration documentation
Testing
- 26 new tool tests (
tests/agents/test_tools.py):- 7 calculator tests (arithmetic, functions, error handling)
- 14 date/time tests (current time, offsets, differences)
- 5 web search tests (mocked HTTP client)
- Updated registry tests for tools capability
- Total: 131 tests, 81.78% coverage (up from 95 tests, 78.95%)
Documentation
- Comprehensive README.md updates:
- Tatlock agent capabilities and tool descriptions
- Requirements section with Ollama and SearXNG setup
- Configuration examples for external services
- Tool usage examples and philosophy
- Troubleshooting for Ollama and SearXNG
- Updated test statistics
- AGENTS.md refactored for LLM development:
- PydanticAI tool registration pattern
- Tool implementation guidelines
- Removed project status, focused on development instructions
- IMPLEMENTATION_ROADMAP.md updates:
- Phase 1 marked as "MOSTLY COMPLETE"
- Detailed completion status for each deliverable
- Updated current state summary
Changed
- Tatlock agent converted from mock to real PydanticAI implementation
- Tatlock capabilities updated:
tools: True - Streaming coordination now handles chunk-based delivery (50 chars) to preserve markdown
- Chat service streaming updated to preserve formatting
- System prompt enhanced with tool usage guidelines and research mindset
- Agent initialization changed to lazy pattern for better testability
Fixed
- Text duplication bug in streaming responses (proper delta calculation)
- Markdown formatting preservation in streamed responses
- GeneratorExit errors from async context managers in generators
- PydanticAI API usage (
result.outputinstead ofresult.data)
0.1.1 - 2025-12-06
Added
Agent Interface (Phase 1)
- Abstract
AgentInterfacebase class for model abstraction LoremTesterAgent: Full-featured mock agent with realistic behavior- Configurable reasoning effort levels (none, minimal, low, medium, high, xhigh)
- Random tool/function call generation for testing
- Error triggers: rate_limit, context_overflow, invalid_tool
- Temperature-based response variation
TatlockAgent: Placeholder for future PydanticAI integrationModelRegistry: Centralized model management and discovery- 18 agent tests with comprehensive coverage
Responses API (Phases 2, 3, 6)
- OpenAI Responses API format with structured output (
/v1/responses)- Reasoning items (thinking summaries with configurable effort)
- Function call items (tool execution simulation)
- Message items (assistant responses with output_text)
- Streaming and non-streaming modes
- Real-time streaming with SSE-Starlette
- Conversation history management (Phase 3):
- Hybrid client/server approach (client maintains state, server tracks)
- Auto-generated deterministic conversation IDs from message hash
- Configurable max turns with automatic trimming (default: 20)
- Context window management with approximate token counting
- Token usage statistics
- Placeholder for future vector memory (Qdrant)
- Advanced features (Phase 6):
- Parameter validation with Pydantic field validators
- Temperature: 0.0-2.0 range enforcement
- Reasoning effort: 6 levels validation
- Max output tokens: positive integer enforcement
- Stop sequences: up to 4, non-empty strings
- Real-time stop sequence detection during streaming
- Real-time max tokens enforcement with token counting
- 45 Responses API tests (router, error handling, history, advanced features)
Chat Completions Wrapper (Phase 5)
- OpenAI Chat Completions compatibility layer (
/v1/chat/completions) - Single source of truth architecture (wraps Responses API)
- Automatic reasoning generation
- Converts reasoning items to
<think>tags for Open WebUI - Pipeline prefix preservation
- System message support
- Enhanced error types (RateLimitError, ContextLengthError)
- 12 Chat Completions tests (router + streaming wrapper)
Application Infrastructure
- FastAPI application factory pattern
- CORS middleware with configurable origins
- Global exception handlers:
- AppException handler for custom errors
- RequestValidationError handler for Pydantic validation
- General exception handler for unexpected errors
- Lifespan management for startup/shutdown
- OpenAPI schema with interactive documentation
- 16 main application tests
Testing Infrastructure
- Comprehensive test suite: 95 tests, 78.95% coverage (up from 62%)
- Async test support with pytest-asyncio
- Test fixtures for sync and async clients
- Integration tests for all API endpoints
- Streaming functionality tests
- Parameter validation tests
- Error handling tests
- Conversation history tests
Documentation
- Complete README.md rewrite with hybrid architecture
- Architecture diagrams and decision documentation
- AGENTS.md with technical implementation details
- API usage examples for all endpoints
- Conversation history guide
- Open WebUI integration instructions
- Troubleshooting section
- Implementation planning documents
Changed
- Hybrid architecture with Responses API as primary endpoint
- Chat Completions now wraps Responses API (no duplicate logic)
- Enhanced error handling with OpenAI-compatible format
- Improved streaming with word-by-word delivery
- Better test organization with domain-based structure
Security
- Minor version locking for all dependencies
- All packages CVE-checked (as of 2025-12-06)
- Environment variable protection via .gitignore
- No known vulnerabilities in dependency tree
- Input validation on all API endpoints
0.1.0 - 2025-12-06
Added
- Project initialization
- Python 3.12.11 environment
- FastAPI 0.123.9 web framework
- PydanticAI 1.27.0 dependency (ready for future integration)
- Mock chat completions (lorem ipsum responses)
- Mock model listing (mistral-nemo:latest)
- Testing infrastructure (pytest, coverage, ruff, mypy)
- Configuration management with pydantic-settings
- CORS middleware
- Exception handlers (OpenAI-compatible error format)