fix(agent): stop cron and subagent runs auto-titling their sessions

The turn prologue titles every session, and it is shared by every agent —
including the ones no person is reading. A cron job already names its own
session after the job in its finally block, so the titler spent a side-LLM
call per fire to write the delivery scaffolding over it for the length of
the run. A delegated child's session is hidden from every picker, so a
batch at max_concurrent_children paid N title calls for N names nobody
opens.

Both are the same class of run that already sets skip_memory to stay off
the auxiliary path, so keep the titler off it too.
This commit is contained in:
Brooklyn Nicholson
2026-08-09 03:42:00 -05:00
parent c143ec7f0c
commit cedc933c1f
2 changed files with 54 additions and 5 deletions

View File

@@ -170,18 +170,36 @@ def append_notes_to_multimodal_content(content: Any, notes: str) -> bool:
return False
# Surfaces whose sessions must not be auto-titled. The prologue is shared by
# EVERY agent, not only the ones a human is watching, so membership here is what
# keeps the titler off machine-driven runs:
#
# - cron — the scheduler names its own session after the job in its `finally`
# block, and the opener is the cron delivery hint, not a user's request.
# Titling it writes that scaffolding as the visible name for the whole run and
# bills a side-LLM call per fire, against the same job that sets
# `skip_memory` / `skip_background_review` to avoid exactly that.
# - subagent — a delegated child's session is hidden from every picker, so its
# title is never read. A batch at `max_concurrent_children` would pay N title
# calls for N names nobody sees.
_UNTITLED_PLATFORMS = frozenset({"cron", "subagent"})
def _maybe_title_session_at_turn_start(agent: Any, messages: List[Any]) -> None:
"""Kick off auto-titling for this session's first user message.
Called from the turn prologue, so every surface (CLI, gateway, TUI/desktop,
ACP) gets identical behavior without each one re-implementing the call.
Fully defensive: titling is cosmetic and must never break a turn.
Called from the turn prologue, so every surface a human reads (CLI, gateway,
TUI/desktop, ACP) gets identical behavior without each one re-implementing
the call. Fully defensive: titling is cosmetic and must never break a turn.
"""
session_db = getattr(agent, "_session_db", 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:
return
try:
from agent.message_content import flatten_message_text
from agent.title_generator import maybe_auto_title

View File

@@ -365,13 +365,44 @@ def test_between_turns_refresh_adds_late_tool_when_servers_registered():
assert any(t["function"]["name"] == "mcp_x_tool" for t in agent.tools)
class _TitlingAgent:
"""Only what ``_maybe_title_session_at_turn_start`` reads off an agent."""
def __init__(self, platform):
self.platform = platform
self.session_id = "sess-1"
self.model = "test/model"
self.provider = "openrouter"
self.base_url = "https://openrouter.ai/api/v1"
self.api_key = "sk-x"
self.api_mode = "chat_completions"
self._session_db = MagicMock()
self._session_db_created = True
def _title_turn(platform, message="Fix the login button"):
"""Run the prologue's titling step and return the maybe_auto_title mock."""
from agent import turn_context
with patch("agent.title_generator.maybe_auto_title") as titler:
turn_context._maybe_title_session_at_turn_start(
_TitlingAgent(platform),
[{"role": "user", "content": message}],
)
return titler
@pytest.mark.parametrize("platform", ["cli", "telegram", "desktop", "acp", None])
def test_prologue_titles_the_surfaces_a_person_reads(platform):
assert _title_turn(platform).called
@pytest.mark.parametrize("platform", ["cron", "CRON", "subagent"])
def test_prologue_does_not_title_machine_driven_runs(platform):
"""Cron names its own session after the job, and nobody opens a subagent's.
Both would otherwise pay a side-LLM call per run for a name that is either
overwritten or never read.
"""
assert not _title_turn(platform).called