feat(runtime): session-setup hook (register_session_setup)#781
feat(runtime): session-setup hook (register_session_setup)#781seanturner83 wants to merge 2 commits into
Conversation
Adds an extension point that runs a callback once per scan, right after the
sandbox session is ready and before the agent's first turn, with the live
session and the scan config:
from strix.runtime.session_manager import register_session_setup
async def prepare(session, scan_config):
await session.exec(...) # set up in-sandbox state the agent will use
register_session_setup(prepare)
Mirrors backends.register_backend / agents.factory.register_agent_tools. The
gap it fills: a @function_tool runs runner-side and only receives a
RunContextWrapper, never the sandbox session — so setup that must session.exec
inside the container (build an index, warm a cache, install a probe) has no
seam to hook. run_strix_scan invokes the callbacks after create_or_reuse and
before building the root agent.
Best-effort by contract: callbacks are awaited in registration order, and an
exception in one is logged and swallowed so an optional setup step can never
fail the scan. Duplicate registrations are ignored.
Motivating consumer: a SCIP code-graph addon that indexes the freshly
materialised target in-sandbox and copies the index out for its query tools —
but the hook is generic (cache warming, sidecar probes, etc.).
Tests: registration order, session/config passthrough, dedup, failure-is-
swallowed, empty-registry no-op.
Greptile SummaryThis PR adds a session-setup extension point before agent execution. The main changes are:
Confidence Score: 4/5The cached-session resume path can repeat non-idempotent setup and needs a fix before merging.
strix/core/runner.py Important Files Changed
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
strix/core/runner.py:218
**Resume Repeats Session Setup**
When a scan resumes in the same process, `create_or_reuse` returns its cached sandbox and this unconditional call runs every setup callback against that already-prepared session. Non-idempotent hooks can start duplicate services, append configuration twice, or fail after partial changes; the swallowed exception then lets the resumed agent continue with invalid sandbox state. Track setup completion with the cached session so each materialized session is prepared only once.
Reviews (1): Last reviewed commit: "feat(runtime): session-setup hook (regis..." | Re-trigger Greptile |
| # the target is materialised, but before the agent's first turn — the | ||
| # window an addon needs to prepare in-sandbox state (e.g. a code-graph | ||
| # index). Best-effort: a hook failure is logged, never fatal. | ||
| await session_manager.run_session_setups(bundle["session"], scan_config) |
There was a problem hiding this comment.
When a scan resumes in the same process, create_or_reuse returns its cached sandbox and this unconditional call runs every setup callback against that already-prepared session. Non-idempotent hooks can start duplicate services, append configuration twice, or fail after partial changes; the swallowed exception then lets the resumed agent continue with invalid sandbox state. Track setup completion with the cached session so each materialized session is prepared only once.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/core/runner.py
Line: 218
Comment:
**Resume Repeats Session Setup**
When a scan resumes in the same process, `create_or_reuse` returns its cached sandbox and this unconditional call runs every setup callback against that already-prepared session. Non-idempotent hooks can start duplicate services, append configuration twice, or fail after partial changes; the swallowed exception then lets the resumed agent continue with invalid sandbox state. Track setup completion with the cached session so each materialized session is prepared only once.
How can I resolve this? If you propose a fix, please make it concise.…ile usestrix#781) create_or_reuse caches + reuses the session bundle across in-process resumes (the cred-boundary iteration loop). run_session_setups was called unconditionally, so a resume re-ran every setup callback against an already-prepared sandbox — double-applying non-idempotent hooks (start a service twice, re-append config) or failing mid-way and, since failures are swallowed, leaving the resumed agent on invalid state. Take the bundle (not the raw session) and stamp it once setups have run; skip on reuse. Stamp BEFORE running so a partial/failed setup doesn't retry-loop. A fresh session (new bundle) — including a cross-push PR resume in a new process — gets a fresh run, so setup-derived state is never stale: the reused bundle is the same container with the same materialised source. Tests: run-once-on-reuse, fresh-bundle-reruns, marked-done-even-on-failure.
|
Good catch — fixed in 33eb270.
On staleness (since setup-derived state like an index is what this is for): the reused bundle is the same container with the same materialised source, so nothing's stale — the code hasn't changed between in-process iterations. A cross-push PR resume runs in a new process against a freshly materialised sandbox → new bundle → setups re-run → the index is rebuilt against the new code. So skipping on reuse never serves a stale artifact. Added tests: run-once-on-reuse, fresh-bundle-reruns-afresh, and marked-done-even-when-a-callback-fails. |
Summary
Adds a generic extension point —
register_session_setup(callback)— that runs a coroutine once per scan, right after the sandbox session is ready and before the agent's first turn, with the live session and the scan config.It mirrors the existing
backends.register_backendandagents.factory.register_agent_toolsseams.Why
A
@function_toolruns runner-side and only receives aRunContextWrapper— never the sandbox session. So any setup that mustsession.execinside the container before the agent starts (build an index against the freshly-materialised target, warm a cache, install a probe) currently has nowhere to hook. This adds that one seam.run_strix_scaninvokes the registered callbacks aftercreate_or_reusereturns and before the root agent is built — the window where the target is materialised but analysis hasn't begun.Contract
Motivating consumer
A SCIP code-graph addon (separate) that indexes the materialised target in-sandbox and copies the index out for its runner-side query tools. But the hook is deliberately generic — cache warming, sidecar readiness probes, etc. — and adds nothing to the default path (no callbacks registered → a no-op).
Tests
tests/test_session_setup_hooks.py: registration order, session/config passthrough, dedup, failure-is-swallowed, empty-registry no-op. +142 lines acrosssession_manager.py(registry + invoker),runner.py(invocation), and the test.🤖 Generated with Claude Code