Class: Ocak::ClaudeRunner
- Inherits:
-
Object
- Object
- Ocak::ClaudeRunner
- Defined in:
- lib/ocak/claude_runner.rb
Defined Under Namespace
Classes: AgentResult
Constant Summary collapse
- FailedStatus =
Backwards-compat alias — FailedStatus now lives in ProcessRunner.
ProcessRunner::FailedStatus
- AGENT_TOOLS =
{ 'implementer' => 'Read,Write,Edit,Glob,Grep,Bash', 'reviewer' => 'Read,Grep,Glob,Bash', 'security-reviewer' => 'Read,Grep,Glob,Bash', 'auditor' => 'Read,Grep,Glob,Bash', 'documenter' => 'Read,Write,Edit,Glob,Grep,Bash', 'merger' => 'Read,Glob,Grep,Bash', 'pipeline' => 'Read,Write,Edit,Glob,Grep,Bash', 'planner' => 'Read,Glob,Grep,Bash' }.freeze
- MODEL_HAIKU =
ENV.fetch('OCAK_MODEL_HAIKU', 'haiku')
- MODEL_SONNET =
ENV.fetch('OCAK_MODEL_SONNET', 'sonnet')
- MODEL_OPUS =
ENV.fetch('OCAK_MODEL_OPUS', 'opus')
- AGENT_MODELS =
{ 'planner' => MODEL_SONNET, 'reviewer' => MODEL_OPUS, 'security-reviewer' => MODEL_SONNET, 'auditor' => MODEL_SONNET, 'documenter' => MODEL_SONNET, 'merger' => MODEL_SONNET, 'implementer' => MODEL_SONNET, 'pipeline' => MODEL_OPUS }.freeze
- TIMEOUT =
10 minutes per agent invocation
600- MAX_RETRIES =
2- RETRY_DELAYS =
[5, 15].freeze
- TRANSIENT_PATTERNS =
[ /connection.*reset/i, /timed?\s*out/i, /ECONNREFUSED/, /rate\s*limit/i, /503|502|429/, /overloaded/i ].freeze
Instance Method Summary collapse
-
#initialize(config:, logger:, watch: nil, registry: nil) ⇒ ClaudeRunner
constructor
A new instance of ClaudeRunner.
- #run_agent(agent_name, prompt, chdir: nil, model: nil, retries: MAX_RETRIES) ⇒ Object
-
#run_prompt(prompt, allowed_tools: 'Read,Glob,Grep,Bash', chdir: nil, model: nil) ⇒ Object
Run a raw prompt without agent file (for planner, init analysis, etc.).
Constructor Details
#initialize(config:, logger:, watch: nil, registry: nil) ⇒ ClaudeRunner
Returns a new instance of ClaudeRunner.
59 60 61 62 63 64 |
# File 'lib/ocak/claude_runner.rb', line 59 def initialize(config:, logger:, watch: nil, registry: nil) @config = config @logger = logger @watch = watch @registry = registry end |
Instance Method Details
#run_agent(agent_name, prompt, chdir: nil, model: nil, retries: MAX_RETRIES) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/ocak/claude_runner.rb', line 66 def run_agent(agent_name, prompt, chdir: nil, model: nil, retries: MAX_RETRIES) chdir ||= @config.project_dir agent_file = @config.agent_path(agent_name) unless File.exist?(agent_file) @logger.error("Agent file not found: #{agent_file}", agent: agent_name) return AgentResult.new(success: false, output: "Agent file not found: #{agent_file}") end instructions = File.read(agent_file) full_prompt = "#{instructions}\n\n---\n\nTask: #{prompt}" allowed_tools = AGENT_TOOLS.fetch(agent_name, 'Read,Glob,Grep,Bash') agent_model = model || AGENT_MODELS[agent_name] run_with_retry(agent_name, full_prompt, allowed_tools, agent_model, chdir: chdir, retries: retries) end |
#run_prompt(prompt, allowed_tools: 'Read,Glob,Grep,Bash', chdir: nil, model: nil) ⇒ Object
Run a raw prompt without agent file (for planner, init analysis, etc.)
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/ocak/claude_runner.rb', line 84 def run_prompt(prompt, allowed_tools: 'Read,Glob,Grep,Bash', chdir: nil, model: nil) chdir ||= @config.project_dir stdout, _, status = run_claude(prompt, allowed_tools, chdir: chdir, model: model) # Try to extract result from stream-json, fall back to raw stdout result_text = extract_result_from_stream(stdout) || stdout success = status.respond_to?(:success?) && status.success? AgentResult.new(success: success, output: result_text) end |