Class: Chocomint::Orchestrator
- Inherits:
-
Object
- Object
- Chocomint::Orchestrator
- Defined in:
- lib/chocomint/orchestrator.rb
Overview
ツール実行を完全制御するオーケストレータ (DESIGN §5, §6, §9)。 LLM は提案者と監査者に限定し、実行・判定・再試行・記録は Ruby が担う (DESIGN §20)。
Defined Under Namespace
Classes: Result, StepResult
Instance Method Summary collapse
-
#initialize(primary:, registry:, machine_validator:, semantic_validator:, logger:, max_retry: 10, timeout_sec: 30) ⇒ Orchestrator
constructor
A new instance of Orchestrator.
-
#run(request, expectations: nil) ⇒ Object
成功時は Result(status: "PASS")。回復不能時は例外を送出する (DESIGN §14)。.
-
#run_step(proposal) ⇒ Object
マルチステップ (Planner) 用: 確定済みの 1 proposal を実行し、機械検証する。 LLM への再提案は行わず、実行 + machine 検証の結果だけを返す (提案・全体達成判定・ループ制御は Planner の責務)。 提案の形状 (未知ツール / スキーマ不一致) は事前に検証し、不正なら例外を送出する。 戻り値: StepResult(machine_ok, result, error)。.
Constructor Details
#initialize(primary:, registry:, machine_validator:, semantic_validator:, logger:, max_retry: 10, timeout_sec: 30) ⇒ Orchestrator
Returns a new instance of Orchestrator.
14 15 16 17 18 19 20 21 22 23 |
# File 'lib/chocomint/orchestrator.rb', line 14 def initialize(primary:, registry:, machine_validator:, semantic_validator:, logger:, max_retry: 10, timeout_sec: 30) @primary = primary @registry = registry @machine_validator = machine_validator @semantic_validator = semantic_validator @logger = logger @max_retry = max_retry @timeout_sec = timeout_sec end |
Instance Method Details
#run(request, expectations: nil) ⇒ Object
成功時は Result(status: "PASS")。回復不能時は例外を送出する (DESIGN §14)。
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/chocomint/orchestrator.rb', line 42 def run(request, expectations: nil) trace_id = SecureRandom.uuid # Step 1: Tool Proposal — JSON invalid / unknown tool は FAIL。 # LLM 通信エラー (タイムアウト等) は一時的な障害として RETRY に乗せる。 proposal, propose_error = propose(request, trace_id) attempt = 0 # 初回から前回までの全試行 (提案 + 失敗原因) を蓄積し、再提案時にまとめて渡す。 history = [] loop do attempt += 1 # backoff は上限を設けて過度な待機を防ぐ (attempt 数増加に対応 / DESIGN §6)。 sleep([attempt - 1, 5].min) if attempt > 1 if proposal.nil? # propose/repropose が LLM 通信エラーで失敗した回。ツール実行はスキップし RETRY へ。 result = { exit_code: 1, stdout: "", stderr: propose_error.to_s, duration_ms: 0 } status = "RETRY" verifier_output = nil error = propose_error else result, machine_ok, error = execute_and_machine_validate(proposal) if machine_ok begin pass, verifier_output = @semantic_validator.validate( request: request, result: result, expectations: expectations, trace_id: trace_id, proposal: proposal ) rescue Chocomint::Error => e # verifier の LLM 通信エラーも一時的な障害として RETRY 扱いにする。 pass = false verifier_output = nil error = "verifier request failed: #{e.}" end if pass @logger.record(trace_id: trace_id, attempt: attempt, request: request, proposal: proposal, result: result, status: "PASS", verifier_output: verifier_output) return Result.new(status: "PASS", trace_id: trace_id, attempts: attempt, result: result, proposal: proposal) end status = "RETRY" # verifier=0 or invalid error ||= "semantic validation failed: #{verifier_output}" else verifier_output = nil status = "RETRY" result ||= { exit_code: 1, stdout: "", stderr: error.to_s, duration_ms: 0 } # tool 例外時は error が入るが、ツールが正常応答で exit_code!=0 を # 返しただけの場合は error が nil のまま残るため、result のエラー内容で補う # (repropose の feedback に失敗理由を確実に載せるため)。 error ||= result[:stderr]&.empty? == false ? result[:stderr] : "machine validation failed" end end @logger.record(trace_id: trace_id, attempt: attempt, request: request, proposal: proposal || { "error" => error.to_s }, result: result, status: status, verifier_output: verifier_output) # この試行の提案と失敗原因を履歴に残す (次の再提案の材料にするため nil でも保持する)。 history << { attempt: attempt, proposal: proposal, error: error } if attempt < @max_retry # 初回〜前回までの全試行を渡し、同じ失敗を繰り返さないよう再提案する (DESIGN §6)。 proposal, propose_error = repropose(request, history, trace_id) next end @logger.record(trace_id: trace_id, attempt: attempt, request: request, proposal: proposal || { "error" => error.to_s }, result: result, status: "FAIL", verifier_output: verifier_output) raise RetryLimitExceededError, "retry limit exceeded (#{@max_retry})" end end |
#run_step(proposal) ⇒ Object
マルチステップ (Planner) 用: 確定済みの 1 proposal を実行し、機械検証する。 LLM への再提案は行わず、実行 + machine 検証の結果だけを返す (提案・全体達成判定・ループ制御は Planner の責務)。 提案の形状 (未知ツール / スキーマ不一致) は事前に検証し、不正なら例外を送出する。 戻り値: StepResult(machine_ok, result, error)。
32 33 34 35 36 37 38 39 |
# File 'lib/chocomint/orchestrator.rb', line 32 def run_step(proposal) validate_proposal_shape!(proposal) result, machine_ok, error = execute_and_machine_validate(proposal) result ||= { exit_code: 1, stdout: "", stderr: error.to_s, duration_ms: 0 } # machine 検証は通ったが error が無い正常応答で exit_code!=0 のケースを補う。 error ||= result[:stderr].to_s.empty? ? nil : result[:stderr] unless machine_ok StepResult.new(machine_ok: machine_ok, result: result, error: error) end |