Skip to content

Conversation

@wesm
Copy link
Collaborator

@wesm wesm commented Jan 25, 2026

Summary

Adds --model flag support to all agents (codex, claude-code, gemini, copilot, opencode), allowing users to specify which model an agent should use. This lays the groundwork for the more comprehensive agent/model-per-reasoning-level configuration described in #125.

Changes

CLI

  • Add --model flag to review, refine, and run commands
  • Help text explains format varies by agent (e.g., opencode uses provider/model)

Configuration

  • default_model in ~/.roborev/config.toml - global default model
  • model in .roborev.toml - per-repo model override
  • Resolution priority: CLI flag > repo config > global config > agent default

Agent Interface

  • All agents implement WithModel(model string) Agent
  • Model passed to underlying CLI where supported (--model, -m, etc.)

Database & Sync

  • Added model column to Postgres schema (v1→v2 migration)
  • Model included in job sync between SQLite and Postgres
  • Model returned in job listing/detail API responses
  • COALESCE backfill ensures existing jobs get model populated on upsert

Schema Management

  • Postgres schema now defined in internal/storage/schemas/*.sql files
  • Single source of truth, easy to diff between versions
  • v1→v2 migration tested with job data preservation

Bug Fixes

  • Fixed OpenCodeAgent.WithReasoning to preserve Model field
  • Improved OpenCode tool-call filter documentation

Relationship to #125

This PR provides the foundation for the model-per-reasoning-level feature proposed in #125:

This PR Enables in #125
WithModel() on all agents Phase 2 model overrides
default_model / model config Fallback when no per-reasoning override
model column in database Already stores resolved model per job
ResolveModel() function Base for future ResolveReviewModel(reasoning, ...)

The database schema does not need further changes - the single model column stores whichever model was resolved at enqueue time, regardless of selection mechanism.

Supersedes

Supersedes #124 (OpenCode tool-call filtering) - that fix is included here along with improved documentation.

Test Plan

  • Unit tests for ResolveModel() config resolution
  • Unit tests for WithModel() persistence across all agents
  • Unit tests for model flag generation in buildArgs()
  • Integration tests for Postgres v1→v2 migration
  • Integration tests for COALESCE model backfill (Postgres & SQLite)
  • All existing tests pass

beettlle and others added 15 commits January 25, 2026 15:50
## Summary
- Introduces a new function `filterOpencodeToolCallLines` to clean up the output from the OpenCode CLI by removing JSON lines that represent tool calls, which are not needed for the review process.
- Adds a helper function `isOpencodeToolCallLine` to identify these JSON lines.

## Changes
- Updated the `Review` method to utilize the new filtering function on the command output before returning the result.

## Test plan
- [ ] Verify that the output from `OpenCodeAgent.Review` no longer includes tool-call JSON lines.

Generated with [Cursor](https://cursor.com)
- Require exactly 2 keys (name, arguments) to identify tool calls
- Use TrimRight instead of TrimSpace to preserve leading indentation
- Add tests for JSON examples with extra keys and indented content

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add model configuration support to allow specifying which model opencode
should use. This is useful when the default model doesn't support certain
features or when you want to use a specific model for reviews.

Changes:
- Add `opencode_model` to config.toml for global default
- Add `opencode_model` to .roborev.toml for per-repo override
- Add `--model` flag to run, review, and refine commands
- Add `WithModel(model string)` to Agent interface
- Pass `--model` flag to opencode when configured
- Add `model` column to review_jobs table with migration

The model format for opencode is "provider/model", e.g.,
"anthropic/claude-sonnet-4-20250514".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend model configuration from opencode-only to all agents (codex,
claude, gemini, copilot). Each agent now properly stores and passes
the model flag to its CLI (-m for codex/gemini, --model for claude/
copilot). Renamed config from opencode_model to model/default_model
for generality.

Added tests for ResolveModel config resolution and agent model
persistence through WithReasoning/WithAgentic method chains.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…docs

WithReasoning was returning the same instance instead of a copy, which
could cause issues with method chaining. Now returns a copy that
preserves all fields including Model.

Also improved the filterOpencodeToolCallLines comment to document that
it filters the standard LLM tool call format that may occasionally leak
through when streaming, not OpenCode-specific output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses review finding about testing gap: the model flag plumbing
was not covered for Copilot and OpenCode. Added integration tests
that verify --model is passed to both agents.

Also clarified ResolveModel comment to document which config file
uses which key (default_model in config.toml, model in .roborev.toml).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update CLI --model help text to be generic (not opencode-specific)
- Add model column to Postgres schema with v1->v2 migration
- Include model in UpsertJob, PulledJob, and PullJobs for sync
- Add model to SyncableJob and GetJobsToSync for push sync
- Include model in ListJobs and GetJobByID for API responses

Addresses review findings #2478 and #2479.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add COALESCE for model in UpsertJob (postgres.go) and UpsertPulledJob
  (sync.go) ON CONFLICT clauses so existing jobs get model backfilled
  when the incoming row has one
- Add integration test for v1→v2 Postgres migration that verifies:
  - Schema version advances from 1 to 2
  - Model column is added to review_jobs table
  - Existing jobs remain accessible with NULL model

Addresses review findings #2483.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use schema-qualified table names (roborev.schema_version, etc.) in
  MigratesV1ToV2 test instead of SET search_path, which only affects
  one connection in a pool
- Add TestIntegration_UpsertJob_BackfillsModel to verify Postgres
  COALESCE behavior: existing NULL model gets backfilled, and empty
  model doesn't clear existing value
- Add TestUpsertPulledJob_BackfillsModel for SQLite path with same
  verification

Addresses review findings #2487.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add internal/storage/schemas/postgres_v1.sql and postgres_v2.sql
- v1→v2 migration test now loads schema from embedded SQL file
- Makes schema differences between versions easy to diff
- Simplifies test by removing inline schema definitions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- postgres.go now embeds schemas/postgres_v2.sql instead of defining
  schema as Go string slice
- pgSchemaStatements() parses the SQL file into individual statements
- SQL files use schema-qualified names (roborev.table_name) for clarity
- Removes ~100 lines of inline schema definition from postgres.go
- Single source of truth: edit the SQL file to change schema

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Drop existing schema at start of test so it runs regardless of prior state
- Fix SQL parsing to handle statements with leading comments (match
  pgSchemaStatements() logic)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tion

- Add test job insertion before v1→v2 migration to verify data survives
- Verify pre-existing job has model=NULL after migration
- Add CREATE SCHEMA assertion to TestPgSchemaStatementsContainsRequiredTables
- Document that v1 SQL is the sync schema (completed jobs only)

Addresses review findings #2495 and #2496.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes FK error when sequence isn't reset in reused test database.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
EnqueueJob and EnqueueRangeJob now require model parameter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@wesm wesm merged commit f8f6658 into main Jan 25, 2026
7 checks passed
@wesm wesm deleted the configurable-models branch January 25, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants