4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
13 KiB
13 KiB
Runtime package rules
Human summary
The runtime package holds the focused support modules for the interactive
shell runtime. The top-level bootstrap and controller live one level up in
interactive_shell/.
In simple terms:
../main.pystarts the interactive session and handles process/bootstrap gates.startup/first_launch_github.pyowns the first-launch GitHub sign-in gate.../controller.pyowns theInteractiveShellControllerorchestration class, including prompt input, submitted prompt handling, queued turn consumption, prompt-mediated confirmation waits, one-turn pipeline handoff, background output draining, and shutdown.core/prompt_manager.pyowns prompt-toolkit setup and prompt rendering.input/owns prompt input event conversion: EOF, Ctrl-C, CPR cleanup, and resume hints.utils/input_policy.pyowns prompt stdin/spinner decisions for turns.startup/initial_input.pyowns non-interactive initial-input replay.background/workers.pyowns alert watching, spinner ticking, sampler startup, and turn-start background output drains.background/also owns background investigation records, launchers, and completion notification delivery.core/holds the core runtime engine:state.py— shared runtime state (ReplState,SpinnerState)turn_detection.py— pure text classifiers for cancel, confirm, and correction detection
core.agent_harness.session.tasksowns the cross-session task registry surfaced via/tasksand/cancel.- Reusable per-agent session state (
Session) lives incore.agent_harness.session. Terminal runtime context assembly (ReplRuntimeContext,create_repl_runtime_context) lives ininteractive_shell.runtime.context.
These instructions apply to interactive_shell/runtime/ and all
subdirectories. Parent AGENTS.md files still apply.
Architectural intent (locked)
The runtime package is intentionally split into focused concerns:
core/state.py— runtime state and transition helpers only.core/turn_detection.py— pure prompt text classification only.utils/input_policy.py— terminal stdin/spinner gating decisions only.agent_presentation.py— terminal presentation for the agent prompt only (agent lifecycle events, presentation-state reducer/renderer,ConsoleAgentEventSink).turn_host.py— terminal/runtime host forShellAgentprompts only.../controller.py— stable async entrypoint and async prompt runtime/event loop orchestration, submitted prompt handling, queued-turn consumption, prompt-mediated confirmation waits, turn telemetry, one-turn pipeline handoff, background output draining, and shutdown only.core/prompt_manager.py— prompt-toolkit setup and prompt rendering only.input/— prompt input event conversion and terminal-input cleanup only.background/workers.py— background worker startup and turn-start drain hooks only.core.agent_harness.session.background— background investigation record and preferences only.background/runner.py— session-local background investigation launchers only.background/notifications.py— background RCA completion notification delivery only.../main.py— process/bootstrap boundary only.startup/initial_input.py— scripted initial-input replay only.startup/first_launch_github.py— first-launch GitHub sign-in gate only.core.agent_harness.session.tasks— task registry + persistence only.core.agent_harness.accounting.token_accounting— session-scoped LLM token accounting and run metadata only.
Keep these boundaries strict. If a change crosses concerns, move code to the owner module instead of broadening module responsibilities.
Data flow contract (locked)
The interactive runtime must keep this shape:
interactive_shell.main.run_repl(synchronous entrypoint) sets up process-level concerns and callsrun_repl_async.interactive_shell.main.run_repl_async(async body) createsInteractiveShellController.InteractiveShellController.start_interactive_shellowns prompt lifecycle, submitted input handling, queued-turn consumption, and per-turn task scheduling.runtime.turn_host.run_agent_turn_queueconsumes queued prompts through an injectedrun_turncallable, which in production islambda text: run_agent_turn(self.turn_runtime, text).runtime.turn_host.run_agent_turn(runtime, text)drives one submitted turn.AgentTurnRuntimeis the immutable dependency bundle it operates on (session,state,spinner,invalidate_prompt,request_exit);run_agent_turnowns presentation setup, prompt-mediated confirmation, dispatch state, and per-turn execution.interactive_shell.runtime.shell_turn_execution.execute_shell_turnbinds shell adapters aroundcore.agent_harness.turns.orchestrator.run_turn.core.agent_harnessowns one prompt's action/answer mechanics and accounting finalization. The terminal presentation forAgentEventemissions lives inruntime/agent_presentation.py.
Do not invert this dependency direction.
Architecture diagram
flowchart TD
runRepl["interactive_shell.main.run_repl"] --> replMain["interactive_shell.main.run_repl_async"]
replMain --> controller["interactive_shell.controller.InteractiveShellController"]
controller --> turnHost["runtime.turn_host.run_agent_turn(turn_runtime, text)"]
turnHost --> turnEntry["interactive_shell.runtime.shell_turn_execution.execute_shell_turn"]
turnEntry --> coreHarness["core.agent_harness.turns.orchestrator.run_turn"]
coreHarness --> sideEffects["slash/help/agent/follow-up/investigation side effects"]
controller --> replState["core.state.ReplState"]
controller --> spinnerState["core.state.SpinnerState"]
controller --> inputReader["input.PromptInputReader"]
State ownership rules
ReplStateis the single source of truth for:- active dispatch task
- cancellation event
- confirmation event/response lifecycle
- exit requests
- the explicit turn
phase(TurnPhase:IDLE,DISPATCHING,AWAITING_CONFIRMATION,CANCELLING)
- Mutate turn state through the
ReplStatetransition methods, never by poking raw fields from other modules:start_dispatch/attach_turn_task/attach_cancel_event->DISPATCHINGbegin_confirmation->AWAITING_CONFIRMATION;clear_confirmationreturns toDISPATCHING/IDLE(and never clobbers an in-progressCANCELLING)cancel_current_dispatch->CANCELLING(only when there is something to cancel) then signals the cancel/confirm events andtask.cancelfinish_dispatch/clear_current_task->IDLE
phaseis authoritative for confirmation and cancelling.is_dispatch_running()stays derived from the asyncio task (the runtime truth of the in-flight turn);is_awaiting_confirmation()andis_cancelling()are derived fromphase.- Do not reorder the signaling inside
cancel_current_dispatchor move theconfirm_responsereset after theconfirm_eventpublish inbegin_confirmation; both orderings are load-bearing for cancellation and confirmation race-safety. SpinnerStateowns spinner rendering state only; it must not depend on runtime task management.
Turn execution rules
- Do not reintroduce
dispatch.py, anAgentTurnRunner-style wrapper class, or any compatibility-only forwarding module. - The terminal host lives in
runtime/turn_host.py:run_agent_turn(runtime, text)owns shell presentation (StreamingConsole, spinner, recorder, progress scope), constructs aConsoleAgentEventSink, owns dispatch state, and lazily imports + callsinteractive_shell.runtime.shell_turn_execution.execute_shell_turn.AgentTurnRuntimeis the immutable dependency bundle it operates on; the controller constructs it and passes a boundrun_agent_turncoroutine intorun_agent_turn_queue. - The shell adapter entry lives in
runtime/shell_turn_execution.py:execute_shell_turncomposes the action-turn (runtime/action_turn.py), gather (runtime/integration_tool_gathering.py), and answer (runtime/answer_turn.py) adapters plus accounting aroundcore.agent_harness.turns.orchestrator.run_turn. Each adapter owns its own binding; tests import them from their owning module (notshell_turn_execution). - The reusable per-prompt loop lives in
core.agent_harness: turn snapshots, observation reset, action/response routing, and core result construction stay surface-agnostic. - Keep terminal side effects (spinner, prompt suppression,
console.print, CPR drain) inConsoleAgentEventSink— defined inruntime/agent_presentation.py— not in the turn-entry adapter or the core harness. - Put cancel/confirm/correction text classifiers in
core/turn_detection.py. - Put stdin blocking and spinner decisions in
utils/input_policy.py. - Keep prompt-mediated confirmation waiting in
runtime/core/confirmation.py. - Turn accounting is consolidated behind
ShellTurnAccountingininteractive_shell/runtime/core/turn_accounting.py, invoked frominteractive_shell.runtime.shell_turn_execution.execute_shell_turn. It owns action-agent analytics, terminal-turn aggregate telemetry, prompt-recorder flush, conversational-turn persistence, and the final assistant-intent stamp.interactive_shell.runtime.action_turn.run_action_tool_turnreturns facts only (ToolCallingTurnResultwithaccounting_statusofcompleted/not_run) and emits no analytics itself. Do not re-scatter accounting back intorun_action_tool_turnor standalone_record_*helpers.
Controller rules
../controller.pyowns:InteractiveShellControllerstart_interactive_shellshell lifecycle orchestration- alert listener setup/teardown
AgentTurnRuntimeconstruction and shutdown- queued prompt submission
turn_host.pyowns:run_input_loop(module-level) — read and handle user input until exitrun_agent_turn_queue(module-level) — consume queued prompts until exit (runs an injectedrun_turn)run_agent_turn(runtime, text)(module-level) — presentation, dispatch state, prompt-mediated confirmation, and turn-entry invocation over anAgentTurnRuntimeConsoleAgentEventSink(inruntime/agent_presentation.py) — terminal presentation for agent lifecycle events over_reduce_agent_presentation/_render_agent_presentation_transition- queued turn consumption
- per-turn task lifecycle
- dispatch start/finish state transitions
- prompt-mediated confirmation waiting
- turn telemetry and
execute_shell_turninvocation - current turn cancellation helpers
- coordination between prompt, background, and shutdown helpers
core/prompt_manager.pyowns:- prompt-toolkit wiring
- prompt rendering callbacks
- pending prompt defaults and autosubmit handling
input/owns:- prompt input event types
- terminal EOF and Ctrl-C conversion
- CPR cleanup for submitted prompt text
- session resume hints when prompt input closes
background/workers.pyowns:- alert watcher lifecycle
- spinner ticker lifecycle
- sampler startup
- background notice drains at turn start
- Keep prompt rendering concerns in runtime/prompting modules, not in dispatch/execution.
Main/bootstrap rules
../main.pyowns:- startup sweep
- TTY/non-TTY gate
- banner display for interactive runs
- async boundary (
asyncio.run)
../controller.pyowns alert listener setup/teardown because the inbox is part of the running shell lifecycle.- Do not move per-turn dispatch/runtime logic back into startup bootstrap.
Compatibility surface policy
runtime/__init__.pyshould be a thin export layer.- Do not duplicate business logic in
__init__.py. runtime/__init__.pyexportsSessionfromcore.agent_harness.sessionand runtime-context helpers frominteractive_shell.runtime.context. New shared runtime code should import session names directly fromcore.agent_harness.session.- Do not re-add
_xxxunderscore aliases or wrapper functions for compatibility. Tests and callers should import canonical names from their owning submodule.
Test seam policy
- Prefer patching canonical module seams:
interactive_shell.controller.*for prompt-loop, queued-turn, confirmation behavior, one-turn pipeline execution, and side effectsinteractive_shell.main.*for process/bootstrap behaviorruntime.core.state.*for state-specific behavior
- Avoid adding new tests that monkeypatch package-root internals in
runtime.__init__unless there is no stable canonical seam.
Refactor guardrails
- No behavior changes to action-planning policy should be introduced from
runtime/refactors. - Keep interruption semantics unchanged:
- Esc or bare cancel commands interrupt active dispatch
- cancellation moves the turn to
TurnPhase.CANCELLINGand signals both the cancel event and any pending confirmation event beforetask.cancel - confirmation prompts are cancel-safe and never silently auto-confirm; a
cancel during confirmation must not be downgraded back to
DISPATCHING
- Preserve observability semantics (turn telemetry and turn summaries).