fix(free-tier): a setup chat turn does not start the sign-in offer clock

The setup chat's last turn (the fork answer and the handoff) finished clean
on the free tier, so it was recorded as the first task. The offer then came
due three minutes after setup ended, which lands in the middle of the first
real task when that task runs longer than three minutes. Seen live on a
Windows dev build: first_task_at was the setup chat's end, not the task's.
Turns in the setup profile's sessions are no longer tasks, as the offer
module already intended ("normally the task setup hands off to").
This commit is contained in:
alt-glitch
2026-10-07 20:24:09 +05:30
parent e4a4f1b4f7
commit 392d0170da
2 changed files with 24 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ import pytest
import tui_gateway.server as server
from hermes_cli import anon_auth, free_tier_offer
from hermes_cli.profiles import SETUP_PROFILE_MARKER
from tui_gateway.free_tier_task_done import note_task_done
CLEAN = {"completed": True, "final_response": "Here is your plan.", "user_intervened": False}
@@ -56,6 +57,17 @@ def test_disqualified_turns_record_nothing(result, anonymous, display_kind, user
assert not _recorded()
def test_a_setup_chat_turn_is_not_a_task(tmp_path):
"""The setup chat's turns (its last one ends with the handoff) do not start the offer clock: it would
otherwise come due three minutes into the first real task."""
setup_home = tmp_path / "home" / "profiles" / "hermes-setup"
setup_home.mkdir(parents=True)
(setup_home / SETUP_PROFILE_MARKER).write_text("{}", encoding="utf-8")
session = _session(profile_home=str(setup_home))
note_task_done(session, dict(CLEAN), session["agent"], None)
assert not _recorded()
@pytest.mark.parametrize("method,params", [
("session.steer", {"text": "also check my calendar"}),
("session.redirect", {"text": "actually only Monday"}),

View File

@@ -27,9 +27,21 @@ def is_clean_task(result: Any, agent: Any, *, user_input: bool, display_kind: st
return is_anonymous_agent(agent)
def _in_setup_profile(session: dict) -> bool:
# The setup chat is not a task: counting its last turn made the offer come due during the first real task.
from pathlib import Path
from hermes_cli.profiles import SETUP_PROFILE_MARKER
from hermes_constants import get_hermes_home
home = session.get("profile_home")
return ((Path(home) if home else get_hermes_home()) / SETUP_PROFILE_MARKER).is_file()
def note_task_done(session: dict, result: Any, agent: Any, display_kind: str | None) -> None:
"""Record a clean free-tier task for the sign-in offer. Never fails the turn."""
try:
if _in_setup_profile(session):
return
if is_clean_task(result, agent, user_input=bool(session.get("_turn_user_input")), display_kind=display_kind):
from hermes_cli.free_tier_offer import record_task_done
record_task_done()