Commit Graph

19 Commits

Author SHA1 Message Date
Rodin b76270c21b fix: put anthropic_version in request body, not header
CI / test (pull_request) Successful in 12s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Failing after 17s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m50s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m43s
SAP AI Core expects anthropic_version in the JSON body, not as a header.
2026-05-09 23:23:42 -07:00
Rodin b92a968d93 fix: add anthropic-version header for AI Core Anthropic endpoint
CI / test (pull_request) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Failing after 17s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m4s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m9s
2026-05-09 23:19:00 -07:00
Rodin 34507dd9ff fix: propagate LLM timeout to AI Core client
CI / test (pull_request) Successful in 15s
CI / review (/anthropic/v1, anthropic--claude-4.6-sonnet, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 32s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m58s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m16s
Address review feedback:

MAJOR:
- AICoreClient now defaults to 5min timeout (matching Client)
- Add AICoreClient.WithTimeout() for explicit timeout control
- Client.WithAICore() inherits parent client's timeout
- Client.WithTimeout() propagates to aicore client if set

MINOR:
- Extract AICoreOpenAIAPIVersion constant for the hardcoded api-version
- Tighten IsAnthropicModel to only match 'anthropic--' prefix
  (SAP AI Core always uses this prefix for Anthropic models)

NIT:
- Use fmt.Sprintf for token generation in tests (robust for >9 calls)
- Add error checking in TestAICoreClient_TokenExpiry
- Add tests for WithTimeout propagation
2026-05-09 22:29:19 -07:00
claw cf453504cb feat: add native SAP AI Core support
CI / test (pull_request) Successful in 13s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Failing after 12s
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 12s
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 14s
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Failing after 11s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m12s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m28s
Adds a new 'aicore' LLM provider that authenticates directly with SAP AI Core
using OAuth client credentials. This eliminates the need for an external proxy
(hai-aicore or hai) when running review-bot in SAP environments.

Key changes:
- New llm/aicore.go with AICoreClient for OAuth token management and
  deployment discovery
- Thread-safe token caching with automatic refresh before expiry
- Automatic routing to /invoke (Anthropic) or /chat/completions (OpenAI)
  based on model name
- New CLI flags: --aicore-client-id, --aicore-client-secret, --aicore-auth-url,
  --aicore-api-url, --aicore-resource-group
- Updated action.yml with corresponding inputs
- Comprehensive test coverage for AI Core client

Example usage in CI:
  llm-provider: aicore
  llm-model: anthropic--claude-4.6-sonnet
  aicore-client-id: ${{ secrets.AICORE_CLIENT_ID }}
  aicore-client-secret: ${{ secrets.AICORE_CLIENT_SECRET }}
  aicore-auth-url: ${{ secrets.AICORE_AUTH_URL }}
  aicore-api-url: ${{ secrets.AICORE_API_URL }}

Closes #49
2026-05-08 17:49:26 -07:00
claw db479d0ff4 fix: retry on transient LLM response body truncation
CI / test (pull_request) Successful in 15s
CI / review (/openai/v1, gpt-4.1, gpt41, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 25s
CI / review (/openai/v1, gpt-4.1-mini, gpt41-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 29s
CI / review (/anthropic/v1, claude-sonnet-4-6, sonnet, anthropic, SONNET_REVIEW_TOKEN) (pull_request) Successful in 49s
CI / review (/openai/v1, gpt-5, security, openai, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 50s
CI / review (/openai/v1, gpt-5, gpt, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m15s
CI / review (/openai/v1, gpt-5-mini, gpt5-mini, openai, GPT_REVIEW_TOKEN) (pull_request) Successful in 52s
Addresses intermittent 'unexpected end of JSON input' failures where the
LLM response body is truncated in transit between the proxy and client.

Root cause: network-level truncation where io.ReadAll returns partial data
(observed in 3/50 CI runs through HAI proxy). The response body reading
was already using io.ReadAll correctly, but transient network issues
between the proxy and client can still cause partial reads.

Changes:
- Add Content-Length validation in doRequest: detect when fewer bytes
  arrive than the server declared, triggering a retry
- Add retry logic in Complete: retries once on retryable errors (body
  read failures, content-length mismatches) with a 500ms backoff
- Add parse-level retry in main: if ParseResponse fails, re-requests
  from the LLM once before giving up (defensive, since retries always
  succeed per issue evidence)
- Improve ParseResponse error diagnostics: log raw vs cleaned lengths
  and a preview of the cleaned content to aid future debugging

Does NOT retry on API errors (4xx/5xx) or structural issues — only
transient body read problems.

Closes #47
2026-05-07 00:44:32 -07:00
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 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 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 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 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
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 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 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 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