Files
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

55 lines
1.6 KiB
Python

"""
Tests for TatlockOllamaProvider configuration.
The AsyncOpenAI client must carry an explicit timeout from
config.OLLAMA_TIMEOUT instead of the SDK default (~600s), so a stuck
LLM call cannot consume the whole delegation budget.
"""
import pytest
from src.core.config import config
from src.ollama.provider import TatlockOllamaProvider, _sanitize_messages
@pytest.mark.unit
class TestProviderTimeout:
"""Timeout configuration on the underlying AsyncOpenAI client."""
def test_openai_client_timeout_from_config(self):
provider = TatlockOllamaProvider(base_url="http://localhost:11434/v1")
assert provider._openai_client.timeout == float(config.OLLAMA_TIMEOUT)
def test_timeout_is_not_sdk_default(self):
provider = TatlockOllamaProvider(base_url="http://localhost:11434/v1")
# The OpenAI SDK defaults to 600s; the configured cap must win
assert provider._openai_client.timeout < 600
@pytest.mark.unit
class TestMessageSanitization:
"""Null content sanitization for Ollama compatibility."""
def test_null_content_with_tool_calls_becomes_empty_string(self):
messages = [
{
"role": "assistant",
"content": None,
"tool_calls": [{"id": "call_1", "type": "function"}],
}
]
sanitized = _sanitize_messages(messages)
assert sanitized[0]["content"] == ""
def test_regular_messages_unchanged(self):
messages = [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Good day, sir."},
]
assert _sanitize_messages(messages) == messages