Commit Graph

186 Commits

Author SHA1 Message Date
Rodin 14a0c2a946 feat: add Anthropic Messages API support (#18)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m2s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m43s
Adds --llm-provider flag (openai|anthropic) to switch between API formats.

Anthropic implementation:
- POST /messages endpoint
- x-api-key + anthropic-version headers
- System prompt as top-level field (not a message)
- max_tokens: 8192 for response generation
- Parses content blocks [{type: "text", text: "..."}]

Changes:
- llm/client.go: Provider type, completeAnthropic(), doRequest() shared helper
- cmd/review-bot/main.go: --llm-provider / LLM_PROVIDER flag
- .gitea/actions/review/action.yml: llm-provider input + env
- llm/client_test.go: 4 new tests for Anthropic path

Backwards compatible — default provider is still openai.

Closes #18
2026-05-01 18:49:17 -07:00
Rodin 67d835909f feat: add context budget system for LLM overflow (#19)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m30s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m29s
Adds a budget package that estimates token usage and progressively
trims context to fit within model-specific limits.

Trim order (least important first):
1. Language patterns
2. Repository conventions
3. Full file context
4. Diff (truncated as last resort)

When content is trimmed, a note is appended to the user prompt so
the LLM knows context was reduced.

- New budget package with Fit(), EstimateTokens(), LimitForModel()
- Model limit table (GPT-4.1: 128K, GPT-5: 200K, Claude: 200K)
- Refactored review/prompt.go: BuildSystemBase() and BuildUserMeta()
  extract non-trimmable content; old functions delegate to new ones
- main.go uses budget.Fit() instead of direct prompt assembly
- 7 unit tests covering all trim paths

Closes #19
2026-05-01 18:46:53 -07:00
rodin ef3e6d5e87 Merge pull request 'fix: path-escape file paths and eliminate url package shadowing' (#17) from fix/url-escaping-and-shadow into main
CI / test (push) Successful in 15s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
2026-05-01 21:55:02 +00:00
Rodin aade891129 docs: add package-level documentation
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Failing after 55s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Failing after 1m6s
Per go-patterns/package-design.md, every package needs a doc comment.
Added to gitea, llm, and review packages.
2026-05-01 14:54:58 -07:00
Rodin 7b42de67ca fix: handle empty path in ListContents (root listing)
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m4s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m8s
Empty path now yields /contents instead of /contents/ (trailing slash).
Added doc comment noting empty path = repo root.
2026-05-01 14:46:40 -07:00
Rodin dd2661fe14 fix: address all review findings from PR #17
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 52s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m12s
- Rename all remaining url locals to reqURL (consistency)
- Use http.MethodGet/http.MethodPost constants
- Document escapePath: relative paths only, double-encoding expected
- Add TestEscapePath with 7 edge cases (empty, spaces, #, deep, encoded)
2026-05-01 14:40:19 -07:00
Rodin 98a4772f30 fix: path-escape file paths and eliminate url package shadowing
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 55s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m48s
- Add escapePath() helper: escapes each path segment individually
  (preserves slashes as separators, escapes spaces/#/? etc)
- Apply to GetFileContent, GetFileContentRef, ListContents
- Rename doGet parameter from url to reqURL (avoids shadowing net/url)
- Rename local variables in GetFileContent/ListContents for consistency

Addresses remaining findings from PR #16 review.
2026-05-01 14:33:18 -07:00
rodin fc23b6ebe9 Merge pull request 'fix: quick wins (#7, #9, #13)' (#16) from fix/quick-wins into main
CI / test (push) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
2026-05-01 21:30:57 +00:00
Rodin b02ade4f23 fix: quick wins (#7, #9, #13)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 59s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m48s
- Add --version flag and log version on startup (closes #9)
- URL-escape ref query parameter in GetFileContentRef (closes #7)
- Add go vet to release workflow (closes #13)

Renamed local url variable to reqURL to avoid shadowing net/url package.
2026-05-01 14:19:37 -07:00
rodin f8e77cf7e3 Merge pull request 'feat: add context.Context + unexport client fields' (#14) from fix/context-and-encapsulation into main
CI / test (push) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
Release / release (push) Successful in 31s
v0.1.0
2026-05-01 21:10:37 +00:00
Rodin 69e70466fd fix: address all review findings (context timeout, docs, early exit)
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m7s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m40s
- Overall context timeout now derived from LLM timeout + 1 minute
  (no longer hardcoded 3min that could conflict with longer LLM timeouts)
- Clarify concurrency docs: With* methods are setup-only, not concurrent
- Add ctx.Err() checks in fetchFileContext and fetchPatterns loops
  (break early on cancellation instead of making unnecessary requests)
2026-05-01 13:26:19 -07:00
Rodin 0cca44b65a fix: address all remaining review findings on PR #14
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m29s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m36s
- Fix doc comments: WithTimeout and WithTemperature each get their own
- Add TestWithTimeout (verifies short timeout causes request failure)
- Log warning on directory recursion failure in GetAllFilesInPath
- Note: unexported fields is a breaking change, will document in release notes
2026-05-01 13:17:39 -07:00
Rodin 43041a00f5 fix: rewrite action.yml (was corrupted with duplicate keys)
CI / test (pull_request) Successful in 11s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m34s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m33s
Clean single definition of all inputs: temperature, timeout,
patterns-repo, patterns-files. Also added runner requirements
comment at the top.
2026-05-01 13:08:18 -07:00
Rodin 1da61e514d feat: make LLM timeout configurable (default 5min)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m6s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m14s
New flag: --llm-timeout / LLM_TIMEOUT (seconds, default 300)
New builder: llmClient.WithTimeout(duration)
Composite action: new timeout input

Keeps 5 minutes as the sensible default but allows tuning for
larger repos or slower models.
2026-05-01 13:04:00 -07:00
Rodin 401e94d3e4 fix: increase LLM client timeout to 5 minutes
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m13s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m43s
GPT-5-mini timed out on larger diffs (2min was too short).
LLM calls for code review with full file context can take 2-4min.
2026-05-01 13:00:36 -07:00
Rodin cedb5e7b90 fix: address all review findings on PR #14
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 48s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Failing after 2m12s
- gitea.Client: add concurrency safety doc comment
- gitea.Client: set 30s HTTP client timeout as safety net
- llm.Client: add concurrency safety doc comment
- llm.Client: set 2min HTTP client timeout (LLM calls are slow)
- gitea/client.go: gofmt to fix indentation
- integration_test: update to current BuildSystemPrompt/BuildUserPrompt signatures
- integration_test: use strings.SplitN for owner/repo parsing
2026-05-01 12:56:07 -07:00
Rodin ecebd52371 fix: log warnings instead of swallowing errors
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m29s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m44s
- GetAllFilesInPath: log.Printf when file fetch or dir recursion fails
- integration_test: use strings.SplitN for owner/repo parsing (idiomatic)

Addresses GPT review findings #1, #2.
2026-05-01 12:45:52 -07:00
Rodin 27e0056f29 feat: add context.Context + unexport client fields
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 54s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m22s
REVIEW.md findings 1-4, 14:
- All Gitea client methods now accept context.Context as first param
- All LLM client methods now accept context.Context as first param
- Use http.NewRequestWithContext for cancellation/timeout support
- Main uses 3-minute timeout context for all operations
- Unexport Client struct fields (baseURL, token, apiKey, etc.)
- Use bytes.NewReader instead of strings.NewReader(string(...))
2026-05-01 12:31:41 -07:00
aweiker ffca0eb016 Merge pull request 'docs: add comprehensive code review report (vs go-patterns)' (#1) from docs/code-review-report into main
CI / test (push) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #1
2026-05-01 19:25:16 +00:00
Rodin 9aec7ff952 docs: add comprehensive code review report (vs go-patterns)
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Failing after 1m4s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Failing after 3m47s
2026-05-01 19:24:41 +00:00
aweiker 582ebf7ff6 Merge pull request 'ci: add release workflow + install script' (#2) from ci/release-workflow into main
CI / test (push) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (push) Has been skipped
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (push) Has been skipped
Reviewed-on: #2
2026-05-01 19:24:15 +00:00
Rodin f77ea171c3 ci: add go-patterns as review reference
CI / test (pull_request) Successful in 13s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m43s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m50s
Self-reviews now use rodin/go-patterns (README.md + docs/) as
language idiom criteria alongside CONVENTIONS.md.
2026-05-01 12:15:25 -07:00
Rodin 56f5abda3c feat: multi-repo patterns + directory recursion
CI / test (pull_request) Successful in 14s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m57s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 2m2s
patterns-repo now accepts a comma-separated list of repos:
  PATTERNS_REPO="rodin/elixir-patterns,rodin/phoenix-conventions"

patterns-files accepts files AND directories:
  PATTERNS_FILES="README.md,docs/"

When a path is a directory, all files within it are fetched
recursively via the Gitea contents API. Only .md, .txt, .yml,
and .yaml files are included as pattern content.

New API methods:
- ListContents: list files/dirs at a path via contents API
- GetAllFilesInPath: recursively fetch all file contents

This allows a single review action to pull idioms from multiple
pattern repos (e.g. elixir-patterns + phoenix-conventions) and
include entire directories of documentation as review criteria.
2026-05-01 12:14:19 -07:00
Rodin e234dca474 feat: full file context + patterns-repo support
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m51s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m0s
Major improvements to review quality:

1. Full file context: fetch complete content of all modified files from
   the PR branch and include as reference. This eliminates false-positive
   "missing import" findings since the model sees the entire file.

2. Patterns repo: new --patterns-repo / PATTERNS_REPO flag fetches
   language idiom files from a separate Gitea repo (e.g. rodin/elixir-patterns)
   and includes them as review criteria.

3. Multi-file patterns: --patterns-files / PATTERNS_FILES accepts
   comma-separated file paths to fetch from the patterns repo.

New API methods:
- GetPullRequestFiles: list changed files in a PR
- GetFileContentRef: fetch file content from a specific branch/ref

Prompt changes:
- BuildSystemPrompt now accepts (conventions, patterns)
- BuildUserPrompt now accepts fileContext parameter
- File context displayed before diff for model reference
- Patterns presented as "review criteria" in system prompt

Composite action updated with patterns-repo and patterns-files inputs.
2026-05-01 12:11:49 -07:00
Rodin c76362af95 fix: prevent false-positive missing-import findings
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m59s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 3m36s
The LLM was treating the diff as complete file context and flagging
"missing imports" for symbols that exist in unchanged portions of
the file. Added explicit instructions to the system prompt:

- Clarify that the diff is partial; unchanged code already exists
- Explicitly instruct: do not flag missing imports/types unless the
  diff introduces a new usage without a corresponding addition
- Add rule: never flag undefined symbols that could exist in the
  unchanged portions
2026-05-01 12:00:27 -07:00
Rodin 46c63ed121 fix: address all review findings (zero remaining)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m43s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 2m19s
Tests:
- Add WithTemperature tests (builder method, chaining, zero omission)
- Add temperature serialization tests (omitted when 0, included when set)

Composite action:
- Use python3 for robust JSON version parsing (replaces sed)
- Verify SHA-256 checksum before executing downloaded binary
- Wire up repo input (no longer hardcodes rodin/review-bot)

Release workflow:
- Handle 409 conflict (existing release for tag)
- Use file-based JSON parsing for reliability

Code:
- Tighten WithTemperature doc comment (single clear line)
- Fix flag alignment (missing tab on llmTemp declaration)
2026-05-01 11:58:21 -07:00
Rodin 59fbd38837 fix: address all remaining review findings
CI / test (pull_request) Successful in 14s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 2m20s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m20s
- Add temperature range validation (must be 0-2, fatal on invalid)
- release.yml: use python3 for robust JSON parsing instead of sed
- Composite action: add header comment confirming Gitea Actions compat
- All findings from review #385 addressed
2026-05-01 11:40:15 -07:00
Rodin 8d53b649ee fix: address review findings (cache path, docs)
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 2m13s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m48s
- Composite action: cache to runner.temp instead of /usr/local/bin
  (avoids permission issues on runners)
- Document that temperature=0 means server default (omitted from request)
- Note: strconv import already exists (false positive from GPT-5)
2026-05-01 11:38:28 -07:00
Rodin c458587cfc feat: add composite action for clean distribution
CI / test (pull_request) Successful in 13s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 2m28s
CI / review (gpt-5-mini, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m43s
- .gitea/actions/review/action.yml: composite action with caching
  Consumers just use:
    uses: https://gitea.weiker.me/rodin/review-bot/.gitea/actions/review@v0.1.0
  No Go toolchain needed, binary cached by version tag.

- Remove install.sh (replaced by composite action)
- CI workflow: use matrix strategy to parallelize reviews
- Self-review still builds from source (pre-release)
2026-05-01 11:32:15 -07:00
Rodin 4b3cac66c3 fix: address review findings
CI / test (pull_request) Successful in 14s
CI / review (pull_request) Successful in 5m3s
- install.sh: verify SHA-256 checksum before installing binary
- install.sh: fallback to ~/.local/bin if /usr/local/bin not writable
- install.sh: use sed instead of grep for POSIX-safe JSON parsing
- release.yml: remove jq dependency, parse release ID with sed
- llm: make temperature configurable via --llm-temperature / LLM_TEMPERATURE
- llm: add WithTemperature builder method on Client
- llm: omit temperature from request when zero (uses server default)
2026-05-01 11:22:31 -07:00
Rodin b6277216f7 fix: remove hardcoded temperature (unsupported by GPT-5)
CI / test (pull_request) Successful in 14s
CI / review (pull_request) Successful in 4m56s
GPT-5 via SAP AI Core only supports temperature=1 (default).
Remove the hardcoded 0.1 and use omitempty so the field is not sent.
2026-05-01 11:15:08 -07:00
Rodin 99916fe24a fix(ci): use GPT models available via HAI proxy
CI / test (pull_request) Successful in 13s
CI / review (pull_request) Failing after 12s
HAI proxy serves Anthropic on a different path (/anthropic/v1) than
OpenAI (/openai/v1). Until review-bot supports multiple base URLs,
use GPT-5 and GPT-5-mini for both review slots.
2026-05-01 11:02:27 -07:00
Rodin d62e8ee4f0 ci: retrigger after adding secrets
CI / test (pull_request) Successful in 14s
CI / review (pull_request) Failing after 12s
2026-05-01 10:40:39 -07:00
Rodin 0568a84aa9 ci: add release workflow + install script
CI / test (pull_request) Successful in 14s
CI / review (pull_request) Failing after 11s
- Release workflow: builds linux/darwin amd64/arm64 on tag push
- Injects version via -ldflags
- Creates Gitea release with binary assets + checksums
- install.sh: curl-pipe-bash installer from latest release
- Version variable in main.go for -version flag support
2026-05-01 10:36:23 -07:00
Rodin 3c536c42d5 Add unit tests, integration test, CI workflow, and conventions
CI / test (push) Successful in 18s
CI / review (push) Has been skipped
- gitea/client_test.go: mock HTTP tests for all API methods + error cases
- llm/client_test.go: mock tests for completion, errors, timeouts
- review/parser_test.go: JSON parsing, markdown fences, validation
- review/formatter_test.go: markdown output, empty/multiple findings
- review/prompt_test.go: system/user prompt construction
- integration_test.go: full end-to-end flow (build tag: integration)
- .gitea/workflows/ci.yml: test + vet + build on push, dual LLM review on PRs
- CONVENTIONS.md: coding standards for self-review dogfooding
- README.md: usage docs, env vars, architecture
2026-05-01 10:03:44 -07:00
Rodin 700f186023 Initial implementation: AI code review bot for Gitea
- CLI binary with flag/env var configuration
- Gitea API client (PR metadata, diff, CI status, post review)
- OpenAI-compatible LLM client
- Structured review prompt with conventions support
- JSON response parser with validation
- Markdown review formatter for Gitea
- CI failure auto-detection (REQUEST_CHANGES)
- Dry-run mode for testing
2026-05-01 09:42:45 -07:00