feat: add key-free demo mode replaying recorded fixtures

This commit is contained in:
Justin Visser 2026-08-11 09:14:22 +02:00
parent 0664cc2d27
commit 401a0ddea7
21 changed files with 1040 additions and 31 deletions

View file

@ -112,7 +112,7 @@ class AnthropicRecommender:
if parsed is None:
raise RecommenderOutputError("Intent response contained no structured output")
validated = IntentOutput.model_validate(parsed.model_dump())
return _to_intent(validated)
return to_intent(validated)
async def stream_rerank(
self,
@ -125,7 +125,7 @@ class AnthropicRecommender:
) -> AsyncGenerator[RerankSelection]:
"""Yield each complete valid selection while the JSON is streaming."""
schema = transform_schema(RerankOutput.model_json_schema())
parser = _RecommendationObjectParser()
parser = RecommendationObjectParser()
async with self.client.messages.stream(
model=self.settings.llm_model,
max_tokens=self.settings.rerank_max_tokens,
@ -166,8 +166,11 @@ class AnthropicRecommender:
raise RecommenderOutputError("Rerank response returned too many selections")
class _RecommendationObjectParser:
class RecommendationObjectParser:
"""Incrementally extract complete recommendation objects from JSON text."""
def __init__(self) -> None:
"""Create an empty parser for one rerank response."""
self.complete_text = ""
self._scan_index = 0
self._object_start: int | None = None
@ -177,6 +180,7 @@ class _RecommendationObjectParser:
self._has_found_array = False
def feed(self, text_delta: str) -> list[RerankSelectionOutput]:
"""Consume a text delta and return newly completed selections."""
self.complete_text += text_delta
if not self._has_found_array:
match = _RECOMMENDATION_ARRAY.search(self.complete_text)
@ -231,7 +235,8 @@ class _RecommendationObjectParser:
raise RecommenderOutputError("Rerank item failed validation") from error
def _to_intent(output: IntentOutput) -> Intent:
def to_intent(output: IntentOutput) -> Intent:
"""Map validated intent output to the application domain."""
return Intent(
mood=tuple(output.mood),
activity=output.activity,