SAP AI Core's Anthropic endpoint uses AWS Bedrock API format, not native
Anthropic API. Verified via integration testing:
- 2023-06-01: Invalid API version
- bedrock-2023-05-31: Works ✓
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
- Use 'anthropic--claude-4.6-sonnet' instead of 'claude-sonnet-4-6'
(hai-aicore proxy requires the 'anthropic--' prefix)
- Remove gpt-4.1, gpt-4.1-mini, gpt-5-mini reviewers since those models
are not deployed in SAP AI Core
- Keep sonnet, gpt-5, and security reviews
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
No blocking issues found — ready for human review.
#### Notes (informational, not blocking)
**[fit]** `staticcheck` reports:
-`llm/aicore.go:237` and `llm/client.go:231`: struct literal conversion style (S1016) — minor style nit, existing in both old and new code
-`gitea/diff.go:78`: HasPrefix return ignored (SA4017) — pre-existing, not introduced by this PR
-`cmd/review-bot/main_test.go:347`: nil Context (SA1012) — pre-existing, not introduced by this PR
**[fit]** Body length validation: `aicore.go` does not include the Content-Length vs body length validation that `doRequest` has in `client.go`. This is acceptable because:
1. AI Core uses OAuth tokens which are short-lived, so truncation is less likely
2. The retry logic still applies via "read response" error pattern
3. Adding complexity to aicore.go for an edge case that hasn't manifested is premature
**[completeness]** Tests pass (go test ./...), go vet clean, no uncommitted changes.
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.