From b1fdc35f70a09f2bb6e8fcb7feddf76512a8215d Mon Sep 17 00:00:00 2001 From: Rodin Date: Sun, 10 May 2026 01:02:54 -0700 Subject: [PATCH] feat: integrate AI Core client with review-bot Adds aicore provider option that uses native SAP AI Core instead of OpenAI-compatible proxy. Configurable via: - AICORE_CLIENT_ID - AICORE_CLIENT_SECRET - AICORE_AUTH_URL - AICORE_API_URL - AICORE_RESOURCE_GROUP --- cmd/review-bot/main.go | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/cmd/review-bot/main.go b/cmd/review-bot/main.go index 021ccc3..e26735c 100644 --- a/cmd/review-bot/main.go +++ b/cmd/review-bot/main.go @@ -69,7 +69,13 @@ func main() { dryRun := flag.Bool("dry-run", false, "Print review to stdout instead of posting") llmTemp := flag.Float64("llm-temperature", envOrDefaultFloat("LLM_TEMPERATURE", 0), "LLM temperature (0 = server default)") llmTimeout := flag.Int("llm-timeout", envOrDefaultInt("LLM_TIMEOUT", 300), "LLM request timeout in seconds (default 300)") - llmProvider := flag.String("llm-provider", envOrDefault("LLM_PROVIDER", "openai"), "LLM API provider: openai or anthropic") + llmProvider := flag.String("llm-provider", envOrDefault("LLM_PROVIDER", "openai"), "LLM API provider: openai, anthropic, or aicore") + // AI Core specific flags (only used when provider=aicore) + aicoreClientID := flag.String("aicore-client-id", envOrDefault("AICORE_CLIENT_ID", ""), "SAP AI Core client ID (for provider=aicore)") + aicoreClientSecret := flag.String("aicore-client-secret", envOrDefault("AICORE_CLIENT_SECRET", ""), "SAP AI Core client secret (for provider=aicore)") + aicoreAuthURL := flag.String("aicore-auth-url", envOrDefault("AICORE_AUTH_URL", ""), "SAP AI Core auth URL (for provider=aicore)") + aicoreAPIURL := flag.String("aicore-api-url", envOrDefault("AICORE_API_URL", ""), "SAP AI Core API URL (for provider=aicore)") + aicoreResourceGroup := flag.String("aicore-resource-group", envOrDefault("AICORE_RESOURCE_GROUP", "default"), "SAP AI Core resource group (for provider=aicore)") flag.Parse() @@ -84,10 +90,20 @@ func main() { slog.Info("review-bot starting", "version", version) // Validate required fields - if *giteaURL == "" || *repo == "" || *prNum == "" || *reviewerToken == "" || - *llmBaseURL == "" || *llmAPIKey == "" || *llmModel == "" { + // For aicore provider, llm-base-url and llm-api-key are not required + isAICore := llm.Provider(*llmProvider) == llm.ProviderAICore + if *giteaURL == "" || *repo == "" || *prNum == "" || *reviewerToken == "" || *llmModel == "" { fmt.Fprintf(os.Stderr, "Error: missing required flags or environment variables\n\n") - fmt.Fprintf(os.Stderr, "Required: --gitea-url, --repo, --pr, --reviewer-token, --llm-base-url, --llm-api-key, --llm-model\n") + fmt.Fprintf(os.Stderr, "Required: --gitea-url, --repo, --pr, --reviewer-token, --llm-model\n") + os.Exit(1) + } + if !isAICore && (*llmBaseURL == "" || *llmAPIKey == "") { + fmt.Fprintf(os.Stderr, "Error: --llm-base-url and --llm-api-key are required for provider=%s\n", *llmProvider) + os.Exit(1) + } + if isAICore && (*aicoreClientID == "" || *aicoreClientSecret == "" || *aicoreAuthURL == "" || *aicoreAPIURL == "") { + fmt.Fprintf(os.Stderr, "Error: AI Core credentials required for provider=aicore\n\n") + fmt.Fprintf(os.Stderr, "Required: --aicore-client-id, --aicore-client-secret, --aicore-auth-url, --aicore-api-url\n") os.Exit(1) } @@ -125,8 +141,17 @@ func main() { switch llm.Provider(*llmProvider) { case llm.ProviderOpenAI, llm.ProviderAnthropic: llmClient.WithProvider(llm.Provider(*llmProvider)) + case llm.ProviderAICore: + llmClient.WithAICore(llm.AICoreConfig{ + ClientID: *aicoreClientID, + ClientSecret: *aicoreClientSecret, + AuthURL: *aicoreAuthURL, + APIURL: *aicoreAPIURL, + ResourceGroup: *aicoreResourceGroup, + }) + slog.Info("using SAP AI Core provider", "resource_group", *aicoreResourceGroup) default: - slog.Error("invalid LLM provider", "provider", *llmProvider, "valid", "openai, anthropic") + slog.Error("invalid LLM provider", "provider", *llmProvider, "valid", "openai, anthropic, aicore") os.Exit(1) } if *llmTimeout > 0 {