Session Context#
session_context is the unified per-turn context manager. It populates the ContextVars (_store / _current_turn_id / _current_runtime / _call_id) so that capabilities such as feeding docstrings into the prompt, DAG persistence, and ask_user tracking take effect across all entry points.
Interface#
@contextmanager
def session_context(
session_id: str | None = None,
*,
agent_id: str = "main",
turn_id: str | None = None,
runtime=None,
create_runtime_if_none: bool = True,
):
db = default_db()
sid = session_id or ("adhoc_" + _short_uuid())
if db.get_session(sid) is None:
db.create_session(sid, agent_id, source="cli")
rt = runtime
if rt is None and create_runtime_if_none:
rt = create_runtime()
tid = turn_id or ("turn_" + _short_uuid())
tokens = []
tokens.append(("_store", _store.set(SessionNodeWriter(db, sid))))
tokens.append(("_turn", _current_turn_id.set(tid)))
if rt is not None:
tokens.append(("_rt", _current_runtime.set(rt)))
try:
yield SessionHandle(db=db, session_id=sid, runtime=rt, turn_id=tid)
finally:
for _name, tok in reversed(tokens):
tok.var.reset(tok)
When the session does not exist, session_context calls create_session — this is one of the creation entry points described in operations.md.
Session boundaries#
Boundaries are determined by how session_id is passed, not by the number of calls.
| Caller intent | What to pass | Behavior |
|---|---|---|
| Run a new task | Do not pass session_id | Creates a new one and returns/prints the id to the caller |
| Continue the same task (2nd, 3rd call) | Pass the id returned last time | Reuses it, continuing the history |
| Start something unrelated | Do not pass one (or pass a different id) | A separate, new session |
CLI equivalent: the first run without --session prints a new id; --session <id> continues.
Ending a session#
A session does not need to be explicitly "ended" — it is an append-only git history. You write until you stop, and the next time you come back with the same id, you keep writing. Exiting session_context only resets the ContextVars; it does not delete the session.
Usage at each entry point#
| Entry point | Usage |
|---|---|
| dispatcher | with session_context(req.session_id, ...) replaces the existing inline set/reset |
| research harness | with session_context(session_id="research_" + uuid, runtime=rt) wraps research_agent |
| process_runner | The same manager replaces the hand-copied set/reset |
| tests | Same as above |