diff --git a/open-sse/config/providers.js b/open-sse/config/providers.js index 1dbc3df7..fbe4b769 100644 --- a/open-sse/config/providers.js +++ b/open-sse/config/providers.js @@ -195,7 +195,19 @@ export const PROVIDERS = { clientId: "Iv1.b507a08c87ecfe98" }, kiro: { - baseUrl: "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse", + // All three hosts resolve to the same regional CodeWhisperer streaming service + // (GenerateAssistantResponse). They are alternate DNS surfaces, NOT separate quota + // buckets — AWS throttles per authenticated identity (token + profileArn), not per + // hostname. Listing them enables edge-level failover (5xx / connect timeout / a + // degraded surface); it does NOT multiply 429 headroom. To actually spread 429 load, + // add multiple Kiro accounts — account rotation in sse/handlers/chat.js handles that. + // Order: newest Kiro IDE endpoint first, legacy AWS domains as fallback. + baseUrl: "https://runtime.us-east-1.kiro.dev/generateAssistantResponse", + baseUrls: [ + "https://runtime.us-east-1.kiro.dev/generateAssistantResponse", + "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse", + "https://q.us-east-1.amazonaws.com/generateAssistantResponse", + ], format: "kiro", retry: { 429: 2 }, headers: { diff --git a/open-sse/executors/kiro.js b/open-sse/executors/kiro.js index 7af3f3f0..47aba379 100644 --- a/open-sse/executors/kiro.js +++ b/open-sse/executors/kiro.js @@ -2,8 +2,6 @@ import { BaseExecutor } from "./base.js"; import { PROVIDERS } from "../config/providers.js"; import { v4 as uuidv4 } from "uuid"; import { refreshKiroToken } from "../services/tokenRefresh.js"; -import { proxyAwareFetch } from "../utils/proxyFetch.js"; -import { HTTP_STATUS, RETRY_CONFIG, DEFAULT_RETRY_CONFIG, resolveRetryEntry } from "../config/runtimeConfig.js"; /** * KiroExecutor - Executor for Kiro AI (AWS CodeWhisperer) @@ -33,45 +31,25 @@ export class KiroExecutor extends BaseExecutor { } /** - * Custom execute for Kiro - handles AWS EventStream binary response with retry support + * Kiro execute — delegate to BaseExecutor for endpoint fallback + retry, then + * transform the binary AWS EventStream into OpenAI-shaped SSE on success. + * + * BaseExecutor.execute() walks config.baseUrls (runtime.us-east-1.kiro.dev → + * codewhisperer → q) advancing to the next host on 429 (shouldRetry) and on + * network/5xx errors, while tryRetry handles in-place retries per `retry: {429: 2}`. + * Note: the baseUrls are alternate surfaces of one regional service, so rotation + * is edge-level failover — it does not grant fresh 429 quota. Per-account 429 + * spreading is handled upstream by account rotation in sse/handlers/chat.js. + * + * Errors are returned untransformed so the upstream handler can read the body, + * classify the status, and trigger account fallback/cooldown. */ - async execute({ model, body, stream, credentials, signal, log, proxyOptions = null }) { - const url = this.buildUrl(model, stream, 0); - const transformedBody = this.transformRequest(model, body, stream, credentials); - - // Merge default retry config with provider-specific config - const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...this.config.retry }; - let retryAttempts = 0; - - while (true) { - const headers = this.buildHeaders(credentials, stream); - - const response = await proxyAwareFetch(url, { - method: "POST", - headers, - body: JSON.stringify(transformedBody), - signal - }, proxyOptions); - - // Check if should retry based on status code - const { attempts: maxRetries, delayMs } = resolveRetryEntry(retryConfig[response.status]); - if (!response.ok && maxRetries > 0 && retryAttempts < maxRetries) { - retryAttempts++; - log?.debug?.("RETRY", `${response.status} retry ${retryAttempts}/${maxRetries} after ${delayMs / 1000}s`); - await new Promise(resolve => setTimeout(resolve, delayMs)); - continue; - } - - if (!response.ok) { - return { response, url, headers, transformedBody }; - } - - // Success - transform and return - // For Kiro, we need to transform the binary EventStream to SSE - // Create a TransformStream to convert binary to SSE text - const transformedResponse = this.transformEventStreamToSSE(response, model); - return { response: transformedResponse, url, headers, transformedBody }; + async execute(args) { + const result = await super.execute(args); + if (result?.response?.ok) { + result.response = this.transformEventStreamToSSE(result.response, args.model); } + return result; } /**