fix(delegate): title subagent sessions after their goal without a model call
This commit is contained in:
@@ -606,6 +606,18 @@ def _persist_session_title(session_db, session_id, title, *, source, dedupe=True
|
||||
return _set(deduped)
|
||||
|
||||
|
||||
def apply_subagent_title(session_db, session_id: str, goal: str) -> Optional[str]:
|
||||
"""Title a delegate run ``Subagent: <goal's first line>`` at ``derived`` authority. No model call:
|
||||
runs fan out in bulk, and the prefix alone is what tells them apart from conversations wherever
|
||||
``sessions.show_subagents`` lists them (#97202). Collisions get ``#N``. Never raises."""
|
||||
try:
|
||||
derived = derive_title(goal) if is_titleable_user_message(goal) else None
|
||||
return _persist_session_title(session_db, session_id, f"Subagent: {derived}", source="derived") if derived else None
|
||||
except Exception:
|
||||
logger.debug("Subagent title failed for %s", session_id, exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
def apply_instant_title(
|
||||
session_db, session_id: str, user_message: str, title_callback: Optional[TitleCallback] = None,
|
||||
title_preview: str | None = None,
|
||||
|
||||
@@ -157,9 +157,9 @@ def append_notes_to_multimodal_content(content: Any, notes: Optional[str]) -> bo
|
||||
return False
|
||||
|
||||
|
||||
# Surfaces whose sessions must not be auto-titled: cron names its own session and
|
||||
# its opener is a delivery hint; subagent sessions are hidden from every picker.
|
||||
_UNTITLED_PLATFORMS = frozenset({"cron", "subagent"})
|
||||
# Cron sessions are never auto-titled: cron names its own session and its opener is a delivery hint.
|
||||
# Subagent runs get a cheap ``Subagent: <goal>`` title instead of a model call (apply_subagent_title).
|
||||
_UNTITLED_PLATFORMS = frozenset({"cron"})
|
||||
|
||||
|
||||
def _maybe_title_session_at_turn_start(agent: Any, messages: List[Any]) -> None:
|
||||
@@ -168,11 +168,12 @@ def _maybe_title_session_at_turn_start(agent: Any, messages: List[Any]) -> None:
|
||||
session_id = getattr(agent, "session_id", None)
|
||||
if not session_db or not session_id:
|
||||
return
|
||||
if str(getattr(agent, "platform", "") or "").lower() in _UNTITLED_PLATFORMS:
|
||||
platform = str(getattr(agent, "platform", "") or "").lower()
|
||||
if platform in _UNTITLED_PLATFORMS:
|
||||
return
|
||||
try:
|
||||
from agent.message_content import flatten_message_text
|
||||
from agent.title_generator import maybe_auto_title
|
||||
from agent.title_generator import apply_subagent_title, maybe_auto_title
|
||||
|
||||
# Turn's user message as text; image-only turns yield "" and are skipped.
|
||||
user_text = ""
|
||||
@@ -194,6 +195,9 @@ def _maybe_title_session_at_turn_start(agent: Any, messages: List[Any]) -> None:
|
||||
ensure()
|
||||
if not getattr(agent, "_session_db_created", False):
|
||||
return
|
||||
if platform == "subagent":
|
||||
apply_subagent_title(session_db, session_id, user_text)
|
||||
return
|
||||
# Snapshot runtime identity so the background titler can skip if the user
|
||||
# switches models before it fires.
|
||||
# ``session_id`` rides along so the background titler's OpenCode request carries the
|
||||
|
||||
@@ -506,6 +506,29 @@ def test_prologue_does_not_title_machine_driven_runs(platform):
|
||||
assert not _title_turn(platform).called
|
||||
|
||||
|
||||
def test_prologue_names_a_subagent_run_after_its_goal_without_a_model_call():
|
||||
"""A delegate run gets ``Subagent: <goal>`` at derived authority so it reads as machinery
|
||||
wherever ``sessions.show_subagents`` lists it, instead of staying untitled (#97202)."""
|
||||
from agent import turn_context
|
||||
|
||||
agent = _TitlingAgent("subagent")
|
||||
agent._session_db.set_auto_title.return_value = True
|
||||
with patch("agent.title_generator.maybe_auto_title") as titler:
|
||||
turn_context._maybe_title_session_at_turn_start(
|
||||
agent, [{"role": "user", "content": "Audit the billing module\n\nContext: ..."}])
|
||||
assert not titler.called
|
||||
agent._session_db.set_auto_title.assert_called_once_with(
|
||||
"sess-1", "Subagent: Audit the billing module", source="derived")
|
||||
|
||||
|
||||
def test_prologue_leaves_cron_runs_untitled():
|
||||
agent = _TitlingAgent("cron")
|
||||
from agent import turn_context
|
||||
|
||||
turn_context._maybe_title_session_at_turn_start(agent, [{"role": "user", "content": "Run the job"}])
|
||||
assert not agent._session_db.set_auto_title.called
|
||||
|
||||
|
||||
def test_prologue_forwards_the_submit_title_preview_to_the_titler():
|
||||
"""A paste-shrunk ``display_metadata.title_preview`` from prompt.submit is the text the
|
||||
titler should read, not the full pasted body."""
|
||||
|
||||
Reference in New Issue
Block a user