ulysses/static
Kenny Van de Maele 64d65b73c1
feat: round-limit handling — Continue affordance at the cap + configurable cap (#1999)
* feat: round-limit handling — Continue affordance at the cap + configurable cap

When the agent loop runs out of rounds (per-message step cap, default 20)
while still actively using tools, it stopped silently mid-task. Now:

1. The loop emits a `rounds_exhausted` SSE event at the cap, and the UI shows
   a "Continue" pill at the bottom of the chat that resumes the task from where
   it left off. Repeated cap-hits each get a fresh Continue (multiple continues
   in a row).
2. The cap is configurable in Settings → Agent ("Max steps per message"),
   validated on the client, at the save endpoint, and at the read site.

- src/agent_loop.py: track `_exhausted_rounds` (set only when a full
  tool-executing round completes on the last allowed round — i.e. the agent
  wanted to keep going); emit `{"type":"rounds_exhausted","rounds":N}` (logged).
- routes/chat_routes.py: read `agent_max_rounds` (clamped 1..200), pass as
  `max_rounds`; forward the new event through the SSE relay.
- routes/auth_routes.py: validate numeric settings on save (int + clamp;
  agent_max_rounds 1..200, agent_max_tool_calls 0..1000; 400 on non-int).
- src/settings.py: default `agent_max_rounds = 20`.
- static/: Settings input + client-side clamp; the Continue pill (reuses the
  existing .stopped-indicator / .continue-btn classes and theme vars
  --border/--fg/--bg/--accent); appended to the chat container so it survives
  the message re-render at stream finalize. chat.js cache version bumped.

* test: cover rounds_exhausted emission (cap-hit vs normal finish)

Drives the real stream_agent_loop with mocked LLM stream / tool exec / settings:
a tool block every round exhausts the cap and must emit rounds_exhausted; a
plain answer hits the done-break and must not. Guards the for/else logic.
2026-06-04 22:36:05 +02:00
..
fonts Odysseus v1.0 2026-05-31 23:58:26 +09:00
js feat: round-limit handling — Continue affordance at the cap + configurable cap (#1999) 2026-06-04 22:36:05 +02:00
lib Odysseus v1.0 2026-05-31 23:58:26 +09:00
app.js fix(ui): modal drag + removed startDrag func (#2430) 2026-06-04 20:34:18 +02:00
index.html feat: round-limit handling — Continue affordance at the cap + configurable cap (#1999) 2026-06-04 22:36:05 +02:00
login.html fix(login): keep inputs >=16px on touch so iOS doesn't zoom on focus (#1632) 2026-06-03 14:23:24 +09:00
manifest.json Odysseus v1.0 2026-05-31 23:58:26 +09:00
style.css feat: round-limit handling — Continue affordance at the cap + configurable cap (#1999) 2026-06-04 22:36:05 +02:00
sw.js fix(ui): modal drag + removed startDrag func (#2430) 2026-06-04 20:34:18 +02:00