71435fa0ea
A background memory/skill review (agent/background_review.py) forks a second, complete AIAgent in a daemon thread that deliberately shares the live agent's own session_id for prompt-cache warmth. Nothing previously stopped a user's next live turn from starting while that fork was still mid-conversation, letting both stream against the same session_id and credentials concurrently. That produced two observable failures: - Doubled prompt-token accounting on the live turn's own calls (the two concurrent request/response streams under one session_id confuse the token-usage bookkeeping), triggering premature context compression. - A lockup that a normal interrupt could not clear: the review fork is a fully independent AIAgent with its own _interrupt_requested flag, and was never added to the parent's _active_children list -- the only list AIAgent.interrupt() actually walks for cross-agent cancellation -- so a live-turn Ctrl+C had no propagation path to it at all. Fix, three files: 1. agent/agent_init.py -- add _background_review_agent / _background_review_lock tracking state to every AIAgent, mirroring the existing _active_children pattern. 2. agent/background_review.py -- the review fork now registers itself on the parent's _active_children right after construction (reusing the same list/lock interrupt() already fans out to for real subagent delegation), and unregisters on every exit path (success, the tool-whitelist finally, and the outer exception safety-net). All registration is defensive (getattr/try-except) so an AIAgent built without going through agent_init.py's setup degrades to "no cross-turn cancellation" instead of aborting the whole review. 3. agent/conversation_loop.py -- at the very start of every run_conversation() turn, if a prior background review is still in-flight, it is now proactively cancelled via interrupt() before the live turn proceeds -- fire-and-forget, non-blocking, adds no latency. Adds 3 regression tests to tests/run_agent/test_background_review.py, confirmed to fail against the pre-fix code via a scripted revert. Verified: ruff clean on all touched files; 66/66 background-review and interrupt-propagation tests pass; 256/256 across turn_finalizer + run_agent regression suites; no fork-only symbols in the diff.