feat: [api] Various changes to get the adventure possible choice feature working

This commit is contained in:
wilson 2026-05-06 22:42:01 +01:00
parent e40574ae9d
commit 461473d379
4 changed files with 32 additions and 6 deletions

View file

@ -144,6 +144,7 @@ class AdventureService:
self,
adventure_id: uuid.UUID,
entry_id: uuid.UUID,
user_id: uuid.UUID,
) -> None:
"""Full entry generation pipeline. Called from the worker queue.
@ -157,6 +158,7 @@ class AdventureService:
assert adventure is not None, f"Adventure {adventure_id} not found"
all_entries = await self.entry_repo.list_for_adventure(adventure_id)
all_decisions = [await self.decision_repo.get_for_entry_and_user(entry_id=uuid.UUID(e.id), user_id=user_id) for e in all_entries]
current_entry = next(e for e in all_entries if e.id == str(entry_id))
is_first_entry = current_entry.entry_index == 0
is_final_entry = current_entry.entry_index + 1 == adventure.max_entry_count
@ -184,6 +186,7 @@ class AdventureService:
vibes=adventure.vibes,
protagonist=adventure.protagonist,
prior_entries=prior_entries,
prior_decisions=all_decisions,
)
raw_text, usage_dict = await self.anthropic_client.complete(
@ -192,7 +195,7 @@ class AdventureService:
max_tokens=2048,
)
story_text, choices_parsed, gm_notes, story_so_far = parse_entry_response(raw_text)
story_text, choices_parsed, gm_notes = parse_entry_response(raw_text)
await self.entry_repo.update_content(
entry_id=entry_id,

View file

@ -96,6 +96,7 @@ def build_conversation_messages(
vibes: list[str],
protagonist: list[str],
prior_entries: list[tuple[AdventureEntry, list[AdventureEntryPossibleChoice], str | None]],
prior_decisions: list[AdventureEntryPossibleChoice | None],
) -> list[dict]:
"""Build the full messages array for an Anthropic API call.
@ -110,8 +111,22 @@ def build_conversation_messages(
messages.append(
{"role": "assistant", "content": reconstruct_assistant_message(entry, choices)}
)
if chosen_label is not None:
messages.append({"role": "user", "content": chosen_label})
# Find the player's decision for this entry
choice_ids = [c.id for c in choices]
decision_for_entry = next(
(d for d in prior_decisions if d and d.choice_id in choice_ids),
None
)
# If a decision exists, append the player's chosen option
if decision_for_entry:
chosen_option = next(
(c for c in choices if c.id == decision_for_entry.choice_id),
None
)
if chosen_option:
messages.append({"role": "user", "content": chosen_option.label})
return messages

View file

@ -120,10 +120,10 @@ def _make_service(db: AsyncSession) -> AdventureService:
async def _run_entry_pipeline_task(
adventure_id: uuid.UUID, entry_id: uuid.UUID
adventure_id: uuid.UUID, entry_id: uuid.UUID, user_id: uuid.UUID
) -> None:
async with AsyncSessionLocal() as db:
await _make_service(db).run_entry_pipeline(adventure_id, entry_id)
await _make_service(db).run_entry_pipeline(adventure_id, entry_id, user_id)
# ---------------------------------------------------------------------------
@ -289,7 +289,7 @@ async def create_adventure(
)
await worker.enqueue(
partial(
_run_entry_pipeline_task, uuid.UUID(adventure.id), uuid.UUID(first_entry.id)
_run_entry_pipeline_task, uuid.UUID(adventure.id), uuid.UUID(first_entry.id), user_id
)
)
return _to_adventure_response(adventure)
@ -375,6 +375,7 @@ async def record_decision(
_run_entry_pipeline_task,
uuid.UUID(next_entry.adventure_id),
uuid.UUID(next_entry.id),
user_id,
)
)
return DecisionResponse(

View file

@ -28,6 +28,7 @@ class AdventureChoiceItem(BaseModel):
class AdventureEntryItem(BaseModel):
id: str
adventure_id: str
possible_choices: list[AdventureChoiceItem] | None
generated_from_choice_id: str | None
status: str
entry_index: int
@ -81,6 +82,7 @@ async def get_adventure(
entries = await PostgresAdventureEntryRepository(db).list_for_adventure(adv_id)
choices_repo = PostgresAdventureEntryChoiceRepository(db)
translation_repo = PostgresAdventureEntryTranslationRepository(db)
audio_repo = PostgresAdventureEntryAudioRepository(db)
@ -93,10 +95,15 @@ async def get_adventure(
target_language=adventure.source_language,
)
audio = await audio_repo.get_for_entry(entry_id=eid, component_type="story_text")
choices = await choices_repo.list_for_entry(eid)
entry_items.append(
AdventureEntryItem(
id=entry.id,
adventure_id=entry.adventure_id,
possible_choices=[
AdventureChoiceItem(id=c.id, index=c.index, label=c.label, text=c.text)
for c in choices ]
if choices else None,
generated_from_choice_id=entry.generated_from_choice_id,
status=entry.status,
entry_index=entry.entry_index,