runLoop and context compaction
runLoop is the session’s ReAct outer loop: it decides whether this turn handles a subtask first, compacts first, or asks the model again. When context grows, the system uses compaction to create a summary message, then filterCompacted truncates older raw text before the next model call. Separately, SessionSummary does not call the model and only tallies workspace diffs — do not conflate the two.
Place on the main path
Section titled “Place on the main path”flowchart TD Prompt[SessionPrompt.prompt] --> User[createUserMessage] User --> Loop[Runner.ensureRunning] Loop --> RL[runLoop while] RL --> Next{Next action} Next --> Sub[subtask] Next --> Comp[compaction] Next --> LLM[processor + LLM]One session’s Runner ensures two runLoops do not run concurrently. See Instance boundaries and concurrency.
Priority each turn
Section titled “Priority each turn”- Read
filterCompactedhistory and find anchors (lastUser / lastAssistant / pending tasks). - If the assistant finished cleanly and no tool-call is pending, exit.
- Consume tasks (LIFO): prefer subtask, then compaction.
- If overflow prediction is true, create a compaction task and continue.
- Otherwise enter a normal model turn: resolve tools, Processor consumes the stream.
flowchart TD A[Read history + anchors] --> B{Finished?} B -->|yes| Z[Return] B -->|no| C{Has task?} C -->|subtask| S[handleSubtask] --> A C -->|compaction| P[compaction.process] --> A C -->|none| O{Overflow?} O -->|yes| N[Create compaction] --> A O -->|no| L[LLM turn] --> AWhere compaction comes from
Section titled “Where compaction comes from”| Source | Mechanism |
|---|---|
| Overflow prediction | Inside runLoop, context about to overflow → create compaction |
| Processor signal | Step end or context-overflow error → return compact → create compaction |
| Manual | Session summarize / compaction API |
| Queue | User messages that already carry a compaction Part, consumed by the outer loop |
compaction.process calls the model with a dedicated compaction role and prompt to produce a text summary (tools forbidden), then writes an assistant message with summary=true. In automatic mode it may append a synthetic user message so execution can continue. Returns continue or stop (including failure exit when context is still too large).
Working with filterCompacted
Section titled “Working with filterCompacted”flowchart LR C[compaction produces summary assistant] --> U[User message carries compaction Part] U --> F[Next turn filterCompacted] F --> V[Model-facing view shortens]The summary keeps a semantic anchor; older raw text is not expanded. Message-model side: Message model and cross-turn memory.
SessionSummary is not compaction
Section titled “SessionSummary is not compaction”On finish-step, Processor may trigger SessionSummary: tally adds/deletes and files from snapshot diffs, write session-level summary fields. It does not call an LLM and does not create a filterCompacted boundary. It is work accounting, not meeting-minutes-style compaction.
Boundaries and costs
Section titled “Boundaries and costs”- Compaction costs an extra model call and latency; on failure the outer loop may stop instead of stuffing over-limit context.
- Summary quality is bounded by the compaction prompt and model; a bad summary pollutes later turns — use session replay and human review to locate it.
- Structured output (
json_schema) can end the outer loop early; that path is independent of compaction.
Related reading: