Module: Silas::SubprocessRunner
- Defined in:
- lib/silas/subprocess_runner.rb
Overview
The engine-owned analog of StepRunner: it wraps one whole subprocess run in a single anchor Step and persists the durable result. Replay-aware and fail-closed — a resumed run whose subprocess got far enough to register a CLI session but did not finish is FAILED rather than re-spawned, because an engine-owned subprocess can't be replayed exactly-once (design risk #1).
Class Method Summary collapse
-
.call(turn) ⇒ Object
Returns :terminal or :failed.
- .engine_context(turn, step) ⇒ Object
Class Method Details
.call(turn) ⇒ Object
Returns :terminal or :failed.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/silas/subprocess_runner.rb', line 11 def call(turn) step = Step.find_or_create_by!(turn: turn, index: 0) return :terminal if step.completed? if turn.cli_session_id.present? # A prior execution spawned a subprocess that never completed the step. turn.finish!(:failed, reason: "agent_sdk_interrupted") return :failed end result = Silas.resolved_engine.execute_step(engine_context(turn, step)) step.update!( status: "completed", terminal: true, response_blocks: result.blocks, stop_reason: result.stop_reason, model: Silas.agent.model, input_tokens: result.usage&.dig(:input_tokens), output_tokens: result.usage&.dig(:output_tokens) ) :terminal end |
.engine_context(turn, step) ⇒ Object
32 33 34 35 36 37 38 39 |
# File 'lib/silas/subprocess_runner.rb', line 32 def engine_context(turn, step) { turn: turn, step: step, index: 0, system: turn.instructions_snapshot, messages: MessageBuilder.call(turn, upto_index: nil), tools: Silas.tool_definitions, model: Silas.agent.model, limits: { max_steps: Silas.agent.max_steps } } end |