feat(core): seeds without text wait for the first turn

This commit is contained in:
hh
2026-08-28 19:03:08 +02:00
parent 38986cb82e
commit c88726db9e
3 changed files with 42 additions and 12 deletions
+34 -11
View File
@@ -38,7 +38,7 @@ from claude_agent_sdk import (
from sqlmodel import col, select
from beaver_gateway.core.injects import InjectQueue, inject_header
from beaver_gateway.core.kinds import KINDS, Kind
from beaver_gateway.core.kinds import KINDS, Kind, as_kind
from beaver_gateway.core.transcript import (
messages_from_entries,
render_messages,
@@ -492,7 +492,9 @@ class Conversations:
``binding`` = ``(frontend, external_id)`` puts it into a window that
already exists (a topic the user created) instead of asking the
home frontend to ``materialize`` one. ``text`` rides with the seed
as the first thing the user said, whatever the seed mode.
as the first thing the user said, whatever the seed mode; without
it the seed waits in ``flags`` and opens the first turn, so a fresh
window stays silent and costs nothing until someone speaks.
"""
if seed not in SEEDS:
msg = f"unknown seed {seed!r}"
@@ -526,21 +528,41 @@ class Conversations:
await self.bind(conv, frontend=binding[0], external_id=binding[1])
else:
await self.materialize(conv)
prompt = await self._seed_text(
SeedContext(
kind=kind, seed=seed, agent=agent, parent=parent, text=text, title=title
),
window=window,
ctx = SeedContext(
kind=kind, seed=seed, agent=agent, parent=parent, text=text, title=title
)
if text is None:
return await self.set_flags(conv, {"seed": seed, "seed_window": window})
await self._queue.push(
conversation_id=cast("int", conv.id),
priority="user",
origin=origin if text and seed != "brief" else f"сид:{seed}",
text=prompt,
origin=f"сид:{seed}" if seed == "brief" else origin,
text=await self._seed_text(ctx, window=window),
)
self._ensure_worker(cast("int", conv.id))
return conv
async def _pending_seed(self, conv: Conversation) -> str | None:
"""A seed nobody has spoken after yet: rendered now, spent once."""
seed = conv.flags.get("seed")
if not seed:
return None
parent = await self.get_row(conv.parent_id) if conv.parent_id else None
ctx = SeedContext(
kind=as_kind(conv.kind),
seed=str(seed),
agent=conv.agent_name,
parent=parent,
text=None,
title=conv.title,
)
window = conv.flags.get("seed_window")
text = await self._seed_text(
ctx, window=window if isinstance(window, int) else None
)
await self.set_flags(conv, {"seed": None, "seed_window": None})
return text
async def fork(
self,
conv: Conversation,
@@ -983,8 +1005,6 @@ class Conversations:
stamp = datetime.now(UTC).astimezone().strftime("%Y-%m-%d %H:%M")
title = f" «{ctx.title}»" if ctx.title else ""
head = f"[сид: {ctx.seed}] {ctx.kind}{title}, {stamp}."
if not ctx.text or ctx.seed == "brief":
head += " Это контекст, не обращение: отвечать не нужно."
body: str | None = None
if self._texts.seed is not None:
produced: Any = self._texts.seed(ctx)
@@ -1065,6 +1085,9 @@ class Conversations:
else:
origin = "inject"
prompt = "\n\n".join(f"{inject_header(i.origin)}\n{i.text}" for i in batch)
seed = await self._pending_seed(conv)
if seed:
prompt = f"{seed}\n\n{prompt}"
try:
text, capture = await self.run_text_turn(
conv, prompt, origin=origin, turn_id=turn_id, item_origin=head.origin