3 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 1139d8ca38 fix(provider): T-6 — the sanitized client is wired for real
The provider assigned self._openai_client, an attribute nobody reads
— OllamaProvider.client serves self._client — so the null-content
sanitizer, the wrapper signal reading and the OLLAMA_TIMEOUT cap were
all silently dead in production (sessions unaffected; they ride
ModelSettings). Found via webber's identical bug on 2026-09-13.

Three fixes travel together, because wiring alone would have traded a
silent bypass for a loud crash: the client goes through the official
openai_client constructor parameter; the parent-chat lookup survives
openai's property/cached_property descriptor change (this venv's
2.11.0 is the latter — the old hardcoded .fget would have raised
AttributeError on the first wired completion; ported from webber's
2026-08-11 fix); and the balancing/compaction signals are read from
the response body's model_extra inside create() — the httpx
event-hook approach demonstrably never fires under the openai SDK.

The tests now assert through provider.client, the property
pydantic_ai actually reads. The old ones asserted on the dead
attribute and stayed green for the entire bypass — a check whose
subject is not the real thing cannot fail for the real reason
(workspace D-24's shape). Three mutations shown to fail their tests:
the dead-attribute wiring, the .fget-only lookup, and removing the
signal read from the request path. 683 tests green; a live dev turn
through the wired client answers normally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-13 10:27:21 +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 c50f7eefcb Add comprehensive testing infrastructure
Implement test suite with 62% coverage and 12 passing tests.
Async testing support, fixtures, and SSE streaming tests.

Test Configuration (pytest.ini):
- Async mode configured
- Coverage reporting enabled
- Test markers (unit, integration)
- Warning filters
- Async fixtures with session scope

Test Fixtures (tests/conftest.py):
- TestClient for sync requests
- AsyncClient for streaming tests
- Mock request fixtures
- Shared test application instance

Core Tests (tests/core/):
- Health endpoint testing
- Root endpoint testing
- Exception handler testing
- 100% coverage of core routes

Chat Tests (tests/chat/test_router.py):
- Non-streaming completion tests
- Streaming with SSE and 20s timeout
- Temperature validation
- Message role validation
- Invalid request handling
- Comprehensive edge case coverage

Models Tests (tests/models/):
- Model listing endpoint tests
- Response format validation
- OpenAI compatibility verification

Streaming Tests:
- Proper SSE format parsing
- [DONE] marker handling
- Chunk structure verification
- 20-second timeout protection
- asyncio.wait_for() timeout handling

Test Coverage:
- Overall: 62.14%
- src/chat/: High coverage
- src/models/: High coverage
- src/core/: 100% coverage
- 12 tests passing

Following Best Practices:
- Async test support
- Fixture-based setup
- Isolated test cases
- Comprehensive assertions
- Timeout protection

Status: Production-ready test suite

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 10:52:18 +01:00