From 38094a2339e09f9a2a4df93be75928c8bcc1fc7c Mon Sep 17 00:00:00 2001 From: taetaetae Date: Fri, 30 Jan 2026 16:25:32 +0900 Subject: [PATCH 1/3] feat(kiro): Add dynamic region support for API endpoints ## Problem - Kiro API endpoints were hardcoded to us-east-1 region - Enterprise users in other regions (e.g., ap-northeast-2) experienced significant latency (200-400x slower) due to cross-region API calls - This is the API endpoint counterpart to quotio PR #241 which fixed token refresh endpoints ## Solution - Add buildKiroEndpointConfigs(region) function for dynamic endpoint generation - Extract region from auth.Metadata["region"] field - Fallback to us-east-1 for backward compatibility - Use case-insensitive authMethod comparison (consistent with quotio PR #252) ## Changes - Add kiroDefaultRegion constant - Convert hardcoded endpoint URLs to dynamic fmt.Sprintf with region - Update getKiroEndpointConfigs to extract and use region from auth - Fix isIDCAuth to use case-insensitive comparison ## Testing - Backward compatible: defaults to us-east-1 when no region specified - Enterprise users can now use their local region endpoints Related: - quotio PR #241: Dynamic region for token refresh (merged) - quotio PR #252: authMethod case-insensitive fix - quotio Issue #253: Performance issue report --- internal/runtime/executor/kiro_executor.go | 74 +++++++++++++++------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/internal/runtime/executor/kiro_executor.go b/internal/runtime/executor/kiro_executor.go index 57574268..f5339663 100644 --- a/internal/runtime/executor/kiro_executor.go +++ b/internal/runtime/executor/kiro_executor.go @@ -334,12 +334,16 @@ type kiroEndpointConfig struct { Name string // Endpoint name for logging } -// kiroEndpointConfigs defines the available Kiro API endpoints with their compatible configurations. -// The order determines fallback priority: primary endpoint first, then fallbacks. +// kiroDefaultRegion is the default AWS region for Kiro API endpoints. +// Used when no region is specified in auth metadata. +const kiroDefaultRegion = "us-east-1" + +// buildKiroEndpointConfigs creates endpoint configurations for the specified region. +// This enables dynamic region support for Enterprise/IdC users in non-us-east-1 regions. // // CRITICAL: Each endpoint MUST use its compatible Origin and AmzTarget values: -// - CodeWhisperer endpoint (codewhisperer.us-east-1.amazonaws.com): Uses AI_EDITOR origin and AmazonCodeWhispererStreamingService target -// - Amazon Q endpoint (q.us-east-1.amazonaws.com): Uses CLI origin and AmazonQDeveloperStreamingService target +// - CodeWhisperer endpoint (codewhisperer.{region}.amazonaws.com): Uses AI_EDITOR origin and AmazonCodeWhispererStreamingService target +// - Amazon Q endpoint (q.{region}.amazonaws.com): Uses CLI origin and AmazonQDeveloperStreamingService target // // Mismatched combinations will result in 403 Forbidden errors. // @@ -348,22 +352,32 @@ type kiroEndpointConfig struct { // 2. These tokens use AI_EDITOR origin which is only compatible with CodeWhisperer endpoint // 3. Amazon Q endpoint requires CLI origin which is for Amazon Q CLI tokens // This matches the AIClient-2-API-main project's configuration. -var kiroEndpointConfigs = []kiroEndpointConfig{ - { - URL: "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse", - Origin: "AI_EDITOR", - AmzTarget: "AmazonCodeWhispererStreamingService.GenerateAssistantResponse", - Name: "CodeWhisperer", - }, - { - URL: "https://q.us-east-1.amazonaws.com/", - Origin: "CLI", - AmzTarget: "AmazonQDeveloperStreamingService.SendMessage", - Name: "AmazonQ", - }, +func buildKiroEndpointConfigs(region string) []kiroEndpointConfig { + if region == "" { + region = kiroDefaultRegion + } + return []kiroEndpointConfig{ + { + URL: fmt.Sprintf("https://codewhisperer.%s.amazonaws.com/generateAssistantResponse", region), + Origin: "AI_EDITOR", + AmzTarget: "AmazonCodeWhispererStreamingService.GenerateAssistantResponse", + Name: "CodeWhisperer", + }, + { + URL: fmt.Sprintf("https://q.%s.amazonaws.com/generateAssistantResponse", region), + Origin: "CLI", + AmzTarget: "AmazonQDeveloperStreamingService.SendMessage", + Name: "AmazonQ", + }, + } } +// kiroEndpointConfigs is kept for backward compatibility with default us-east-1 region. +// Prefer using buildKiroEndpointConfigs(region) for dynamic region support. +var kiroEndpointConfigs = buildKiroEndpointConfigs(kiroDefaultRegion) + // getKiroEndpointConfigs returns the list of Kiro API endpoint configurations to try in order. +// Supports dynamic region based on auth metadata "region" field. // Supports reordering based on "preferred_endpoint" in auth metadata/attributes. // For IDC auth method, automatically uses CodeWhisperer endpoint with CLI origin. func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { @@ -371,15 +385,27 @@ func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { return kiroEndpointConfigs } + // Extract region from auth metadata, fallback to default + region := kiroDefaultRegion + if auth.Metadata != nil { + if r, ok := auth.Metadata["region"].(string); ok && r != "" { + region = r + log.Debugf("kiro: using region from auth metadata: %s", region) + } + } + + // Build endpoint configs for the specified region + endpointConfigs := buildKiroEndpointConfigs(region) + // For IDC auth, use CodeWhisperer endpoint with AI_EDITOR origin (same as Social auth) // Based on kiro2api analysis: IDC tokens work with CodeWhisperer endpoint using Bearer auth // The difference is only in how tokens are refreshed (OIDC with clientId/clientSecret for IDC) // NOT in how API calls are made - both Social and IDC use the same endpoint/origin if auth.Metadata != nil { authMethod, _ := auth.Metadata["auth_method"].(string) - if authMethod == "idc" { - log.Debugf("kiro: IDC auth, using CodeWhisperer endpoint") - return kiroEndpointConfigs + if strings.ToLower(authMethod) == "idc" { + log.Debugf("kiro: IDC auth, using CodeWhisperer endpoint (region: %s)", region) + return endpointConfigs } } @@ -396,7 +422,7 @@ func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { } if preference == "" { - return kiroEndpointConfigs + return endpointConfigs } preference = strings.ToLower(strings.TrimSpace(preference)) @@ -405,7 +431,7 @@ func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { var sorted []kiroEndpointConfig var remaining []kiroEndpointConfig - for _, cfg := range kiroEndpointConfigs { + for _, cfg := range endpointConfigs { name := strings.ToLower(cfg.Name) // Check for matches // CodeWhisperer aliases: codewhisperer, ide @@ -426,7 +452,7 @@ func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { // If preference didn't match anything, return default if len(sorted) == 0 { - return kiroEndpointConfigs + return endpointConfigs } // Combine: preferred first, then others @@ -445,7 +471,7 @@ func isIDCAuth(auth *cliproxyauth.Auth) bool { return false } authMethod, _ := auth.Metadata["auth_method"].(string) - return authMethod == "idc" + return strings.ToLower(authMethod) == "idc" } // buildKiroPayloadForFormat builds the Kiro API payload based on the source format. From 9293c685e0023246dfe3a3186bb0f7acc1fba27c Mon Sep 17 00:00:00 2001 From: taetaetae Date: Fri, 30 Jan 2026 16:30:03 +0900 Subject: [PATCH 2/3] fix: Correct Amazon Q endpoint URL path Revert the Amazon Q endpoint path to root '/' instead of '/generateAssistantResponse'. The '/generateAssistantResponse' path is only for CodeWhisperer endpoint with 'GenerateAssistantResponse' target. Amazon Q endpoint uses 'SendMessage' target which requires the root path. Thanks to @gemini-code-assist for catching this copy-paste error. --- internal/runtime/executor/kiro_executor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/runtime/executor/kiro_executor.go b/internal/runtime/executor/kiro_executor.go index f5339663..35bbd03f 100644 --- a/internal/runtime/executor/kiro_executor.go +++ b/internal/runtime/executor/kiro_executor.go @@ -364,7 +364,7 @@ func buildKiroEndpointConfigs(region string) []kiroEndpointConfig { Name: "CodeWhisperer", }, { - URL: fmt.Sprintf("https://q.%s.amazonaws.com/generateAssistantResponse", region), + URL: fmt.Sprintf("https://q.%s.amazonaws.com/", region), Origin: "CLI", AmzTarget: "AmazonQDeveloperStreamingService.SendMessage", Name: "AmazonQ", From e7cd7b524324a85748467b75a5ed98279d22344c Mon Sep 17 00:00:00 2001 From: taetaetae Date: Fri, 30 Jan 2026 21:52:02 +0900 Subject: [PATCH 3/3] fix: Support separate OIDC and API regions via ProfileARN extraction Address @Xm798's feedback: OIDC region may differ from API region in some Enterprise setups (e.g., OIDC in us-east-2, API in us-east-1). Region priority (highest to lowest): 1. api_region - explicit override for API endpoint region 2. ProfileARN - extract region from arn:aws:service:REGION:account:resource 3. region - OIDC/Identity region (fallback) 4. us-east-1 - default Changes: - Add extractRegionFromProfileARN() to parse region from ARN - Update getKiroEndpointConfigs() with 4-level region priority - Add regionSource logging for debugging --- internal/runtime/executor/kiro_executor.go | 48 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/internal/runtime/executor/kiro_executor.go b/internal/runtime/executor/kiro_executor.go index 35bbd03f..cf09c9ef 100644 --- a/internal/runtime/executor/kiro_executor.go +++ b/internal/runtime/executor/kiro_executor.go @@ -338,6 +338,20 @@ type kiroEndpointConfig struct { // Used when no region is specified in auth metadata. const kiroDefaultRegion = "us-east-1" +// extractRegionFromProfileARN extracts the AWS region from a ProfileARN. +// ARN format: arn:aws:codewhisperer:REGION:ACCOUNT:profile/PROFILE_ID +// Returns empty string if region cannot be extracted. +func extractRegionFromProfileARN(profileArn string) string { + if profileArn == "" { + return "" + } + parts := strings.Split(profileArn, ":") + if len(parts) >= 4 && parts[3] != "" { + return parts[3] + } + return "" +} + // buildKiroEndpointConfigs creates endpoint configurations for the specified region. // This enables dynamic region support for Enterprise/IdC users in non-us-east-1 regions. // @@ -377,23 +391,49 @@ func buildKiroEndpointConfigs(region string) []kiroEndpointConfig { var kiroEndpointConfigs = buildKiroEndpointConfigs(kiroDefaultRegion) // getKiroEndpointConfigs returns the list of Kiro API endpoint configurations to try in order. -// Supports dynamic region based on auth metadata "region" field. +// Supports dynamic region based on auth metadata "api_region", "profile_arn", or "region" field. // Supports reordering based on "preferred_endpoint" in auth metadata/attributes. // For IDC auth method, automatically uses CodeWhisperer endpoint with CLI origin. +// +// Region priority: +// 1. auth.Metadata["api_region"] - explicit API region override +// 2. ProfileARN region - extracted from arn:aws:service:REGION:account:resource +// 3. auth.Metadata["region"] - OIDC/Identity region (may differ from API region) +// 4. kiroDefaultRegion (us-east-1) - fallback func getKiroEndpointConfigs(auth *cliproxyauth.Auth) []kiroEndpointConfig { if auth == nil { return kiroEndpointConfigs } - // Extract region from auth metadata, fallback to default + // Determine API region with priority: api_region > profile_arn > region > default region := kiroDefaultRegion + regionSource := "default" + if auth.Metadata != nil { - if r, ok := auth.Metadata["region"].(string); ok && r != "" { + // Priority 1: Explicit api_region override + if r, ok := auth.Metadata["api_region"].(string); ok && r != "" { region = r - log.Debugf("kiro: using region from auth metadata: %s", region) + regionSource = "api_region" + } else { + // Priority 2: Extract from ProfileARN + if profileArn, ok := auth.Metadata["profile_arn"].(string); ok && profileArn != "" { + if arnRegion := extractRegionFromProfileARN(profileArn); arnRegion != "" { + region = arnRegion + regionSource = "profile_arn" + } + } + // Priority 3: OIDC region (only if not already set from profile_arn) + if regionSource == "default" { + if r, ok := auth.Metadata["region"].(string); ok && r != "" { + region = r + regionSource = "region" + } + } } } + log.Debugf("kiro: using region %s (source: %s)", region, regionSource) + // Build endpoint configs for the specified region endpointConfigs := buildKiroEndpointConfigs(region)