feat(commands): /background, /btw slash commands + undo button + reasoning chip

Rebased onto master after #931 (aux title routing) to resolve streaming.py conflict.
All changes from both PRs are cleanly integrated.

2088 tests passing (2065 master + 23 from #931).

Co-authored-by: bergeouss <bergeouss@gmail.com>
This commit is contained in:
nesquena-hermes
2026-04-24 01:24:51 +00:00
parent 57222c70e7
commit 9c69b646ff
10 changed files with 568 additions and 12 deletions

View File

@@ -866,8 +866,12 @@ def _sse(handler, event, data):
handler.wfile.flush()
def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, attachments=None):
"""Run agent in background thread, writing SSE events to STREAMS[stream_id]."""
def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, attachments=None, *, ephemeral=False):
"""Run agent in background thread, writing SSE events to STREAMS[stream_id].
When ephemeral=True, session mutations are skipped — used by /btw to get
a streaming answer without persisting to the parent session.
"""
q = STREAMS.get(stream_id)
if q is None:
return
@@ -1336,6 +1340,27 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
task_id=session_id,
persist_user_message=msg_text,
)
# ── Ephemeral mode (/btw): deliver answer, skip persistence, cleanup ──
if ephemeral:
_answer = ''
for _m in reversed(result.get('messages') or []):
if isinstance(_m, dict) and _m.get('role') == 'assistant':
_answer = str(_m.get('content', ''))
break
put('done', {
'session': {'session_id': session_id, 'messages': result.get('messages', [])},
'usage': {'input_tokens': 0, 'output_tokens': 0},
'ephemeral': True,
'answer': _answer,
})
if _checkpoint_stop is not None:
_checkpoint_stop.set()
try:
import pathlib
pathlib.Path(s.path).unlink(missing_ok=True)
except Exception:
pass
return # skip all normal persistence for ephemeral sessions
if _checkpoint_stop is not None:
_checkpoint_stop.set()
if _ckpt_thread is not None: