Class: OllamaAgent::SelfImprovement::Improver

Inherits:
Object
  • Object
show all
Defined in:
lib/ollama_agent/self_improvement/improver.rb

Overview

Copies the project into a temp directory, runs the agent with optional semi-auto patch policy, runs the test suite in the sandbox, and optionally merges changed files back to the source tree. rubocop:disable Metrics/ClassLength – orchestration + restore + merge helpers

Constant Summary collapse

SANDBOX_EXCLUDE =
%w[.git vendor coverage tmp .bundle .cursor node_modules .rspec_status].freeze
MERGE_SKIP_BASENAMES =

Basenames never merged back from the sandbox (test runs create these; they are gitignored).

%w[.rspec_status].freeze
VERIFY_STEPS =
%w[syntax rubocop rspec].freeze
FIX_PROMPT =
<<~PROMPT
  You are improving the ollama_agent Ruby gem in this temporary sandbox copy.
  The user message may begin with "## Static analysis (ruby_mastery)" from tooling; confirm against the sandbox.
  Use list_files, search_code, and read_file to understand the code, then edit_file with valid unified diffs.
  Prefer small, reviewable changes: fixes, tests, docs, and clarity.
  Scan for TODO/FIXME/HACK comments and prioritize sensible cleanups when they are low-risk.
  Minimal diffs only: fewest lines per edit_file, exact @@ counts—no whole-method or mega-hunks.
  Do not delete Gemfile, Gemfile.lock, the gemspec, or exe/; the improve run restores those from the source
  tree before tests, but deleting them breaks the session.
  Do not add or rely on .rspec_status or other ignored test-artifact files; RSpec may create them during the test step.
  After this session, the runner verifies the sandbox (configured steps such as ruby -c on changed .rb files,
  optional RuboCop, then bundle exec rspec spec/)—keep edits syntactically valid and test-friendly.

  When finished, summarize what you changed in plain language.
PROMPT

Instance Method Summary collapse

Instance Method Details

#run(model: nil, root: nil, yes: false, semi: true, apply: false, http_timeout: nil, think: nil, client: nil, skill_paths: nil, skills_enabled: nil, skills_include: nil, skills_exclude: nil, external_skills_enabled: nil, max_tokens: nil, context_summarize: nil, stream: false, verify: nil, ruby_mastery: true) ⇒ Object

rubocop:disable Metrics/ParameterLists – mirrors CLI; keeps call sites explicit rubocop:disable Metrics/MethodLength, Metrics/AbcSize – single orchestration entrypoint



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
# File 'lib/ollama_agent/self_improvement/improver.rb', line 43

def run(model: nil, root: nil, yes: false, semi: true, apply: false, http_timeout: nil, think: nil, client: nil,
        skill_paths: nil, skills_enabled: nil, skills_include: nil, skills_exclude: nil,
        external_skills_enabled: nil,
        max_tokens: nil, context_summarize: nil,
        stream: false,
        verify: nil,
        ruby_mastery: true)
  source_root = resolve_source_root(root)
  sandbox_root = Dir.mktmpdir("ollama_agent_improve_")
  policy = semi ? PatchRisk.method(:assess).to_proc : nil
  verify_steps = normalize_verify_steps(verify)

  begin
    copy_project_into_sandbox(source_root, sandbox_root)
    run_agent_session(
      sandbox_root,
      source_root: source_root,
      ruby_mastery: ruby_mastery,
      stream: stream,
      client: client,
      model: model,
      confirm_patches: !yes,
      patch_policy: policy,
      http_timeout: http_timeout,
      think: think,
      max_tokens: max_tokens,
      context_summarize: context_summarize,
      skill_paths: skill_paths,
      skills_enabled: skills_enabled,
      skills_include: skills_include,
      skills_exclude: skills_exclude,
      external_skills_enabled: external_skills_enabled
    )
    restore_build_essentials_from_source(source_root, sandbox_root)
    missing = missing_gemfile_failure(source_root, sandbox_root)
    return build_run_result(missing, [], source_root) if missing

    test_result = run_test_suite(sandbox_root, source_root, verify_steps)
    copied = copy_back_if_requested(test_result, apply, sandbox_root, source_root)
    build_run_result(test_result, copied, source_root)
  ensure
    FileUtils.remove_entry(sandbox_root) if sandbox_root && Dir.exist?(sandbox_root)
  end
end