Commit Graph
61 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 2f6e444147 docs: drop deleted run_librarian_stream from unreleased changelog entry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:45:48 +02:00
jpmschweitzerandClaude Fable 5 5376a34645 refactor(agents): reduce protocol.py to the live AgentError
Post-coordination-removal sweep: the coordination wire protocol
(AgentRequest, AgentResponse, DelegationIntent, CoordinationResult,
DelegationReason, TaskComplexity, ToolCallRecord, AgentTimeoutError,
AgentUnavailableError, DelegationError) had zero importers left in
src/ - only its own test module. AgentError stays (raised by
run_librarian, mapped to user-safe failures by delegation.py).
Also drops the stale coordination.py line from the README tree.

Import-cycle sanity: python -c 'import src.main' passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
2026-07-14 12:03:31 +02:00
jpmschweitzerandClaude Fable 5 8cf3609948 fix(librarian): quiet healthy-search coverage notes, tag clearing, strict result pairing
Phase A review minors:

- Coverage note: source_status (when present) is now used exclusively;
  the source_counts-absence fallback only considers the optional legs
  the request explicitly enabled (web/documents/volatile). library-desk
  computes source_counts from the final top-N fused results only, so
  absence of the always-on vector/graph legs is normal ranking behavior
  - the old heuristic warned on virtually every healthy search
- update_wiki_page: the empty-list tags sentinel (leave unchanged) made
  clearing all tags impossible; pass exactly ["__CLEAR__"] to send an
  empty tag list, documented in the docstring for the local model
- Text-delegation parallel fallback: zip(..., strict=True) with an
  explicit count-mismatch guard so results can never be silently
  attributed to the wrong agent

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
2026-07-14 11:59:15 +02:00
jpmschweitzerandClaude Fable 5 31b948a748 refactor(agents): delete dead coordination/streaming delegation stack
One delegation implementation remains (src/agents/delegation.py).
Removed, after verifying zero live importers post-Phase-A/B:

- src/agents/coordination.py: CoordinationEngine, duplicate
  delegate_to_librarian, AGENT_EXECUTORS/AGENT_STREAM_EXECUTORS
  (only importer was its own test module)
- run_librarian_stream: documented-broken path (Ollama streaming +
  tool call bug, PydanticAI #1292/#2256), only called by the deleted
  coordination engine
- stream_delegate_to_* wrappers + STREAMING_DELEGATION_WRAPPERS and
  the never-parsed __DELEGATION_RESULT__ marker in delegation.py
- HouseholdRegistry.get_streaming_delegation_tools() (no callers)
- tests/agents/test_coordination.py and the wrapper/stream tests

Note: the STREAMING_DELEGATION_WRAPPERS import in
src/responses/streaming.py was already removed by Phase A (7ce1c1a);
nothing to delete there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
2026-07-14 11:52:36 +02:00
jpmschweitzerandClaude Fable 5 b47c5b9281 test: hard-fail the suite when the tenant resolves to production
Session-scoped autouse guard in tests/conftest.py refuses to run any
test (pytest.exit, returncode 1) when the effective tenant resolves
to the production tenant jpmschweitzer - the same guard library-desk
applies on its side. _initialize_app now depends on the guard so the
refusal happens before any initialization.

Suite-level assertions pin that the live session runs under the
llm_tester namespaces: Qdrant memories_llm_tester collection and
Redis session:llm_tester:* keys. The biographer/memory unit tests
already run fully mocked (no shared-service writes); the e2e
isolation tests already used llm_tester - their constants now derive
from the shared TEST_TENANT/PRODUCTION_TENANT config constants so a
drift fails loudly instead of silently splitting.

Verified: ENVIRONMENT=production pytest run exits 1 with the TENANT
GUARD message and zero tests executed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:08:39 +02:00
jpmschweitzerandClaude Fable 5 b9eae38556 feat(librarian): send explicit non-empty user on every library-desk request
Library-desk is removing its server-side default user, so a request
without an explicit tenant will 422 after its next deploy:

- New client-level _resolve_user() resolves the tenant (explicit arg
  or request context) and raises ValueError on an empty/whitespace
  value BEFORE any bytes hit the wire; all 15 tenant-scoped methods
  use it
- extract_content / extract_content_batch now accept and send the
  user (query param), matching the rest of the API surface
- search_web no longer falls back to a phantom "tatlock-librarian"
  tenant; it sends the resolved user
- health_check stays user-less (public, not tenant-scoped)

Tests: parametrized sweep pins the wire contract (user present in
params or payload) for every tenant-scoped method, for both context
and explicit users; empty-tenant calls are asserted to fail without
any HTTP call; the recorded-fixture hybrid contract test now pins
user as an explicit query param.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:02:46 +02:00
jpmschweitzerandClaude Fable 5 4b786a766c feat(core): enforce tenant isolation guard outside production
Non-production environments (development/testing) now force the
effective tenant to the reserved test tenant "llm_tester" (or a
test_-prefixed override) regardless of DEFAULT_USER misconfiguration:

- Config.effective_default_user only honors DEFAULT_USER outside
  production when it is llm_tester or test_-prefixed; anything else
  is forced to llm_tester (tenant_forced flags the override)
- Config refuses startup (validation error) when a non-production
  environment is explicitly configured with the production tenant
  jpmschweitzer
- get_user() applies the same guard at request-context resolution,
  so an explicit request for the production tenant in dev/test is
  forced to llm_tester with a warning log
- initialize_application() emits one loud startup log line
  (tenant_guard_active / tenant_guard_production) stating the
  effective tenant

Unit tests cover the dev/test/prod x default/explicit-user matrix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:56:29 +02:00
jpmschweitzerandClaude Fable 5 7ce1c1a314 feat(responses): pass conversation context and stream thinks in real time
- delegate_to_* now receives a trimmed conversation history (last ~6
  turns, 500 chars/turn) as context on both live direct-delegation
  paths (streaming and steward non-streaming), via new
  build_delegation_context helper
- _stream_direct_delegation restructured as an async generator: the
  butler 'start' think message streams BEFORE the expert runs and the
  success/error message right after it finishes, instead of all
  messages arriving after the research completed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:30:34 +02:00
jpmschweitzerandClaude Fable 5 0708c759fc fix(librarian): replace nullable tool params with sentinel defaults
Ollama's OpenAI-compatible API mishandles anyOf[X, null] parameter
schemas. update_wiki_page (content/title/tags/description) and
smart_create_wiki_page (path) now use empty-string/empty-list
sentinels translated to None inside the tool, following the
biographer pattern from 9d7ce39.

Adds a snapshot test that walks every registered librarian tool's
emitted JSON schema and fails on any anyOf[..., null].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:26:55 +02:00
jpmschweitzerandClaude Fable 5 24fed8814f feat(librarian): bounded retries, timeout wiring, and client reuse
- 2-attempt short-backoff retry for GETs and the read-only
  POST /query/* and /rag/search endpoints only; wiki writes are never
  retried (duplicate-page risk)
- honor the defined-but-ignored LIBRARY_DESK_TIMEOUT config instead of
  hardcoded 60s/30s per-call values
- hold ONE shared httpx.AsyncClient per librarian run via
  library_client_session (contextvar), instead of constructing a
  client per tool call; nested sessions are no-ops and custom targets
  still get their own client
- read tools raise ModelRetry on transient HTTP errors (transport
  errors, 5xx, 429) so Agent(retries=2) engages; write tools keep
  returning safe failure messages

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:24:42 +02:00
jpmschweitzerandClaude Fable 5 18f2e0efbd feat(agents): enforce one librarian timeout budget
- add LIBRARIAN_TIMEOUT config (default 180s) and enforce it with
  asyncio.wait_for inside delegate_to_librarian, covering the live
  paths (steward direct delegation and SSE streaming) that had no cap
- timeouts fail honestly: success=False with a curated butler sentence,
  detail in logs
- set an explicit timeout on TatlockOllamaProvider's AsyncOpenAI client
  from OLLAMA_TIMEOUT instead of the SDK default (~600s per LLM call)
- remove the contradictory unused 60s default from
  AgentRequest.timeout_seconds; coordination falls back to the
  configured budget

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:19:16 +02:00
jpmschweitzerandClaude Fable 5 99e1fe33ca feat(librarian): signal degraded search coverage
- parse source_counts into HybridRAGResponse and additively parse the
  shared-contract source_status/degraded fields when present (absence
  tolerated, so deploy order between tatlock and library-desk never
  matters)
- hybrid_search appends a one-line coverage note when a leg reported
  'failed' (or degraded is set), falling back to inferring silent legs
  from source_counts on older library-desk versions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:15:09 +02:00
jpmschweitzerandClaude Fable 5 f853db8ccc fix(agents): make librarian failures structured and user-safe
- run_librarian / run_librarian_stream raise AgentError instead of
  returning/yielding error text as normal output; detail stays in logs
- delegate_to_* wrappers now put a curated butler-toned sentence in
  DelegationResult.output on failure and never expose str(e), so
  streaming's error branch is reachable and honest
- _execute_single_delegation propagates success; direct delegation only
  records delegate_to_* as called when the expert actually succeeded
- librarian tools return user-safe messages instead of
  'Error searching: {e}' strings that leaked internal URLs into
  synthesis; coordination stream errors are curated as well
- ruff cleanups (TYPE_CHECKING forward refs, B904, unused locals) in
  the touched files to keep them lint-clean

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:12:30 +02:00
jpmschweitzerandClaude Fable 5 59f5b54ac9 fix(librarian): map live HybridRAG response fields correctly
The client parsed field names the live library-desk service never
returns, so every result rendered as "unknown (score: 0.00)":

- source_type/sources -> source + sources (icons key off sources values)
- rrf_score -> score
- context -> formatted_context
- related_dossiers are per-result; top level aggregates unique titles
- synonyms live inside the keywords dict as a {term: [synonyms]} map

Also stop sending zero limits (service 422s on limit < 1); disabled
legs now rely on the enable_* flags with limits clamped to >= 1.

Adds a recorded live response as a fixture plus contract tests that
pin the mapping (non-unknown sources, non-zero scores, icon coverage).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:00:10 +02:00
jpmschweitzerandClaude Fable 5 11405e0acb chore: release v2.3.0
Build and Push / release (push) Successful in 25s
Build and Push / build (push) Successful in 4m34s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 23:54:32 +02:00
jpmschweitzerandClaude Fable 5 d2aeb8957b docs: document local-first backend, gemma4 gotchas, and contract tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 18:35:53 +02:00
jpmschweitzerandClaude Opus 4.6 427ad311dc feat: switch default Ollama model to gemma4:e2b
Build and Push / release (push) Successful in 21s
Build and Push / build (push) Successful in 5m27s
gemma4:e2b has native function calling with dedicated tool tokens,
achieving 100% tool selection accuracy in benchmarks vs 67% for
mistral-nemo-large, with 5-8x faster response times (2-4s vs 15-20s)
and lower VRAM usage (8GB vs 9.2GB).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:44:27 +02:00
jpmschweitzerandClaude Opus 4.6 f49c5ac02c fix: use exclude_unset for SSE streaming chunk serialization
Build and Push / test (push) Failing after 1m46s
Build and Push / build (push) Has been skipped
Build and Push / release (push) Has been skipped
exclude_none was too aggressive — it stripped finish_reason: null from
intermediate chunks (which OpenAI includes). exclude_unset correctly
omits only fields never passed to the constructor (like reasoning_content
on content-only chunks) while preserving explicitly-set finish_reason: null.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:18:20 +01:00
jpmschweitzerandClaude Opus 4.5 8092740fa4 fix: exclude null fields from streaming chunks for Open WebUI compatibility
Build and Push / release (push) Successful in 3s
Build and Push / build (push) Successful in 1m24s
OpenAI's API omits null fields in streaming chunks, but Tatlock was
including them (content: null, reasoning_content: null). This caused
parsing issues in Open WebUI's streaming handler.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:36:37 +01:00
jpmschweitzerandClaude Opus 4.5 e469746f75 fix: use StreamingResponse for chat completions SSE
Build and Push / release (push) Successful in 2s
Build and Push / build (push) Successful in 1m22s
sse_starlette's EventSourceResponse added \r\n line endings that
Open WebUI couldn't parse. Switched to plain StreamingResponse with
manual SSE formatting matching OpenAI's exact format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:29:08 +01:00
jpmschweitzerandClaude Opus 4.5 31e7884d8f fix: remove Steward analysis from user-visible reasoning
Build and Push / release (push) Successful in 3s
Build and Push / build (push) Successful in 1m21s
The Steward's internal routing analysis (DELEGATE, COMPLEXITY, etc.)
was being exposed in <think> blocks. This is implementation detail,
not useful reasoning for the user.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:19:05 +01:00
jpmschweitzerandClaude Opus 4.5 e15def607d fix: remove extra_body tool_choice hack for Claude backend
Build and Push / build (push) Successful in 1m57s
Build and Push / release (push) Successful in 3s
PydanticAI handles tool_choice natively for Anthropic. The extra_body
hack caused an infinite tool call loop where Claude kept calling the
same tool because tool_choice was forced to "any".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 11:51:42 +01:00
jpmschweitzerandClaude Opus 4.5 3617218359 chore: release v2.0.1
Build and Push / release (release) Failing after 3s
Build and Push / build (release) Successful in 1m21s
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 09:49:46 +01:00
jpmschweitzerandClaude Opus 4.5 496f37a538 feat: add Claude backend with automatic Ollama fallback (Claudification Phase 1)
Build and Push / release (release) Failing after 6s
Build and Push / build (release) Successful in 3m5s
All agents now prefer Claude API when ANTHROPIC_API_KEY is configured,
with automatic fallback to Ollama when offline or unconfigured. New
src/anthropic/ module provides model selection via get_model() factory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 07:19:29 +01:00
jpmschweitzerandClaude Opus 4.5 62eac3eb61 feat: integrate Paperless documents and volatile cache into Librarian
Build and Push / build (release) Successful in 54s
- Add Paperless document search to HybridRAG pipeline
- Add volatile cache (weather, forecast, news, stocks) to HybridRAG
- Add include_documents and include_volatile params to hybrid_search
- Add 📑 and ⚡ icons for document/volatile sources
- Update Librarian prompt with new data source awareness
- Fix Biographer routing: personal memory queries now route correctly
- Add location keywords to Steward pre-fetch logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:31:23 +01:00
jpmschweitzerandClaude Opus 4.5 ba195e401a fix: reduce Tatlock's excessive apologizing
Build and Push / build (release) Successful in 53s
Strengthened personality prompt to prevent unnecessary apologies after
successful Librarian delegations. Added explicit "do NOT apologize"
instructions to both system prompt and synthesis prompt.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 17:52:19 +01:00
jpmschweitzerandClaude Opus 4.5 3ec4f402fa chore: release v1.10.0
Build and Push / build (release) Successful in 1m2s
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 10:34:12 +01:00
jpmschweitzerandClaude Opus 4.5 aa16fe4ffd chore: release v1.9.0
Build and Push / build (release) Successful in 1m37s
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 21:00:01 +01:00
jpmschweitzerandClaude Opus 4.5 363ab378af feat: optimize Housekeeper for Mistral-Nemo tool calling
- Rewrite system prompt with negative constraints and step-by-step process
- Set temperature to 0.1 for deterministic tool calling
- Sort room groups to top of device list (address positional bias)
- Add [ROOM GROUP] marker in list_devices output
- Update tool docstrings with explicit entity_id= parameter examples
- Add optimization findings doc (experiment log: 0% → 100% success)
- Add test script for room group detection regression testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 20:58:39 +01:00
jpmschweitzerandClaude Opus 4.5 e5d50dda77 fix: housekeeper API paths and entity hallucination prevention
Build and Push / build (release) Successful in 56s
- Update all client endpoints to use /housekeeping/ prefix
- Add critical rule requiring list_devices() before control actions
- Add housekeeping API spec documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 20:43:46 +01:00
jpmschweitzerandClaude Opus 4.5 583c407edd fix: Redis bool storage, tool tracking matching, e2e fixture scope
Build and Push / build (release) Successful in 53s
- Convert booleans to strings for Redis hset (Redis doesn't accept bool)
- Extract capability from delegate_to_X tool names for tracking
- Use loop_scope="module" for pytest-asyncio module-scoped fixtures
- Add note about using venv for tests in AGENTS.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 14:53:51 +01:00
jpmschweitzerandClaude Opus 4.5 9980e4764c fix: remove <think> wrappers from think messages
Build and Push / build (release) Successful in 1m49s
Messages in reasoning_content should be plain text, not wrapped
in <think> tags. Removed wrappers from:
- delegation.py household think messages
- orchestration.py status messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 09:12:17 +01:00
jpmschweitzerandClaude Opus 4.5 4907798e74 fix: use reasoning_content for Open WebUI streaming
Build and Push / build (release) Successful in 51s
Use DeepSeek R1 format (reasoning_content field) instead of <think>
tags in content. Open WebUI now renders thinking as proper
collapsible blocks instead of broken escaped HTML.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 00:56:45 +01:00
jpmschweitzerandClaude Opus 4.5 fb54887c03 fix: handle HybridRAG keywords schema change
Build and Push / build (release) Successful in 52s
library-desk now returns keywords as dict with core_keywords field.
Client now handles both list and dict formats for backwards compat.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 00:32:36 +01:00
jpmschweitzerandClaude Opus 4.5 d5e5fc1ad8 fix: Ollama message sanitization and streaming think slugs
Build and Push / build (release) Successful in 52s
- Fix `invalid message content type: <nil>` error from Ollama
- Create TatlockOllamaProvider that sanitizes messages (null → "")
- Update all agents to use sanitized provider
- Fix repeating think messages by adding ReasoningSummaryDone signal

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 00:19:03 +01:00
jpmschweitzerandClaude Opus 4.5 74f47097c2 fix: complete web search integration with query enrichment
Build and Push / build (release) Successful in 52s
Fixes several issues with the web search migration to Librarian:

- Update Steward routing guidelines for web search/weather → Librarian
- Register search_web, read_url, read_urls_batch tools with Librarian agent
- Update Librarian system prompt with web search documentation
- Fix query enrichment not being passed to delegations (location context)
- Add URL reading keywords to RESEARCH action type detection

Weather queries now automatically include user's stored location from
the Biographer, enabling location-aware search results.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 22:51:18 +01:00
jpmschweitzerandClaude Opus 4.5 add9b74207 chore: bump version to 1.7.0
Build and Push / build (release) Successful in 53s
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 18:31:31 +01:00
jpmschweitzerandClaude Opus 4.5 100ebeae52 feat: migrate web search from tatlock_core to Librarian
Move web search functionality to The Librarian agent, integrating with
the library-desk /rag/search endpoint for enhanced search capabilities.

Changes:
- Add search_web, read_url, read_urls_batch tools to Librarian
- Add WebSearchResult, ContentExtractionResult models to client
- Add search_web, extract_content, extract_content_batch client methods
- Update Librarian capability with web/url/internet domains
- Remove search_web from tatlock_core tools and toolset
- Update Tatlock system prompt to delegate web search to Librarian
- Add comprehensive unit tests for new Librarian tools
- Clean up legacy src/agents/tools.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 18:30:16 +01:00
jpmschweitzerandClaude Opus 4.5 49f0da8068 feat: two-phase execution, think slugs, query enrichment (v1.6.0)
Build and Push / build (release) Successful in 1m14s
Two-Phase Tatlock Execution:
- orchestrate_tool_calls() for Phase 1 coordination
- synthesize_from_results() for Phase 2 butler-toned synthesis
- Guarantees butler personality in all responses

Automatic Think Slugs:
- Deterministic butler-perspective messages during expert delegation
- ActionType enum: RETRIEVE, RESEARCH, CREATE, CONTROL, RECORD
- HOUSEHOLD_THINK_MESSAGES mapping for all experts
- Streaming delegation wrappers with automatic think messages

Steward Query Enrichment:
- Auto-fill user context (location, timezone) when not specified
- _build_enriched_query() with regex word boundary matching
- enriched_query field in StewardRecommendation schema

Documentation:
- ORCHESTRATION_SCENARIOS.md rewritten with Mermaid diagrams
- New Housekeeper and Biographer scenarios
- TESTING_IMPROVEMENTS.md for future LLM testing patterns

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 14:00:32 +01:00
jpmschweitzerandClaude Opus 4.5 a1b8fe46e8 feat: add The Housekeeper agent for home automation
Implements The Housekeeper, a new expert agent for home automation
following the Librarian pattern. Communicates with core-api service
which wraps Home Assistant REST API.

New agent features:
- CoreAPIClient with 13 home automation methods
- 13 tools: list_areas, list_devices, get_device_state, turn_on,
  turn_off, toggle, list_scenes, activate_scene, list_scripts,
  run_script, list_automations, toggle_automation, get_history
- PydanticAI agent with butler-friendly system prompt
- HouseholdCapability registration for Steward coordination
- delegate_to_housekeeper() wrapper for orchestration

Also includes:
- Dev port changed from 8123 to 8777 (avoids Home Assistant conflict)
- Config: CORE_API_HOST, CORE_API_KEY, CORE_API_TIMEOUT
- 44 unit tests for client and capability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 10:24:35 +01:00
jpmschweitzerandClaude Opus 4.5 64cad4500a feat: environment-aware config, direct delegation, E2E test suite (v1.4.0)
Build and Push / build (release) Successful in 52s
### Added
- Environment-aware configuration:
  - Auto-selected logging (DEBUG for dev, WARNING for prod)
  - Auto-selected default user (llm_tester for dev isolation)
  - User context logging at request entry
- Direct delegation bypass:
  - Pure memory/librarian requests skip Tatlock LLM
  - Reduces latency for memory-only requests
- Text-based delegation fallback:
  - Parse [DELEGATE:agent] patterns from LLM output
  - Sequential and parallel execution support
- Comprehensive E2E test suite:
  - 22 orchestration tests with QdrantVerifier
  - assert_llm_behavior() for flexible pattern matching
  - Tests for memory, delegation, isolation, scenarios

### Fixed
- Unit test mocks for streaming (async generator)
- Temporal context handling in tests
- LLM non-determinism with pytest.xfail()
- Streaming test timeouts increased

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 21:19:47 +01:00
jpmschweitzerandClaude Opus 4.5 9d7ce399c8 fix(memory): biographer tool type hints for Ollama (v1.3.2)
Build and Push / build (release) Successful in 51s
- Change `str | None` to `str` with empty default for memory_type
- Remove `keywords` parameter from store_insight (auto-generated anyway)
- Ollama's OpenAI API doesn't handle union types with None properly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 15:04:10 +01:00
jpmschweitzerandClaude Opus 4.5 8e38a568ef fix(memory): add biographer to delegation wrappers (v1.3.1)
Build and Push / build (release) Successful in 50s
- Add delegate_to_biographer to household registry delegation map
- Was returning raw tools which caused Ollama "invalid message content type: nil"
- Add Qdrant host/port to .env.example

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 14:56:32 +01:00
jpmschweitzerandClaude Opus 4.5 40663511b4 feat: memory system fixes and Redis config cleanup (v1.3.0)
Build and Push / build (release) Successful in 26s
- Fix Qdrant client to use query_points API (qdrant-client >= 1.10)
- Rename REDIS_DB to REDIS_BENCHMARK_DB for clarity
- Update Redis defaults to match stack allocation (benchmark=6, memory=1)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 14:36:56 +01:00
jpmschweitzerandClaude Opus 4.5 d207594e3c fix(deps): add missing pydantic-settings dependency
Build and Push / build (release) Successful in 50s
pydantic-ai-slim doesn't include pydantic-settings as a transitive
dependency like the full pydantic-ai package did.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 13:57:33 +01:00
jpmschweitzerandClaude Opus 4.5 523c5c43a0 feat(ci): trigger Watchtower update after image push
Build and Push / build (release) Successful in 1m56s
Automatically notify Watchtower to pull and deploy the new image
after a successful registry push.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 13:01:59 +01:00
jpmschweitzerandClaude Opus 4.5 822cdc9bf4 fix(ci): upgrade to build-push-action@v6, disable sbom
- Upgrade docker/build-push-action from v5 to v6
- Add sbom: false alongside provenance: false
- Update registry URL to internal domain

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 11:42:37 +01:00
jpmschweitzerandClaude Opus 4.5 acdde99a5c fix(ci): disable provenance for Gitea registry compatibility
Build and Push / build (release) Failing after 1m1s
Add provenance: false to docker/build-push-action to fix
"received unexpected HTTP status: 200 OK" error when pushing
to Gitea container registry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 21:13:16 +01:00
jpmschweitzerandClaude Opus 4.5 4e6f1da4f3 chore: slim dependencies with pydantic-ai-slim[openai]
Build and Push / build (release) Failing after 1m3s
- Switch from pydantic-ai to pydantic-ai-slim[openai]
- Removes unused provider SDKs (anthropic, boto3, cohere, google, groq, huggingface)
- Production packages: 53 (down from ~158)
- Production footprint: 178MB
- Add DEPENDENCY_SLIM.md with rollback instructions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 21:02:09 +01:00
jpmschweitzerandClaude Opus 4.5 7426dd1ac3 feat: add Phase F.2 - The Biographer (memory agent)
Add The Biographer household member for user memory management:

Memory Service (direct access layer):
- src/core/memory_service.py for fast, LLM-free lookups
- Profile, preference, and fact management
- Session context with Redis caching
- Steward integration via prefetch_context()

The Biographer Agent:
- src/agents/biographer/ package with PydanticAI agent
- Discreet chronicler personality for privacy
- Tools: recall_semantic, list_memories, store_insight,
  update_profile, update_preference, forget_memory
- Registered with Household Registry on startup

Steward Integration:
- Memory context pre-fetch during analysis
- Profile/preferences included in Butler note
- Keyword-based context determination

Also includes:
- delegate_to_biographer() wrapper
- 34 new tests (capability + memory service)
- Version bump to 1.2.0

Documentation cleanup:
- Removed obsolete PHASE2_COMPLETE.md, PHASE2_PLAN.md
- Removed docs/library-desk-requirements.md
- Moved ORCHESTRATION_SCENARIOS.md to project root

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 19:20:18 +01:00