ns-omp-provider-kiro 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1535 -1055
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ var __esm = (fn, res, err) => function __init() {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
10
15
  };
11
16
  var __commonJS = (cb, mod) => function __require() {
12
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
17
+ try {
18
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
19
+ } catch (e) {
20
+ throw mod = 0, e;
21
+ }
13
22
  };
14
23
  var __export = (target, all) => {
15
24
  for (var name in all)
@@ -236,6 +245,12 @@ function getKiroEndpoints(region) {
236
245
  runtime: `https://runtime.${region}.kiro.dev/`
237
246
  };
238
247
  }
248
+ function getKiroRegionFromProfileArn(profileArn) {
249
+ if (!profileArn)
250
+ return void 0;
251
+ const region = profileArn.split(":")[3];
252
+ return region && /^[a-z]{2}(?:-[a-z]+)+-\d$/.test(region) ? region : void 0;
253
+ }
239
254
  function getKiroRegionFromEndpoint(endpoint) {
240
255
  try {
241
256
  const [service, region, ...suffix] = new URL(endpoint).hostname.split(".");
@@ -258,6 +273,7 @@ var init_endpoints = __esm({
258
273
  "ap-southeast-1": "us-east-1",
259
274
  "ap-southeast-2": "us-east-1",
260
275
  "ap-northeast-1": "us-east-1",
276
+ "ap-northeast-2": "us-east-1",
261
277
  "ap-south-1": "us-east-1",
262
278
  "eu-west-1": "eu-central-1",
263
279
  "eu-west-2": "eu-central-1",
@@ -633,779 +649,337 @@ var init_kiro_ide = __esm({
633
649
  }
634
650
  });
635
651
 
636
- // ../kiro-core/dist/models.js
637
- var models_exports = {};
638
- __export(models_exports, {
639
- KIRO_MANAGEMENT_CACHE_PATH: () => KIRO_MANAGEMENT_CACHE_PATH,
640
- KIRO_MANAGEMENT_CACHE_SOURCE: () => KIRO_MANAGEMENT_CACHE_SOURCE,
641
- KIRO_MANAGEMENT_CACHE_VERSION: () => KIRO_MANAGEMENT_CACHE_VERSION,
642
- KIRO_MODEL_IDS: () => KIRO_MODEL_IDS,
643
- applyEffortLadder: () => applyEffortLadder,
644
- getCachedModels: () => getCachedModels,
645
- isCacheStale: () => isCacheStale,
646
- kiroModels: () => kiroModels,
647
- loadCachedModelIds: () => loadCachedModelIds,
648
- mapKiroCatalogModels: () => mapKiroCatalogModels,
649
- resolveApiRegion: () => resolveApiRegion,
650
- resolveKiroModel: () => resolveKiroModel,
651
- updateKiroModelsCache: () => updateKiroModelsCache
652
- });
653
- import { randomUUID } from "node:crypto";
654
- import { existsSync as existsSync3, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync } from "node:fs";
655
- import { homedir as homedir4 } from "node:os";
656
- import { join as join4 } from "node:path";
657
- function isRecord2(value) {
658
- return typeof value === "object" && value !== null && !Array.isArray(value);
659
- }
660
- function isPositiveNumber(value) {
661
- return typeof value === "number" && Number.isFinite(value) && value > 0;
662
- }
663
- function isEffortList(value) {
664
- return Array.isArray(value) && value.length > 0 && value.every((effort) => KIRO_EFFORT_ORDER.includes(effort));
652
+ // ../kiro-core/dist/oauth.js
653
+ function kiroUserAgent(service, sdkVersion) {
654
+ return {
655
+ "User-Agent": `aws-sdk-js/3.714.0 os/macos/24.3.0 lang/js md/nodejs/22.14.0 api/${service}/3.714.0 exec-env/kiro-cli/2.7.0 m/E`,
656
+ "amz-sdk-invocation-id": "00000000-0000-0000-0000-000000000000",
657
+ "amz-sdk-request": `attempt=1; max=${sdkVersion}`
658
+ };
665
659
  }
666
- function isEffortMap(value) {
667
- return isRecord2(value) && Object.values(value).every((mapped) => typeof mapped === "string");
660
+ function kiroAuthHeaders(token) {
661
+ const headers = { Authorization: `Bearer ${token}` };
662
+ if (isApiKey(token))
663
+ headers.tokentype = "API_KEY";
664
+ return headers;
668
665
  }
669
- function isCachedKiroModel(value) {
670
- if (!isRecord2(value))
671
- return false;
672
- const cost = value.cost;
673
- const input = value.input;
674
- const schema = value.additionalModelRequestFieldsSchema;
675
- const tokenLimits = value.tokenLimits;
676
- return typeof value.id === "string" && value.id.length > 0 && typeof value.kiroModelId === "string" && value.kiroModelId.length > 0 && typeof value.name === "string" && value.name.length > 0 && typeof value.reasoning === "boolean" && Array.isArray(input) && input.length > 0 && input.every((modality) => modality === "text" || modality === "image") && isRecord2(cost) && typeof cost.input === "number" && typeof cost.output === "number" && typeof cost.cacheRead === "number" && typeof cost.cacheWrite === "number" && isPositiveNumber(value.contextWindow) && isPositiveNumber(value.maxTokens) && (value.efforts === void 0 || isEffortList(value.efforts)) && (value.effortMap === void 0 || isEffortMap(value.effortMap)) && (schema === void 0 || isRecord2(schema)) && (tokenLimits === void 0 || isRecord2(tokenLimits)) && (value.firstTokenTimeout === void 0 || isPositiveNumber(value.firstTokenTimeout)) && (value.rateMultiplier === void 0 || isPositiveNumber(value.rateMultiplier)) && (value.rateUnit === void 0 || typeof value.rateUnit === "string");
666
+ function isApiKey(token) {
667
+ return token.startsWith("ksk_");
677
668
  }
678
- function parseManagementCache(raw) {
679
- let value;
680
- try {
681
- value = JSON.parse(raw);
682
- } catch {
683
- return void 0;
684
- }
685
- if (!isRecord2(value) || value.version !== KIRO_MANAGEMENT_CACHE_VERSION || value.source !== KIRO_MANAGEMENT_CACHE_SOURCE || !isRecord2(value.regions)) {
686
- return void 0;
669
+ async function loginKiroWithApiKey(apiKey, onProgress) {
670
+ if (!apiKey.startsWith("ksk_")) {
671
+ throw new Error("Invalid API key format. Kiro API keys start with 'ksk_'.");
687
672
  }
688
- const regions = {};
689
- for (const [region, rawEntry] of Object.entries(value.regions)) {
690
- if (!isRecord2(rawEntry) || rawEntry.region !== region || !isPositiveNumber(rawEntry.fetchedAt) || !Array.isArray(rawEntry.models) || rawEntry.models.length === 0 || !rawEntry.models.every(isCachedKiroModel)) {
691
- return void 0;
673
+ onProgress?.("Validating API key...");
674
+ const region = "us-east-1";
675
+ const managementUrl = `https://management.${resolveApiRegion(region)}.kiro.dev/`;
676
+ const response = await fetch(managementUrl, {
677
+ method: "POST",
678
+ headers: {
679
+ "Content-Type": "application/x-amz-json-1.0",
680
+ "X-Amz-Target": "AmazonCodeWhispererService.GetProfile",
681
+ ...kiroAuthHeaders(apiKey),
682
+ ...kiroUserAgent("codewhispererruntime", "F,C")
683
+ },
684
+ body: "{}"
685
+ });
686
+ if (!response.ok) {
687
+ let detail = "";
688
+ try {
689
+ detail = await response.text();
690
+ } catch {
691
+ detail = "";
692
692
  }
693
- const modelIds = /* @__PURE__ */ new Set();
694
- for (const model of rawEntry.models) {
695
- if (modelIds.has(model.id))
696
- return void 0;
697
- modelIds.add(model.id);
693
+ if (response.status === 401 || response.status === 403 || /Invalid token/i.test(detail)) {
694
+ throw new Error("API key was rejected by Kiro. Check that the key is valid and not expired.");
698
695
  }
699
- regions[region] = rawEntry;
696
+ throw new Error(`Kiro GetProfile failed: ${response.status} ${response.statusText} ${detail}`.trim());
700
697
  }
698
+ const data = await response.json();
699
+ const profileArn = data.profile?.arn;
701
700
  return {
702
- version: KIRO_MANAGEMENT_CACHE_VERSION,
703
- source: KIRO_MANAGEMENT_CACHE_SOURCE,
704
- regions
701
+ access: apiKey,
702
+ refresh: `${apiKey}|apikey`,
703
+ expires: Date.now() + 365 * 24 * 60 * 60 * 1e3,
704
+ clientId: "",
705
+ clientSecret: "",
706
+ region,
707
+ authMethod: "apikey",
708
+ ...profileArn ? { profileArn } : {}
705
709
  };
706
710
  }
707
- function readManagementCache() {
708
- if (!existsSync3(KIRO_MANAGEMENT_CACHE_PATH))
709
- return void 0;
710
- try {
711
- return parseManagementCache(readFileSync2(KIRO_MANAGEMENT_CACHE_PATH, "utf-8"));
712
- } catch {
713
- return void 0;
711
+ async function refreshKiroToken(credentials) {
712
+ const refreshed = await refreshKiroTokenInternal(credentials);
713
+ if (!process.env.VITEST) {
714
+ try {
715
+ const { updateKiroModelsCache: updateKiroModelsCache2 } = await Promise.resolve().then(() => (init_models(), models_exports));
716
+ const region = resolveApiRegion(refreshed.region);
717
+ updateKiroModelsCache2(refreshed.access, region, refreshed.profileArn).catch((error2) => {
718
+ console.warn(`[kiro-core] Failed to refresh Kiro model catalog in ${region}: ${formatSafeError(error2)}`);
719
+ });
720
+ } catch (error2) {
721
+ console.warn(`[kiro-core] Failed to start Kiro model catalog refresh: ${formatSafeError(error2)}`);
722
+ }
714
723
  }
724
+ return refreshed;
715
725
  }
716
- function writeManagementCache(cache) {
717
- const temporaryPath = `${KIRO_MANAGEMENT_CACHE_PATH}.${process.pid}.${randomUUID()}.tmp`;
726
+ async function refreshKiroTokenInternal(credentials) {
727
+ const { getKiroCliCredentials: getKiroCliCredentials2, getKiroCliCredentialsAllowExpired: getKiroCliCredentialsAllowExpired2, saveKiroCliCredentials: saveKiroCliCredentials2, getKiroCliSocialToken: getKiroCliSocialToken2, getKiroCliSocialTokenAllowExpired: getKiroCliSocialTokenAllowExpired2 } = await Promise.resolve().then(() => (init_kiro_cli(), kiro_cli_exports));
728
+ const credentialAuthMethod = credentials.authMethod ?? (credentials.refresh.split("|").at(-1) === "desktop" ? "desktop" : "idc");
729
+ const getValidCliCredentials = () => {
730
+ if (credentialAuthMethod === "desktop")
731
+ return getKiroCliSocialToken2();
732
+ const cliCreds = getKiroCliCredentials2();
733
+ return cliCreds?.authMethod === "idc" ? cliCreds : void 0;
734
+ };
735
+ const getExpiredCliCredentials = () => {
736
+ if (credentialAuthMethod === "desktop")
737
+ return getKiroCliSocialTokenAllowExpired2();
738
+ const cliCreds = getKiroCliCredentialsAllowExpired2();
739
+ return cliCreds?.authMethod === "idc" ? cliCreds : void 0;
740
+ };
741
+ if (credentials.authMethod === "apikey" || isApiKey(credentials.access))
742
+ return credentials;
743
+ if (credentialAuthMethod === "idc") {
744
+ const ideCreds = getKiroIdeCredentials();
745
+ if (ideCreds)
746
+ return ideCreds;
747
+ }
748
+ const preCheckCreds = getValidCliCredentials();
749
+ if (preCheckCreds)
750
+ return preCheckCreds;
718
751
  try {
719
- writeFileSync(temporaryPath, JSON.stringify(cache, null, 2), "utf-8");
720
- renameSync(temporaryPath, KIRO_MANAGEMENT_CACHE_PATH);
721
- } finally {
722
- rmSync(temporaryPath, { force: true });
752
+ const refreshed = await refreshKiroTokenDirect(credentials);
753
+ saveKiroCliCredentials2(refreshed);
754
+ return refreshed;
755
+ } catch (refreshError) {
756
+ const retryCreds = getValidCliCredentials();
757
+ if (retryCreds)
758
+ return retryCreds;
759
+ const expiredCliCreds = getExpiredCliCredentials();
760
+ if (expiredCliCreds && expiredCliCreds.refresh !== credentials.refresh) {
761
+ try {
762
+ const refreshedFromCli = await refreshKiroTokenDirect(expiredCliCreds);
763
+ saveKiroCliCredentials2(refreshedFromCli);
764
+ return refreshedFromCli;
765
+ } catch {
766
+ }
767
+ }
768
+ const actualExpiry = credentials.expires + EXPIRES_BUFFER_MS;
769
+ if (credentials.access && Date.now() < actualExpiry) {
770
+ return { ...credentials, expires: actualExpiry };
771
+ }
772
+ throw refreshError;
723
773
  }
724
774
  }
725
- function toLocalModelId(kiroModelId) {
726
- return kiroModelId.replace(/(\d)\.(\d)/g, "$1-$2");
727
- }
728
- function humanizeModelId(modelId) {
729
- return modelId.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
730
- }
731
- function applyEffortLadder(config) {
732
- if (!config || config.values.length === 0)
733
- return {};
734
- const efforts = KIRO_EFFORT_ORDER.filter((effort) => config.values.includes(effort));
735
- if (efforts.length === 0)
736
- return {};
737
- return { efforts, ...config.summarizedThinking ? { supportsSummarizedThinking: true } : {} };
738
- }
739
- function hasReasoningFamilyFallback(modelId) {
740
- const normalizedId = modelId.toLowerCase();
741
- return normalizedId === "auto" || REASONING_FAMILY_MARKERS.some((marker) => normalizedId.includes(marker));
742
- }
743
- function hasVerifiedImageInput(kiroModelId) {
744
- return kiroModelId.startsWith("claude-") || VERIFIED_IMAGE_MODEL_IDS.has(kiroModelId.toLowerCase());
745
- }
746
- function applyVerifiedCapabilities(model) {
747
- if (!hasVerifiedImageInput(model.kiroModelId) || model.input.includes("image"))
748
- return model;
749
- return { ...model, input: ["text", "image"] };
750
- }
751
- function validateCatalogMetadata(model) {
752
- const rawSchema = model.additionalModelRequestFieldsSchema;
753
- const schema = rawSchema ?? void 0;
754
- if (schema !== void 0 && !isRecord2(schema)) {
755
- throw new Error(`Kiro management catalog model ${model.modelId} has an invalid request-fields schema`);
756
- }
757
- const tokenLimits = model.tokenLimits;
758
- if (tokenLimits !== void 0 && !isRecord2(tokenLimits)) {
759
- throw new Error(`Kiro management catalog model ${model.modelId} has invalid token limits`);
760
- }
761
- if (tokenLimits && (tokenLimits.maxInputTokens !== void 0 && !isPositiveNumber(tokenLimits.maxInputTokens) || tokenLimits.maxOutputTokens !== void 0 && !isPositiveNumber(tokenLimits.maxOutputTokens))) {
762
- throw new Error(`Kiro management catalog model ${model.modelId} has invalid token limits`);
775
+ async function refreshKiroTokenDirect(credentials) {
776
+ const parts = credentials.refresh.split("|");
777
+ const refreshToken = parts[0] ?? "";
778
+ const authMethod = parts[parts.length - 1] ?? "idc";
779
+ const region = credentials.region || "us-east-1";
780
+ if (authMethod === "apikey")
781
+ return credentials;
782
+ if (authMethod === "desktop") {
783
+ const url = KIRO_DESKTOP_REFRESH_URL.replace("{region}", region);
784
+ const response2 = await fetch(url, {
785
+ method: "POST",
786
+ headers: { "Content-Type": "application/json", "User-Agent": KIRO_DESKTOP_USER_AGENT },
787
+ body: JSON.stringify({ refreshToken })
788
+ });
789
+ if (!response2.ok)
790
+ throw new Error(`Desktop token refresh failed: ${response2.status}`);
791
+ const data2 = await response2.json();
792
+ if (!data2.accessToken)
793
+ throw new Error("Desktop token refresh: missing accessToken");
794
+ return {
795
+ refresh: `${data2.refreshToken || refreshToken}|desktop`,
796
+ access: data2.accessToken,
797
+ expires: Date.now() + data2.expiresIn * 1e3 - EXPIRES_BUFFER_MS,
798
+ clientId: "",
799
+ clientSecret: "",
800
+ region,
801
+ authMethod: "desktop",
802
+ profileArn: data2.profileArn || credentials.profileArn,
803
+ startUrl: credentials.startUrl
804
+ };
763
805
  }
764
- return { schema, tokenLimits };
765
- }
766
- function mapKiroCatalogModels(catalogModels, region, rates) {
767
- if (catalogModels.length === 0) {
768
- throw new Error(`Kiro management catalog returned no models in ${region}`);
769
- }
770
- const seenIds = /* @__PURE__ */ new Set();
771
- return catalogModels.map((catalogModel) => {
772
- const kiroModelId = catalogModel.modelId;
773
- if (!kiroModelId || kiroModelId.trim() !== kiroModelId) {
774
- throw new Error(`Kiro management catalog returned an invalid model ID in ${region}`);
775
- }
776
- const id = toLocalModelId(kiroModelId);
777
- if (seenIds.has(id)) {
778
- throw new Error(`Kiro management catalog contains conflicting model ID ${id} in ${region}`);
779
- }
780
- seenIds.add(id);
781
- const existing = kiroModels.find((model) => model.id === id);
782
- const rate = rates?.get(kiroModelId);
783
- const { schema, tokenLimits } = validateCatalogMetadata(catalogModel);
784
- const effortConfig = getKiroEffortConfig(schema, kiroModelId);
785
- const catalogName = typeof catalogModel.displayName === "string" && catalogModel.displayName.length > 0 ? catalogModel.displayName : void 0;
806
+ if (authMethod === "external-idp") {
807
+ const idpClientId = parts[1] ?? "";
808
+ const tokenEndpoint = parts[2] ?? "";
809
+ if (!tokenEndpoint)
810
+ throw new Error("External IdP token refresh: missing token endpoint");
811
+ const response2 = await fetch(tokenEndpoint, {
812
+ method: "POST",
813
+ headers: {
814
+ "Content-Type": "application/x-www-form-urlencoded",
815
+ Accept: "application/json",
816
+ "User-Agent": "kiro-core"
817
+ },
818
+ body: new URLSearchParams({
819
+ grant_type: "refresh_token",
820
+ client_id: idpClientId,
821
+ refresh_token: refreshToken
822
+ }).toString()
823
+ });
824
+ if (!response2.ok)
825
+ throw new Error(`External IdP token refresh failed: ${response2.status}`);
826
+ const data2 = await response2.json();
827
+ if (!data2.access_token)
828
+ throw new Error("External IdP token refresh: missing access_token");
829
+ const expiresIn = typeof data2.expires_in === "number" ? data2.expires_in : 3600;
786
830
  return {
787
- id,
788
- kiroModelId,
789
- name: catalogName ?? existing?.name ?? humanizeModelId(id),
831
+ refresh: `${data2.refresh_token || refreshToken}|${idpClientId}|${tokenEndpoint}|external-idp`,
832
+ access: data2.access_token,
833
+ expires: Date.now() + expiresIn * 1e3 - EXPIRES_BUFFER_MS,
834
+ clientId: idpClientId,
835
+ clientSecret: "",
790
836
  region,
791
- // Deliberately schema-only: when a schema exists the resolver returns
792
- // `deriveKiroEffort(schema)`, and when it does not the family-marker guess
793
- // decides. The fallback tier feeds the ladders, not this flag.
794
- reasoning: schema !== void 0 && effortConfig !== void 0 || schema === void 0 && hasReasoningFamilyFallback(id),
795
- ...applyEffortLadder(effortConfig),
796
- input: existing ? [...existing.input] : hasVerifiedImageInput(kiroModelId) ? ["text", "image"] : ["text"],
797
- ...id.startsWith("claude-") ? { recoverTextToolCalls: false } : {},
798
- cost: ZERO_COST,
799
- ...rate ? { rateMultiplier: rate.multiplier, ...rate.unit ? { rateUnit: rate.unit } : {} } : {},
800
- contextWindow: tokenLimits?.maxInputTokens ?? DEFAULT_CONTEXT_WINDOW,
801
- maxTokens: tokenLimits?.maxOutputTokens ?? DEFAULT_MAX_TOKENS,
802
- ...existing?.firstTokenTimeout ? { firstTokenTimeout: existing.firstTokenTimeout } : {},
803
- ...schema ? { additionalModelRequestFieldsSchema: schema } : {},
804
- ...tokenLimits ? { tokenLimits } : {}
837
+ authMethod: "external-idp",
838
+ profileArn: credentials.profileArn
805
839
  };
840
+ }
841
+ const clientId = parts[1] ?? "";
842
+ const clientSecret = parts[2] ?? "";
843
+ const ssoEndpoint = `https://oidc.${region}.amazonaws.com`;
844
+ const response = await fetch(`${ssoEndpoint}/token`, {
845
+ method: "POST",
846
+ headers: { "Content-Type": "application/json", ...kiroUserAgent("ssooidc", "E") },
847
+ body: JSON.stringify({ clientId, clientSecret, refreshToken, grantType: "refresh_token" })
806
848
  });
849
+ if (!response.ok)
850
+ throw new Error(`Token refresh failed: ${response.status}`);
851
+ const data = await response.json();
852
+ return {
853
+ refresh: `${data.refreshToken}|${clientId}|${clientSecret}|idc`,
854
+ access: data.accessToken,
855
+ expires: Date.now() + data.expiresIn * 1e3 - EXPIRES_BUFFER_MS,
856
+ clientId,
857
+ clientSecret,
858
+ region,
859
+ authMethod: "idc",
860
+ profileArn: credentials.profileArn,
861
+ startUrl: credentials.startUrl,
862
+ isEnterprise: credentials.isEnterprise
863
+ };
807
864
  }
808
- function refreshKnownModelIds(cache) {
809
- KIRO_MODEL_IDS.clear();
810
- for (const modelId of BOOTSTRAP_KIRO_MODEL_IDS)
811
- KIRO_MODEL_IDS.add(modelId);
812
- if (!cache)
813
- return;
814
- for (const entry of Object.values(cache.regions)) {
815
- for (const model of entry.models)
816
- KIRO_MODEL_IDS.add(model.kiroModelId);
817
- }
865
+ async function resolveKiroCredentials() {
866
+ const { getKiroCliCredentials: getKiroCliCredentials2, getKiroCliCredentialsAllowExpired: getKiroCliCredentialsAllowExpired2 } = await Promise.resolve().then(() => (init_kiro_cli(), kiro_cli_exports));
867
+ const fresh = getKiroCliCredentials2() ?? getKiroIdeCredentials();
868
+ if (fresh)
869
+ return fresh;
870
+ const stale = getKiroCliCredentialsAllowExpired2();
871
+ if (!stale)
872
+ return void 0;
873
+ return refreshKiroToken(stale);
818
874
  }
819
- function loadCachedModelIds() {
820
- refreshKnownModelIds(readManagementCache());
875
+ var KIRO_DESKTOP_REFRESH_URL, EXPIRES_BUFFER_MS, KIRO_DESKTOP_USER_AGENT;
876
+ var init_oauth = __esm({
877
+ "../kiro-core/dist/oauth.js"() {
878
+ "use strict";
879
+ init_debug();
880
+ init_endpoints();
881
+ init_kiro_ide();
882
+ KIRO_DESKTOP_REFRESH_URL = "https://prod.{region}.auth.desktop.kiro.dev/refreshToken";
883
+ EXPIRES_BUFFER_MS = 5 * 60 * 1e3;
884
+ KIRO_DESKTOP_USER_AGENT = "Kiro-Desktop/0.2.13 (darwin; arm64)";
885
+ }
886
+ });
887
+
888
+ // ../kiro-core/dist/token-type.js
889
+ function isExternalIdpAccessToken(accessToken) {
890
+ if (typeof accessToken !== "string")
891
+ return false;
892
+ const segments = accessToken.split(".");
893
+ if (segments.length !== 3)
894
+ return false;
895
+ const payloadSegment = segments[1];
896
+ if (!payloadSegment)
897
+ return false;
898
+ try {
899
+ const payload = JSON.parse(Buffer.from(payloadSegment.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf-8"));
900
+ return payload.aud === EXTERNAL_IDP_AUDIENCE;
901
+ } catch {
902
+ return false;
903
+ }
821
904
  }
822
- function getCachedModels(region) {
823
- const cache = readManagementCache();
824
- refreshKnownModelIds(cache);
825
- const models = cache?.regions[region]?.models ?? kiroModels;
826
- let changed = false;
827
- const corrected = models.map((model) => {
828
- const result = applyVerifiedCapabilities(model);
829
- if (result !== model)
830
- changed = true;
831
- return result;
832
- });
833
- return changed ? corrected : models;
905
+ function kiroTokenTypeHeaders(accessToken) {
906
+ return isExternalIdpAccessToken(accessToken) ? { tokentype: "EXTERNAL_IDP" } : {};
834
907
  }
835
- function isCacheStale(region) {
836
- const entry = readManagementCache()?.regions[region];
837
- return !entry || Date.now() - entry.fetchedAt > CACHE_MAX_AGE_MS;
908
+ var EXTERNAL_IDP_AUDIENCE;
909
+ var init_token_type = __esm({
910
+ "../kiro-core/dist/token-type.js"() {
911
+ "use strict";
912
+ EXTERNAL_IDP_AUDIENCE = "api://kiro";
913
+ }
914
+ });
915
+
916
+ // ../kiro-core/dist/management.js
917
+ import { createHash } from "node:crypto";
918
+ function candidateManagementRegions(primary) {
919
+ const seen = /* @__PURE__ */ new Set([primary]);
920
+ const candidates = [primary];
921
+ for (const region of CANONICAL_MANAGEMENT_REGIONS) {
922
+ if (!seen.has(region)) {
923
+ seen.add(region);
924
+ candidates.push(region);
925
+ }
926
+ }
927
+ return candidates;
838
928
  }
839
- async function updateKiroModelsCache(accessToken, region, profileArn) {
840
- const response = await fetchKiroModelCatalog({ accessToken, region }, profileArn);
841
- const models = mapKiroCatalogModels(response.models, region, getKiroCliModelRates());
842
- const cache = readManagementCache() ?? {
843
- version: KIRO_MANAGEMENT_CACHE_VERSION,
844
- source: KIRO_MANAGEMENT_CACHE_SOURCE,
845
- regions: {}
929
+ async function requestManagement(auth, operation, path, method, body) {
930
+ const url = new URL(path, getKiroEndpoints(auth.region).management);
931
+ const request = {
932
+ method,
933
+ headers: {
934
+ Accept: "application/json",
935
+ ...kiroAuthHeaders(auth.accessToken),
936
+ ...kiroTokenTypeHeaders(auth.accessToken)
937
+ }
846
938
  };
847
- cache.regions[region] = { region, fetchedAt: Date.now(), models };
848
- writeManagementCache(cache);
849
- refreshKnownModelIds(cache);
939
+ if (method === "GET") {
940
+ for (const [name, value] of Object.entries(body)) {
941
+ if (value !== void 0)
942
+ url.searchParams.set(name, String(value));
943
+ }
944
+ } else {
945
+ request.headers = { ...request.headers, "Content-Type": "application/json" };
946
+ request.body = JSON.stringify(body);
947
+ }
948
+ let response;
949
+ try {
950
+ response = await fetch(url.toString(), request);
951
+ } catch (error2) {
952
+ throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error2 });
953
+ }
954
+ return parseManagementResponse(response, operation, auth.region);
850
955
  }
851
- function resolveKiroModel(modelId, exactKiroModelId) {
852
- if (exactKiroModelId)
853
- return exactKiroModelId;
854
- const cachedModel = Object.values(readManagementCache()?.regions ?? {}).flatMap((entry) => entry.models).find((model) => model.id === modelId);
855
- if (cachedModel) {
856
- KIRO_MODEL_IDS.add(cachedModel.kiroModelId);
857
- return cachedModel.kiroModelId;
956
+ function profileCacheKey(auth) {
957
+ const tokenHash = createHash("sha256").update(auth.accessToken).digest("base64url");
958
+ return `${auth.region}:${tokenHash}`;
959
+ }
960
+ async function getApiKeyProfileArn(accessToken) {
961
+ const operation = "GetProfile";
962
+ let response;
963
+ try {
964
+ response = await fetch(getKiroEndpoints(API_KEY_REGION).management, {
965
+ method: "POST",
966
+ headers: {
967
+ "Content-Type": "application/x-amz-json-1.0",
968
+ "X-Amz-Target": GET_PROFILE_TARGET,
969
+ ...kiroAuthHeaders(accessToken),
970
+ ...kiroUserAgent("codewhispererruntime", "F,C")
971
+ },
972
+ body: "{}"
973
+ });
974
+ } catch (error2) {
975
+ throw new Error(`Kiro management ${operation} request failed in ${API_KEY_REGION}`, { cause: error2 });
858
976
  }
859
- const bootstrapModel = kiroModels.find((model) => model.id === modelId);
860
- if (bootstrapModel)
861
- return bootstrapModel.kiroModelId;
862
- const normalizedId = modelId.replace(/(\d)-(\d)/g, "$1.$2");
863
- loadCachedModelIds();
864
- if (!KIRO_MODEL_IDS.has(normalizedId)) {
865
- throw new Error(`Unknown Kiro model ID: ${modelId}`);
977
+ const parsed = await parseManagementResponse(response, operation, API_KEY_REGION);
978
+ const arn = parsed.profile?.arn;
979
+ if (!arn) {
980
+ throw new Error(`Kiro management ${operation} returned no profile in ${API_KEY_REGION}`);
866
981
  }
867
- return normalizedId;
868
- }
869
- var KIRO_MANAGEMENT_CACHE_VERSION, KIRO_MANAGEMENT_CACHE_SOURCE, KIRO_MANAGEMENT_CACHE_PATH, CACHE_MAX_AGE_MS, DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS, ZERO_COST, REASONING_FAMILY_MARKERS, VERIFIED_IMAGE_MODEL_IDS, bootstrapKiroModels, kiroModels, BOOTSTRAP_KIRO_MODEL_IDS, KIRO_MODEL_IDS;
870
- var init_models = __esm({
871
- "../kiro-core/dist/models.js"() {
872
- "use strict";
873
- init_effort();
874
- init_kiro_cli();
875
- init_management();
876
- init_types();
877
- init_endpoints();
878
- KIRO_MANAGEMENT_CACHE_VERSION = 1;
879
- KIRO_MANAGEMENT_CACHE_SOURCE = "ns-kiro-provider-management";
880
- KIRO_MANAGEMENT_CACHE_PATH = join4(homedir4(), ".ns-kiro-provider-models-cache.json");
881
- CACHE_MAX_AGE_MS = 36e5;
882
- DEFAULT_CONTEXT_WINDOW = 2e5;
883
- DEFAULT_MAX_TOKENS = 8192;
884
- ZERO_COST = Object.freeze({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
885
- REASONING_FAMILY_MARKERS = ["opus", "sonnet", "fable", "coder", "deepseek", "gpt", "glm", "qwen"];
886
- VERIFIED_IMAGE_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.6-luna"]);
887
- bootstrapKiroModels = [
888
- {
889
- id: "claude-opus-5",
890
- kiroModelId: "claude-opus-5",
891
- name: "Claude Opus 5",
892
- reasoning: true,
893
- input: ["text", "image"],
894
- cost: ZERO_COST,
895
- contextWindow: 1e6,
896
- maxTokens: 128e3,
897
- firstTokenTimeout: 18e4
898
- },
899
- {
900
- id: "claude-opus-4-8",
901
- kiroModelId: "claude-opus-4.8",
902
- name: "Claude Opus 4.8",
903
- reasoning: true,
904
- input: ["text", "image"],
905
- cost: ZERO_COST,
906
- contextWindow: 1e6,
907
- maxTokens: 128e3,
908
- firstTokenTimeout: 18e4
909
- },
910
- {
911
- id: "claude-opus-4-7",
912
- kiroModelId: "claude-opus-4.7",
913
- name: "Claude Opus 4.7",
914
- reasoning: true,
915
- input: ["text", "image"],
916
- cost: ZERO_COST,
917
- contextWindow: 1e6,
918
- maxTokens: 128e3,
919
- firstTokenTimeout: 18e4
920
- },
921
- {
922
- id: "claude-opus-4-6",
923
- kiroModelId: "claude-opus-4.6",
924
- name: "Claude Opus 4.6",
925
- reasoning: true,
926
- input: ["text", "image"],
927
- cost: ZERO_COST,
928
- contextWindow: 1e6,
929
- maxTokens: 32768
930
- },
931
- {
932
- id: "claude-opus-4-5",
933
- kiroModelId: "claude-opus-4.5",
934
- name: "Claude Opus 4.5",
935
- reasoning: true,
936
- input: ["text", "image"],
937
- cost: ZERO_COST,
938
- contextWindow: 2e5,
939
- maxTokens: 64e3
940
- },
941
- {
942
- id: "claude-sonnet-5",
943
- kiroModelId: "claude-sonnet-5",
944
- name: "Claude Sonnet 5",
945
- reasoning: true,
946
- input: ["text", "image"],
947
- cost: ZERO_COST,
948
- contextWindow: 1e6,
949
- maxTokens: 65536
950
- },
951
- {
952
- id: "claude-sonnet-4-6",
953
- kiroModelId: "claude-sonnet-4.6",
954
- name: "Claude Sonnet 4.6",
955
- reasoning: true,
956
- input: ["text", "image"],
957
- cost: ZERO_COST,
958
- contextWindow: 1e6,
959
- maxTokens: 65536
960
- },
961
- {
962
- id: "claude-sonnet-4-5",
963
- kiroModelId: "claude-sonnet-4.5",
964
- name: "Claude Sonnet 4.5",
965
- reasoning: true,
966
- input: ["text", "image"],
967
- cost: ZERO_COST,
968
- contextWindow: 2e5,
969
- maxTokens: 65536
970
- },
971
- {
972
- id: "claude-sonnet-4",
973
- kiroModelId: "claude-sonnet-4",
974
- name: "Claude Sonnet 4",
975
- reasoning: true,
976
- input: ["text", "image"],
977
- cost: ZERO_COST,
978
- contextWindow: 2e5,
979
- maxTokens: 65536
980
- },
981
- {
982
- id: "claude-haiku-4-5",
983
- kiroModelId: "claude-haiku-4.5",
984
- name: "Claude Haiku 4.5",
985
- reasoning: false,
986
- input: ["text", "image"],
987
- cost: ZERO_COST,
988
- contextWindow: 2e5,
989
- maxTokens: 65536
990
- },
991
- {
992
- id: "claude-fable-5",
993
- kiroModelId: "claude-fable-5",
994
- name: "Claude Fable 5",
995
- reasoning: true,
996
- input: ["text", "image"],
997
- cost: ZERO_COST,
998
- contextWindow: 1e6,
999
- maxTokens: 65536
1000
- },
1001
- {
1002
- id: "gpt-5-6-luna",
1003
- kiroModelId: "gpt-5.6-luna",
1004
- name: "GPT-5.6 Luna",
1005
- reasoning: true,
1006
- input: ["text", "image"],
1007
- cost: ZERO_COST,
1008
- contextWindow: 272e3,
1009
- maxTokens: 128e3
1010
- },
1011
- {
1012
- id: "gpt-5-6-sol",
1013
- kiroModelId: "gpt-5.6-sol",
1014
- name: "GPT-5.6 Sol",
1015
- reasoning: true,
1016
- input: ["text"],
1017
- cost: ZERO_COST,
1018
- contextWindow: 272e3,
1019
- maxTokens: 128e3
1020
- },
1021
- {
1022
- id: "gpt-5-6-terra",
1023
- kiroModelId: "gpt-5.6-terra",
1024
- name: "GPT-5.6 Terra",
1025
- reasoning: true,
1026
- input: ["text"],
1027
- cost: ZERO_COST,
1028
- contextWindow: 272e3,
1029
- maxTokens: 128e3
1030
- },
1031
- {
1032
- id: "deepseek-3-2",
1033
- kiroModelId: "deepseek-3.2",
1034
- name: "DeepSeek 3.2",
1035
- reasoning: true,
1036
- input: ["text"],
1037
- cost: ZERO_COST,
1038
- contextWindow: 164e3,
1039
- maxTokens: 8192
1040
- },
1041
- {
1042
- id: "minimax-m2-5",
1043
- kiroModelId: "minimax-m2.5",
1044
- name: "MiniMax M2.5",
1045
- reasoning: false,
1046
- input: ["text"],
1047
- cost: ZERO_COST,
1048
- contextWindow: 196e3,
1049
- maxTokens: 8192
1050
- },
1051
- {
1052
- id: "minimax-m2-1",
1053
- kiroModelId: "minimax-m2.1",
1054
- name: "MiniMax M2.1",
1055
- reasoning: false,
1056
- input: ["text"],
1057
- cost: ZERO_COST,
1058
- contextWindow: 196e3,
1059
- maxTokens: 8192
1060
- },
1061
- {
1062
- id: "glm-5",
1063
- kiroModelId: "glm-5",
1064
- name: "GLM 5",
1065
- reasoning: true,
1066
- input: ["text"],
1067
- cost: ZERO_COST,
1068
- contextWindow: 2e5,
1069
- maxTokens: 8192
1070
- },
1071
- {
1072
- id: "qwen3-coder-next",
1073
- kiroModelId: "qwen3-coder-next",
1074
- name: "Qwen3 Coder Next",
1075
- reasoning: true,
1076
- input: ["text"],
1077
- cost: ZERO_COST,
1078
- contextWindow: 256e3,
1079
- maxTokens: 8192
1080
- },
1081
- {
1082
- id: "auto",
1083
- kiroModelId: "auto",
1084
- name: "Auto",
1085
- reasoning: true,
1086
- input: ["text", "image"],
1087
- cost: ZERO_COST,
1088
- contextWindow: 1e6,
1089
- maxTokens: 65536
1090
- }
1091
- ];
1092
- kiroModels = bootstrapKiroModels.map((model) => ({
1093
- ...model,
1094
- ...applyEffortLadder(model.reasoning ? getKiroEffortConfig(model.additionalModelRequestFieldsSchema, model.kiroModelId) : void 0),
1095
- ...model.id.startsWith("claude-") ? { recoverTextToolCalls: false } : {}
1096
- }));
1097
- BOOTSTRAP_KIRO_MODEL_IDS = kiroModels.map((model) => model.kiroModelId);
1098
- KIRO_MODEL_IDS = new Set(BOOTSTRAP_KIRO_MODEL_IDS);
1099
- }
1100
- });
1101
-
1102
- // ../kiro-core/dist/oauth.js
1103
- function kiroUserAgent(service, sdkVersion) {
1104
- return {
1105
- "User-Agent": `aws-sdk-js/3.714.0 os/macos/24.3.0 lang/js md/nodejs/22.14.0 api/${service}/3.714.0 exec-env/kiro-cli/2.7.0 m/E`,
1106
- "amz-sdk-invocation-id": "00000000-0000-0000-0000-000000000000",
1107
- "amz-sdk-request": `attempt=1; max=${sdkVersion}`
1108
- };
1109
- }
1110
- function kiroAuthHeaders(token) {
1111
- const headers = { Authorization: `Bearer ${token}` };
1112
- if (isApiKey(token))
1113
- headers.tokentype = "API_KEY";
1114
- return headers;
1115
- }
1116
- function isApiKey(token) {
1117
- return token.startsWith("ksk_");
1118
- }
1119
- async function loginKiroWithApiKey(apiKey, onProgress) {
1120
- if (!apiKey.startsWith("ksk_")) {
1121
- throw new Error("Invalid API key format. Kiro API keys start with 'ksk_'.");
1122
- }
1123
- onProgress?.("Validating API key...");
1124
- const region = "us-east-1";
1125
- const managementUrl = `https://management.${resolveApiRegion(region)}.kiro.dev/`;
1126
- const response = await fetch(managementUrl, {
1127
- method: "POST",
1128
- headers: {
1129
- "Content-Type": "application/x-amz-json-1.0",
1130
- "X-Amz-Target": "AmazonCodeWhispererService.GetProfile",
1131
- ...kiroAuthHeaders(apiKey),
1132
- ...kiroUserAgent("codewhispererruntime", "F,C")
1133
- },
1134
- body: "{}"
1135
- });
1136
- if (!response.ok) {
1137
- let detail = "";
1138
- try {
1139
- detail = await response.text();
1140
- } catch {
1141
- detail = "";
1142
- }
1143
- if (response.status === 401 || response.status === 403 || /Invalid token/i.test(detail)) {
1144
- throw new Error("API key was rejected by Kiro. Check that the key is valid and not expired.");
1145
- }
1146
- throw new Error(`Kiro GetProfile failed: ${response.status} ${response.statusText} ${detail}`.trim());
1147
- }
1148
- const data = await response.json();
1149
- const profileArn = data.profile?.arn;
1150
- return {
1151
- access: apiKey,
1152
- refresh: `${apiKey}|apikey`,
1153
- expires: Date.now() + 365 * 24 * 60 * 60 * 1e3,
1154
- clientId: "",
1155
- clientSecret: "",
1156
- region,
1157
- authMethod: "apikey",
1158
- ...profileArn ? { profileArn } : {}
1159
- };
1160
- }
1161
- async function refreshKiroToken(credentials) {
1162
- const refreshed = await refreshKiroTokenInternal(credentials);
1163
- if (!process.env.VITEST) {
1164
- try {
1165
- const { updateKiroModelsCache: updateKiroModelsCache2 } = await Promise.resolve().then(() => (init_models(), models_exports));
1166
- const region = resolveApiRegion(refreshed.region);
1167
- updateKiroModelsCache2(refreshed.access, region, refreshed.profileArn).catch((error2) => {
1168
- console.warn(`[kiro-core] Failed to refresh Kiro model catalog in ${region}: ${formatSafeError(error2)}`);
1169
- });
1170
- } catch (error2) {
1171
- console.warn(`[kiro-core] Failed to start Kiro model catalog refresh: ${formatSafeError(error2)}`);
1172
- }
1173
- }
1174
- return refreshed;
1175
- }
1176
- async function refreshKiroTokenInternal(credentials) {
1177
- const { getKiroCliCredentials: getKiroCliCredentials2, getKiroCliCredentialsAllowExpired: getKiroCliCredentialsAllowExpired2, saveKiroCliCredentials: saveKiroCliCredentials2, getKiroCliSocialToken: getKiroCliSocialToken2, getKiroCliSocialTokenAllowExpired: getKiroCliSocialTokenAllowExpired2 } = await Promise.resolve().then(() => (init_kiro_cli(), kiro_cli_exports));
1178
- const credentialAuthMethod = credentials.authMethod ?? (credentials.refresh.split("|").at(-1) === "desktop" ? "desktop" : "idc");
1179
- const getValidCliCredentials = () => {
1180
- if (credentialAuthMethod === "desktop")
1181
- return getKiroCliSocialToken2();
1182
- const cliCreds = getKiroCliCredentials2();
1183
- return cliCreds?.authMethod === "idc" ? cliCreds : void 0;
1184
- };
1185
- const getExpiredCliCredentials = () => {
1186
- if (credentialAuthMethod === "desktop")
1187
- return getKiroCliSocialTokenAllowExpired2();
1188
- const cliCreds = getKiroCliCredentialsAllowExpired2();
1189
- return cliCreds?.authMethod === "idc" ? cliCreds : void 0;
1190
- };
1191
- if (credentials.authMethod === "apikey" || isApiKey(credentials.access))
1192
- return credentials;
1193
- if (credentialAuthMethod === "idc") {
1194
- const ideCreds = getKiroIdeCredentials();
1195
- if (ideCreds)
1196
- return ideCreds;
1197
- }
1198
- const preCheckCreds = getValidCliCredentials();
1199
- if (preCheckCreds)
1200
- return preCheckCreds;
1201
- try {
1202
- const refreshed = await refreshKiroTokenDirect(credentials);
1203
- saveKiroCliCredentials2(refreshed);
1204
- return refreshed;
1205
- } catch (refreshError) {
1206
- const retryCreds = getValidCliCredentials();
1207
- if (retryCreds)
1208
- return retryCreds;
1209
- const expiredCliCreds = getExpiredCliCredentials();
1210
- if (expiredCliCreds && expiredCliCreds.refresh !== credentials.refresh) {
1211
- try {
1212
- const refreshedFromCli = await refreshKiroTokenDirect(expiredCliCreds);
1213
- saveKiroCliCredentials2(refreshedFromCli);
1214
- return refreshedFromCli;
1215
- } catch {
1216
- }
1217
- }
1218
- const actualExpiry = credentials.expires + EXPIRES_BUFFER_MS;
1219
- if (credentials.access && Date.now() < actualExpiry) {
1220
- return { ...credentials, expires: actualExpiry };
1221
- }
1222
- throw refreshError;
1223
- }
1224
- }
1225
- async function refreshKiroTokenDirect(credentials) {
1226
- const parts = credentials.refresh.split("|");
1227
- const refreshToken = parts[0] ?? "";
1228
- const authMethod = parts[parts.length - 1] ?? "idc";
1229
- const region = credentials.region || "us-east-1";
1230
- if (authMethod === "apikey")
1231
- return credentials;
1232
- if (authMethod === "desktop") {
1233
- const url = KIRO_DESKTOP_REFRESH_URL.replace("{region}", region);
1234
- const response2 = await fetch(url, {
1235
- method: "POST",
1236
- headers: { "Content-Type": "application/json", "User-Agent": KIRO_DESKTOP_USER_AGENT },
1237
- body: JSON.stringify({ refreshToken })
1238
- });
1239
- if (!response2.ok)
1240
- throw new Error(`Desktop token refresh failed: ${response2.status}`);
1241
- const data2 = await response2.json();
1242
- if (!data2.accessToken)
1243
- throw new Error("Desktop token refresh: missing accessToken");
1244
- return {
1245
- refresh: `${data2.refreshToken || refreshToken}|desktop`,
1246
- access: data2.accessToken,
1247
- expires: Date.now() + data2.expiresIn * 1e3 - EXPIRES_BUFFER_MS,
1248
- clientId: "",
1249
- clientSecret: "",
1250
- region,
1251
- authMethod: "desktop",
1252
- profileArn: data2.profileArn || credentials.profileArn,
1253
- startUrl: credentials.startUrl
1254
- };
1255
- }
1256
- if (authMethod === "external-idp") {
1257
- const idpClientId = parts[1] ?? "";
1258
- const tokenEndpoint = parts[2] ?? "";
1259
- if (!tokenEndpoint)
1260
- throw new Error("External IdP token refresh: missing token endpoint");
1261
- const response2 = await fetch(tokenEndpoint, {
1262
- method: "POST",
1263
- headers: {
1264
- "Content-Type": "application/x-www-form-urlencoded",
1265
- Accept: "application/json",
1266
- "User-Agent": "kiro-core"
1267
- },
1268
- body: new URLSearchParams({
1269
- grant_type: "refresh_token",
1270
- client_id: idpClientId,
1271
- refresh_token: refreshToken
1272
- }).toString()
1273
- });
1274
- if (!response2.ok)
1275
- throw new Error(`External IdP token refresh failed: ${response2.status}`);
1276
- const data2 = await response2.json();
1277
- if (!data2.access_token)
1278
- throw new Error("External IdP token refresh: missing access_token");
1279
- const expiresIn = typeof data2.expires_in === "number" ? data2.expires_in : 3600;
1280
- return {
1281
- refresh: `${data2.refresh_token || refreshToken}|${idpClientId}|${tokenEndpoint}|external-idp`,
1282
- access: data2.access_token,
1283
- expires: Date.now() + expiresIn * 1e3 - EXPIRES_BUFFER_MS,
1284
- clientId: idpClientId,
1285
- clientSecret: "",
1286
- region,
1287
- authMethod: "external-idp",
1288
- profileArn: credentials.profileArn
1289
- };
1290
- }
1291
- const clientId = parts[1] ?? "";
1292
- const clientSecret = parts[2] ?? "";
1293
- const ssoEndpoint = `https://oidc.${region}.amazonaws.com`;
1294
- const response = await fetch(`${ssoEndpoint}/token`, {
1295
- method: "POST",
1296
- headers: { "Content-Type": "application/json", ...kiroUserAgent("ssooidc", "E") },
1297
- body: JSON.stringify({ clientId, clientSecret, refreshToken, grantType: "refresh_token" })
1298
- });
1299
- if (!response.ok)
1300
- throw new Error(`Token refresh failed: ${response.status}`);
1301
- const data = await response.json();
1302
- return {
1303
- refresh: `${data.refreshToken}|${clientId}|${clientSecret}|idc`,
1304
- access: data.accessToken,
1305
- expires: Date.now() + data.expiresIn * 1e3 - EXPIRES_BUFFER_MS,
1306
- clientId,
1307
- clientSecret,
1308
- region,
1309
- authMethod: "idc",
1310
- profileArn: credentials.profileArn,
1311
- startUrl: credentials.startUrl,
1312
- isEnterprise: credentials.isEnterprise
1313
- };
1314
- }
1315
- async function resolveKiroCredentials() {
1316
- const { getKiroCliCredentials: getKiroCliCredentials2, getKiroCliCredentialsAllowExpired: getKiroCliCredentialsAllowExpired2 } = await Promise.resolve().then(() => (init_kiro_cli(), kiro_cli_exports));
1317
- const fresh = getKiroCliCredentials2() ?? getKiroIdeCredentials();
1318
- if (fresh)
1319
- return fresh;
1320
- const stale = getKiroCliCredentialsAllowExpired2();
1321
- if (!stale)
1322
- return void 0;
1323
- return refreshKiroToken(stale);
1324
- }
1325
- var KIRO_DESKTOP_REFRESH_URL, EXPIRES_BUFFER_MS, KIRO_DESKTOP_USER_AGENT;
1326
- var init_oauth = __esm({
1327
- "../kiro-core/dist/oauth.js"() {
1328
- "use strict";
1329
- init_debug();
1330
- init_endpoints();
1331
- init_kiro_ide();
1332
- KIRO_DESKTOP_REFRESH_URL = "https://prod.{region}.auth.desktop.kiro.dev/refreshToken";
1333
- EXPIRES_BUFFER_MS = 5 * 60 * 1e3;
1334
- KIRO_DESKTOP_USER_AGENT = "Kiro-Desktop/0.2.13 (darwin; arm64)";
1335
- }
1336
- });
1337
-
1338
- // ../kiro-core/dist/token-type.js
1339
- function isExternalIdpAccessToken(accessToken) {
1340
- if (typeof accessToken !== "string")
1341
- return false;
1342
- const segments = accessToken.split(".");
1343
- if (segments.length !== 3)
1344
- return false;
1345
- const payloadSegment = segments[1];
1346
- if (!payloadSegment)
1347
- return false;
1348
- try {
1349
- const payload = JSON.parse(Buffer.from(payloadSegment.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf-8"));
1350
- return payload.aud === EXTERNAL_IDP_AUDIENCE;
1351
- } catch {
1352
- return false;
1353
- }
1354
- }
1355
- function kiroTokenTypeHeaders(accessToken) {
1356
- return isExternalIdpAccessToken(accessToken) ? { tokentype: "EXTERNAL_IDP" } : {};
1357
- }
1358
- var EXTERNAL_IDP_AUDIENCE;
1359
- var init_token_type = __esm({
1360
- "../kiro-core/dist/token-type.js"() {
1361
- "use strict";
1362
- EXTERNAL_IDP_AUDIENCE = "api://kiro";
1363
- }
1364
- });
1365
-
1366
- // ../kiro-core/dist/management.js
1367
- import { createHash as createHash2 } from "node:crypto";
1368
- function candidateManagementRegions(primary) {
1369
- const seen = /* @__PURE__ */ new Set([primary]);
1370
- const candidates = [primary];
1371
- for (const region of CANONICAL_MANAGEMENT_REGIONS) {
1372
- if (!seen.has(region)) {
1373
- seen.add(region);
1374
- candidates.push(region);
1375
- }
1376
- }
1377
- return candidates;
1378
- }
1379
- async function requestManagement(auth, operation, path, method, body) {
1380
- const url = new URL(path, getKiroEndpoints(auth.region).management);
1381
- const request = {
1382
- method,
1383
- headers: {
1384
- Accept: "application/json",
1385
- ...kiroAuthHeaders(auth.accessToken),
1386
- ...kiroTokenTypeHeaders(auth.accessToken)
1387
- }
1388
- };
1389
- if (method === "GET") {
1390
- for (const [name, value] of Object.entries(body)) {
1391
- if (value !== void 0)
1392
- url.searchParams.set(name, String(value));
1393
- }
1394
- } else {
1395
- request.headers = { ...request.headers, "Content-Type": "application/json" };
1396
- request.body = JSON.stringify(body);
1397
- }
1398
- let response;
1399
- try {
1400
- response = await fetch(url.toString(), request);
1401
- } catch (error2) {
1402
- throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error2 });
1403
- }
1404
- return parseManagementResponse(response, operation, auth.region);
1405
- }
1406
- function profileCacheKey(auth) {
1407
- const tokenHash = createHash2("sha256").update(auth.accessToken).digest("base64url");
1408
- return `${auth.region}:${tokenHash}`;
982
+ return arn;
1409
983
  }
1410
984
  async function parseManagementResponse(response, operation, region) {
1411
985
  if (!response.ok) {
@@ -1442,6 +1016,13 @@ async function resolveKiroProfileArn(auth, providedArn) {
1442
1016
  if (pending)
1443
1017
  return pending;
1444
1018
  const request = (async () => {
1019
+ if (isApiKey(auth.accessToken)) {
1020
+ const arn = await getApiKeyProfileArn(auth.accessToken);
1021
+ profileArnCache.set(key, arn);
1022
+ profileRegionCache.set(key, API_KEY_REGION);
1023
+ debugLog("profile.resolve", { source: "api-key", region: API_KEY_REGION, arn });
1024
+ return arn;
1025
+ }
1445
1026
  let lastResponse;
1446
1027
  let lastHttpError;
1447
1028
  for (const region of candidateManagementRegions(auth.region)) {
@@ -1477,73 +1058,544 @@ async function resolveKiroProfileArn(auth, providedArn) {
1477
1058
  pendingProfileRequests.delete(key);
1478
1059
  }
1479
1060
  }
1480
- async function listAvailableModels(auth, profileArn) {
1481
- const response = await requestManagement(auth, "ListAvailableModels", LIST_MODELS_PATH, "GET", {
1482
- origin: "KIRO_CLI",
1483
- profileArn
1484
- });
1485
- if (!Array.isArray(response.models) || response.models.length === 0) {
1486
- throw new Error(`Kiro management ListAvailableModels returned no models in ${auth.region}`);
1061
+ async function listAvailableModels(auth, profileArn) {
1062
+ const response = await requestManagement(auth, "ListAvailableModels", LIST_MODELS_PATH, "GET", {
1063
+ origin: "KIRO_CLI",
1064
+ profileArn
1065
+ });
1066
+ if (!Array.isArray(response.models) || response.models.length === 0) {
1067
+ throw new Error(`Kiro management ListAvailableModels returned no models in ${auth.region}`);
1068
+ }
1069
+ if (response.models.some((model) => !model || typeof model.modelId !== "string" || !model.modelId)) {
1070
+ throw new Error(`Kiro management ListAvailableModels returned an invalid catalog in ${auth.region}`);
1071
+ }
1072
+ return response;
1073
+ }
1074
+ async function fetchKiroModelCatalog(auth, providedProfileArn) {
1075
+ const profileArn = await resolveKiroProfileArn(auth, providedProfileArn);
1076
+ const region = isApiKey(auth.accessToken) ? API_KEY_REGION : profileRegionCache.get(profileCacheKey(auth)) ?? auth.region;
1077
+ if (region !== auth.region) {
1078
+ return listAvailableModels({ ...auth, region }, profileArn);
1079
+ }
1080
+ return listAvailableModels(auth, profileArn);
1081
+ }
1082
+ async function getUsageLimits(auth, request) {
1083
+ const operation = "GetUsageLimits";
1084
+ const url = new URL("Get-Usage-Limits", getKiroEndpoints(auth.region).management);
1085
+ for (const [name, value] of Object.entries(request)) {
1086
+ if (value !== void 0)
1087
+ url.searchParams.set(name, String(value));
1088
+ }
1089
+ let response;
1090
+ try {
1091
+ response = await fetch(url.toString(), {
1092
+ method: "GET",
1093
+ headers: {
1094
+ Accept: "application/json",
1095
+ ...kiroAuthHeaders(auth.accessToken),
1096
+ ...kiroTokenTypeHeaders(auth.accessToken),
1097
+ "User-Agent": "ns-kiro-provider"
1098
+ }
1099
+ });
1100
+ } catch (error2) {
1101
+ throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error2 });
1102
+ }
1103
+ return parseManagementResponse(response, operation, auth.region);
1104
+ }
1105
+ var LIST_PROFILES_PATH, LIST_MODELS_PATH, GET_PROFILE_TARGET, API_KEY_REGION, profileArnCache, pendingProfileRequests, profileRegionCache, CANONICAL_MANAGEMENT_REGIONS, ENV_PROFILE_ARN, KiroManagementHttpError;
1106
+ var init_management = __esm({
1107
+ "../kiro-core/dist/management.js"() {
1108
+ "use strict";
1109
+ init_debug();
1110
+ init_endpoints();
1111
+ init_oauth();
1112
+ init_token_type();
1113
+ LIST_PROFILES_PATH = "List-Available-Profiles";
1114
+ LIST_MODELS_PATH = "List-Available-Models";
1115
+ GET_PROFILE_TARGET = "AmazonCodeWhispererService.GetProfile";
1116
+ API_KEY_REGION = "us-east-1";
1117
+ profileArnCache = /* @__PURE__ */ new Map();
1118
+ pendingProfileRequests = /* @__PURE__ */ new Map();
1119
+ profileRegionCache = /* @__PURE__ */ new Map();
1120
+ CANONICAL_MANAGEMENT_REGIONS = ["us-east-1", "eu-central-1"];
1121
+ ENV_PROFILE_ARN = "KIRO_PROFILE_ARN";
1122
+ KiroManagementHttpError = class extends Error {
1123
+ status;
1124
+ constructor(message, status) {
1125
+ super(message);
1126
+ this.status = status;
1127
+ this.name = "KiroManagementHttpError";
1128
+ }
1129
+ };
1130
+ }
1131
+ });
1132
+
1133
+ // ../kiro-core/dist/models.js
1134
+ var models_exports = {};
1135
+ __export(models_exports, {
1136
+ KIRO_MANAGEMENT_CACHE_PATH: () => KIRO_MANAGEMENT_CACHE_PATH,
1137
+ KIRO_MANAGEMENT_CACHE_SOURCE: () => KIRO_MANAGEMENT_CACHE_SOURCE,
1138
+ KIRO_MANAGEMENT_CACHE_VERSION: () => KIRO_MANAGEMENT_CACHE_VERSION,
1139
+ KIRO_MODEL_IDS: () => KIRO_MODEL_IDS,
1140
+ applyEffortLadder: () => applyEffortLadder,
1141
+ getCachedModels: () => getCachedModels,
1142
+ isCacheStale: () => isCacheStale,
1143
+ kiroModels: () => kiroModels,
1144
+ loadCachedModelIds: () => loadCachedModelIds,
1145
+ mapKiroCatalogModels: () => mapKiroCatalogModels,
1146
+ resolveApiRegion: () => resolveApiRegion,
1147
+ resolveKiroModel: () => resolveKiroModel,
1148
+ updateKiroModelsCache: () => updateKiroModelsCache
1149
+ });
1150
+ import { randomUUID } from "node:crypto";
1151
+ import { existsSync as existsSync3, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync } from "node:fs";
1152
+ import { homedir as homedir4 } from "node:os";
1153
+ import { join as join4 } from "node:path";
1154
+ function isRecord2(value) {
1155
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1156
+ }
1157
+ function isPositiveNumber(value) {
1158
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
1159
+ }
1160
+ function isEffortList(value) {
1161
+ return Array.isArray(value) && value.length > 0 && value.every((effort) => KIRO_EFFORT_ORDER.includes(effort));
1162
+ }
1163
+ function isEffortMap(value) {
1164
+ return isRecord2(value) && Object.values(value).every((mapped) => typeof mapped === "string");
1165
+ }
1166
+ function isCachedKiroModel(value) {
1167
+ if (!isRecord2(value))
1168
+ return false;
1169
+ const cost = value.cost;
1170
+ const input = value.input;
1171
+ const schema = value.additionalModelRequestFieldsSchema;
1172
+ const tokenLimits = value.tokenLimits;
1173
+ return typeof value.id === "string" && value.id.length > 0 && typeof value.kiroModelId === "string" && value.kiroModelId.length > 0 && typeof value.name === "string" && value.name.length > 0 && typeof value.reasoning === "boolean" && Array.isArray(input) && input.length > 0 && input.every((modality) => modality === "text" || modality === "image") && isRecord2(cost) && typeof cost.input === "number" && typeof cost.output === "number" && typeof cost.cacheRead === "number" && typeof cost.cacheWrite === "number" && isPositiveNumber(value.contextWindow) && isPositiveNumber(value.maxTokens) && (value.efforts === void 0 || isEffortList(value.efforts)) && (value.effortMap === void 0 || isEffortMap(value.effortMap)) && (schema === void 0 || isRecord2(schema)) && (tokenLimits === void 0 || isRecord2(tokenLimits)) && (value.firstTokenTimeout === void 0 || isPositiveNumber(value.firstTokenTimeout)) && (value.rateMultiplier === void 0 || isPositiveNumber(value.rateMultiplier)) && (value.rateUnit === void 0 || typeof value.rateUnit === "string");
1174
+ }
1175
+ function parseManagementCache(raw) {
1176
+ let value;
1177
+ try {
1178
+ value = JSON.parse(raw);
1179
+ } catch {
1180
+ return void 0;
1181
+ }
1182
+ if (!isRecord2(value) || value.version !== KIRO_MANAGEMENT_CACHE_VERSION || value.source !== KIRO_MANAGEMENT_CACHE_SOURCE || !isRecord2(value.regions)) {
1183
+ return void 0;
1184
+ }
1185
+ const regions = {};
1186
+ for (const [region, rawEntry] of Object.entries(value.regions)) {
1187
+ if (!isRecord2(rawEntry) || rawEntry.region !== region || !isPositiveNumber(rawEntry.fetchedAt) || !Array.isArray(rawEntry.models) || rawEntry.models.length === 0 || !rawEntry.models.every(isCachedKiroModel)) {
1188
+ return void 0;
1189
+ }
1190
+ const modelIds = /* @__PURE__ */ new Set();
1191
+ for (const model of rawEntry.models) {
1192
+ if (modelIds.has(model.id))
1193
+ return void 0;
1194
+ modelIds.add(model.id);
1195
+ }
1196
+ regions[region] = rawEntry;
1197
+ }
1198
+ return {
1199
+ version: KIRO_MANAGEMENT_CACHE_VERSION,
1200
+ source: KIRO_MANAGEMENT_CACHE_SOURCE,
1201
+ regions
1202
+ };
1203
+ }
1204
+ function readManagementCache() {
1205
+ if (!existsSync3(KIRO_MANAGEMENT_CACHE_PATH))
1206
+ return void 0;
1207
+ try {
1208
+ return parseManagementCache(readFileSync2(KIRO_MANAGEMENT_CACHE_PATH, "utf-8"));
1209
+ } catch {
1210
+ return void 0;
1211
+ }
1212
+ }
1213
+ function writeManagementCache(cache) {
1214
+ const temporaryPath = `${KIRO_MANAGEMENT_CACHE_PATH}.${process.pid}.${randomUUID()}.tmp`;
1215
+ try {
1216
+ writeFileSync(temporaryPath, JSON.stringify(cache, null, 2), "utf-8");
1217
+ renameSync(temporaryPath, KIRO_MANAGEMENT_CACHE_PATH);
1218
+ } finally {
1219
+ rmSync(temporaryPath, { force: true });
1220
+ }
1221
+ }
1222
+ function toLocalModelId(kiroModelId) {
1223
+ return kiroModelId.replace(/(\d)\.(\d)/g, "$1-$2");
1224
+ }
1225
+ function humanizeModelId(modelId) {
1226
+ return modelId.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1227
+ }
1228
+ function applyEffortLadder(config) {
1229
+ if (!config || config.values.length === 0)
1230
+ return {};
1231
+ const efforts = KIRO_EFFORT_ORDER.filter((effort) => config.values.includes(effort));
1232
+ if (efforts.length === 0)
1233
+ return {};
1234
+ return { efforts, ...config.summarizedThinking ? { supportsSummarizedThinking: true } : {} };
1235
+ }
1236
+ function hasReasoningFamilyFallback(modelId) {
1237
+ const normalizedId = modelId.toLowerCase();
1238
+ return normalizedId === "auto" || REASONING_FAMILY_MARKERS.some((marker) => normalizedId.includes(marker));
1239
+ }
1240
+ function hasVerifiedImageInput(kiroModelId) {
1241
+ return kiroModelId.startsWith("claude-") || VERIFIED_IMAGE_MODEL_IDS.has(kiroModelId.toLowerCase());
1242
+ }
1243
+ function applyVerifiedCapabilities(model) {
1244
+ if (!hasVerifiedImageInput(model.kiroModelId) || model.input.includes("image"))
1245
+ return model;
1246
+ return { ...model, input: ["text", "image"] };
1247
+ }
1248
+ function validateCatalogMetadata(model) {
1249
+ const rawSchema = model.additionalModelRequestFieldsSchema;
1250
+ const schema = rawSchema ?? void 0;
1251
+ if (schema !== void 0 && !isRecord2(schema)) {
1252
+ throw new Error(`Kiro management catalog model ${model.modelId} has an invalid request-fields schema`);
1487
1253
  }
1488
- if (response.models.some((model) => !model || typeof model.modelId !== "string" || !model.modelId)) {
1489
- throw new Error(`Kiro management ListAvailableModels returned an invalid catalog in ${auth.region}`);
1254
+ const tokenLimits = model.tokenLimits;
1255
+ if (tokenLimits !== void 0 && !isRecord2(tokenLimits)) {
1256
+ throw new Error(`Kiro management catalog model ${model.modelId} has invalid token limits`);
1490
1257
  }
1491
- return response;
1258
+ if (tokenLimits && (tokenLimits.maxInputTokens !== void 0 && !isPositiveNumber(tokenLimits.maxInputTokens) || tokenLimits.maxOutputTokens !== void 0 && !isPositiveNumber(tokenLimits.maxOutputTokens))) {
1259
+ throw new Error(`Kiro management catalog model ${model.modelId} has invalid token limits`);
1260
+ }
1261
+ return { schema, tokenLimits };
1492
1262
  }
1493
- async function fetchKiroModelCatalog(auth, providedProfileArn) {
1494
- const profileArn = await resolveKiroProfileArn(auth, providedProfileArn);
1495
- const region = profileRegionCache.get(profileCacheKey(auth)) ?? auth.region;
1496
- if (region !== auth.region) {
1497
- return listAvailableModels({ ...auth, region }, profileArn);
1263
+ function mapKiroCatalogModels(catalogModels, region, rates) {
1264
+ if (catalogModels.length === 0) {
1265
+ throw new Error(`Kiro management catalog returned no models in ${region}`);
1498
1266
  }
1499
- return listAvailableModels(auth, profileArn);
1267
+ const seenIds = /* @__PURE__ */ new Set();
1268
+ return catalogModels.map((catalogModel) => {
1269
+ const kiroModelId = catalogModel.modelId;
1270
+ if (!kiroModelId || kiroModelId.trim() !== kiroModelId) {
1271
+ throw new Error(`Kiro management catalog returned an invalid model ID in ${region}`);
1272
+ }
1273
+ const id = toLocalModelId(kiroModelId);
1274
+ if (seenIds.has(id)) {
1275
+ throw new Error(`Kiro management catalog contains conflicting model ID ${id} in ${region}`);
1276
+ }
1277
+ seenIds.add(id);
1278
+ const existing = kiroModels.find((model) => model.id === id);
1279
+ const rate = rates?.get(kiroModelId);
1280
+ const { schema, tokenLimits } = validateCatalogMetadata(catalogModel);
1281
+ const effortConfig = getKiroEffortConfig(schema, kiroModelId);
1282
+ const catalogName = typeof catalogModel.displayName === "string" && catalogModel.displayName.length > 0 ? catalogModel.displayName : void 0;
1283
+ return {
1284
+ id,
1285
+ kiroModelId,
1286
+ // Humanize the wire id, not the local one: `toLocalModelId` rewrites
1287
+ // `5.1` as `5-1`, and a display name derived from it loses the dot —
1288
+ // "Claude Fable 5 1" instead of "Claude Fable 5.1".
1289
+ name: catalogName ?? existing?.name ?? humanizeModelId(kiroModelId),
1290
+ region,
1291
+ // Deliberately schema-only: when a schema exists the resolver returns
1292
+ // `deriveKiroEffort(schema)`, and when it does not the family-marker guess
1293
+ // decides. The fallback tier feeds the ladders, not this flag.
1294
+ reasoning: schema !== void 0 && effortConfig !== void 0 || schema === void 0 && hasReasoningFamilyFallback(id),
1295
+ ...applyEffortLadder(effortConfig),
1296
+ input: existing ? [...existing.input] : hasVerifiedImageInput(kiroModelId) ? ["text", "image"] : ["text"],
1297
+ ...id.startsWith("claude-") ? { recoverTextToolCalls: false } : {},
1298
+ cost: ZERO_COST,
1299
+ ...rate ? { rateMultiplier: rate.multiplier, ...rate.unit ? { rateUnit: rate.unit } : {} } : {},
1300
+ contextWindow: tokenLimits?.maxInputTokens ?? DEFAULT_CONTEXT_WINDOW,
1301
+ maxTokens: tokenLimits?.maxOutputTokens ?? DEFAULT_MAX_TOKENS,
1302
+ ...existing?.firstTokenTimeout ? { firstTokenTimeout: existing.firstTokenTimeout } : {},
1303
+ ...schema ? { additionalModelRequestFieldsSchema: schema } : {},
1304
+ ...tokenLimits ? { tokenLimits } : {}
1305
+ };
1306
+ });
1500
1307
  }
1501
- async function getUsageLimits(auth, request) {
1502
- const operation = "GetUsageLimits";
1503
- const url = new URL("Get-Usage-Limits", getKiroEndpoints(auth.region).management);
1504
- for (const [name, value] of Object.entries(request)) {
1505
- if (value !== void 0)
1506
- url.searchParams.set(name, String(value));
1308
+ function refreshKnownModelIds(cache) {
1309
+ KIRO_MODEL_IDS.clear();
1310
+ for (const modelId of BOOTSTRAP_KIRO_MODEL_IDS)
1311
+ KIRO_MODEL_IDS.add(modelId);
1312
+ if (!cache)
1313
+ return;
1314
+ for (const entry of Object.values(cache.regions)) {
1315
+ for (const model of entry.models)
1316
+ KIRO_MODEL_IDS.add(model.kiroModelId);
1507
1317
  }
1508
- let response;
1509
- try {
1510
- response = await fetch(url.toString(), {
1511
- method: "GET",
1512
- headers: {
1513
- Accept: "application/json",
1514
- ...kiroAuthHeaders(auth.accessToken),
1515
- ...kiroTokenTypeHeaders(auth.accessToken),
1516
- "User-Agent": "ns-kiro-provider"
1517
- }
1518
- });
1519
- } catch (error2) {
1520
- throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error2 });
1318
+ }
1319
+ function loadCachedModelIds() {
1320
+ refreshKnownModelIds(readManagementCache());
1321
+ }
1322
+ function getCachedModels(region) {
1323
+ const cache = readManagementCache();
1324
+ refreshKnownModelIds(cache);
1325
+ const models = cache?.regions[region]?.models ?? kiroModels;
1326
+ let changed = false;
1327
+ const corrected = models.map((model) => {
1328
+ const result = applyVerifiedCapabilities(model);
1329
+ if (result !== model)
1330
+ changed = true;
1331
+ return result;
1332
+ });
1333
+ return changed ? corrected : models;
1334
+ }
1335
+ function isCacheStale(region) {
1336
+ const entry = readManagementCache()?.regions[region];
1337
+ return !entry || Date.now() - entry.fetchedAt > CACHE_MAX_AGE_MS;
1338
+ }
1339
+ async function updateKiroModelsCache(accessToken, region, profileArn) {
1340
+ const response = await fetchKiroModelCatalog({ accessToken, region }, profileArn);
1341
+ const models = mapKiroCatalogModels(response.models, region, getKiroCliModelRates());
1342
+ const cache = readManagementCache() ?? {
1343
+ version: KIRO_MANAGEMENT_CACHE_VERSION,
1344
+ source: KIRO_MANAGEMENT_CACHE_SOURCE,
1345
+ regions: {}
1346
+ };
1347
+ cache.regions[region] = { region, fetchedAt: Date.now(), models };
1348
+ writeManagementCache(cache);
1349
+ refreshKnownModelIds(cache);
1350
+ }
1351
+ function resolveKiroModel(modelId, exactKiroModelId) {
1352
+ if (exactKiroModelId)
1353
+ return exactKiroModelId;
1354
+ const cachedModel = Object.values(readManagementCache()?.regions ?? {}).flatMap((entry) => entry.models).find((model) => model.id === modelId);
1355
+ if (cachedModel) {
1356
+ KIRO_MODEL_IDS.add(cachedModel.kiroModelId);
1357
+ return cachedModel.kiroModelId;
1521
1358
  }
1522
- return parseManagementResponse(response, operation, auth.region);
1359
+ const bootstrapModel = kiroModels.find((model) => model.id === modelId);
1360
+ if (bootstrapModel)
1361
+ return bootstrapModel.kiroModelId;
1362
+ const normalizedId = modelId.replace(/(\d)-(\d)/g, "$1.$2");
1363
+ loadCachedModelIds();
1364
+ if (!KIRO_MODEL_IDS.has(normalizedId)) {
1365
+ throw new Error(`Unknown Kiro model ID: ${modelId}`);
1366
+ }
1367
+ return normalizedId;
1523
1368
  }
1524
- var LIST_PROFILES_PATH, LIST_MODELS_PATH, profileArnCache, pendingProfileRequests, profileRegionCache, CANONICAL_MANAGEMENT_REGIONS, ENV_PROFILE_ARN, KiroManagementHttpError;
1525
- var init_management = __esm({
1526
- "../kiro-core/dist/management.js"() {
1369
+ var KIRO_MANAGEMENT_CACHE_VERSION, KIRO_MANAGEMENT_CACHE_SOURCE, KIRO_MANAGEMENT_CACHE_PATH, CACHE_MAX_AGE_MS, DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS, ZERO_COST, REASONING_FAMILY_MARKERS, VERIFIED_IMAGE_MODEL_IDS, bootstrapKiroModels, kiroModels, BOOTSTRAP_KIRO_MODEL_IDS, KIRO_MODEL_IDS;
1370
+ var init_models = __esm({
1371
+ "../kiro-core/dist/models.js"() {
1527
1372
  "use strict";
1528
- init_debug();
1373
+ init_effort();
1374
+ init_kiro_cli();
1375
+ init_management();
1376
+ init_types();
1529
1377
  init_endpoints();
1530
- init_oauth();
1531
- init_token_type();
1532
- LIST_PROFILES_PATH = "List-Available-Profiles";
1533
- LIST_MODELS_PATH = "List-Available-Models";
1534
- profileArnCache = /* @__PURE__ */ new Map();
1535
- pendingProfileRequests = /* @__PURE__ */ new Map();
1536
- profileRegionCache = /* @__PURE__ */ new Map();
1537
- CANONICAL_MANAGEMENT_REGIONS = ["us-east-1", "eu-central-1"];
1538
- ENV_PROFILE_ARN = "KIRO_PROFILE_ARN";
1539
- KiroManagementHttpError = class extends Error {
1540
- status;
1541
- constructor(message, status) {
1542
- super(message);
1543
- this.status = status;
1544
- this.name = "KiroManagementHttpError";
1378
+ KIRO_MANAGEMENT_CACHE_VERSION = 1;
1379
+ KIRO_MANAGEMENT_CACHE_SOURCE = "ns-kiro-provider-management";
1380
+ KIRO_MANAGEMENT_CACHE_PATH = join4(homedir4(), ".ns-kiro-provider-models-cache.json");
1381
+ CACHE_MAX_AGE_MS = 36e5;
1382
+ DEFAULT_CONTEXT_WINDOW = 2e5;
1383
+ DEFAULT_MAX_TOKENS = 8192;
1384
+ ZERO_COST = Object.freeze({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
1385
+ REASONING_FAMILY_MARKERS = ["opus", "sonnet", "fable", "coder", "deepseek", "gpt", "glm", "qwen"];
1386
+ VERIFIED_IMAGE_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.6-luna"]);
1387
+ bootstrapKiroModels = [
1388
+ {
1389
+ id: "claude-opus-5",
1390
+ kiroModelId: "claude-opus-5",
1391
+ name: "Claude Opus 5",
1392
+ reasoning: true,
1393
+ input: ["text", "image"],
1394
+ cost: ZERO_COST,
1395
+ contextWindow: 1e6,
1396
+ maxTokens: 128e3,
1397
+ firstTokenTimeout: 18e4
1398
+ },
1399
+ {
1400
+ id: "claude-opus-4-8",
1401
+ kiroModelId: "claude-opus-4.8",
1402
+ name: "Claude Opus 4.8",
1403
+ reasoning: true,
1404
+ input: ["text", "image"],
1405
+ cost: ZERO_COST,
1406
+ contextWindow: 1e6,
1407
+ maxTokens: 128e3,
1408
+ firstTokenTimeout: 18e4
1409
+ },
1410
+ {
1411
+ id: "claude-opus-4-7",
1412
+ kiroModelId: "claude-opus-4.7",
1413
+ name: "Claude Opus 4.7",
1414
+ reasoning: true,
1415
+ input: ["text", "image"],
1416
+ cost: ZERO_COST,
1417
+ contextWindow: 1e6,
1418
+ maxTokens: 128e3,
1419
+ firstTokenTimeout: 18e4
1420
+ },
1421
+ {
1422
+ id: "claude-opus-4-6",
1423
+ kiroModelId: "claude-opus-4.6",
1424
+ name: "Claude Opus 4.6",
1425
+ reasoning: true,
1426
+ input: ["text", "image"],
1427
+ cost: ZERO_COST,
1428
+ contextWindow: 1e6,
1429
+ maxTokens: 32768
1430
+ },
1431
+ {
1432
+ id: "claude-opus-4-5",
1433
+ kiroModelId: "claude-opus-4.5",
1434
+ name: "Claude Opus 4.5",
1435
+ reasoning: true,
1436
+ input: ["text", "image"],
1437
+ cost: ZERO_COST,
1438
+ contextWindow: 2e5,
1439
+ maxTokens: 64e3
1440
+ },
1441
+ {
1442
+ id: "claude-sonnet-5",
1443
+ kiroModelId: "claude-sonnet-5",
1444
+ name: "Claude Sonnet 5",
1445
+ reasoning: true,
1446
+ input: ["text", "image"],
1447
+ cost: ZERO_COST,
1448
+ contextWindow: 1e6,
1449
+ maxTokens: 65536
1450
+ },
1451
+ {
1452
+ id: "claude-sonnet-4-6",
1453
+ kiroModelId: "claude-sonnet-4.6",
1454
+ name: "Claude Sonnet 4.6",
1455
+ reasoning: true,
1456
+ input: ["text", "image"],
1457
+ cost: ZERO_COST,
1458
+ contextWindow: 1e6,
1459
+ maxTokens: 65536
1460
+ },
1461
+ {
1462
+ id: "claude-sonnet-4-5",
1463
+ kiroModelId: "claude-sonnet-4.5",
1464
+ name: "Claude Sonnet 4.5",
1465
+ reasoning: true,
1466
+ input: ["text", "image"],
1467
+ cost: ZERO_COST,
1468
+ contextWindow: 2e5,
1469
+ maxTokens: 65536
1470
+ },
1471
+ {
1472
+ id: "claude-sonnet-4",
1473
+ kiroModelId: "claude-sonnet-4",
1474
+ name: "Claude Sonnet 4",
1475
+ reasoning: true,
1476
+ input: ["text", "image"],
1477
+ cost: ZERO_COST,
1478
+ contextWindow: 2e5,
1479
+ maxTokens: 65536
1480
+ },
1481
+ {
1482
+ id: "claude-haiku-4-5",
1483
+ kiroModelId: "claude-haiku-4.5",
1484
+ name: "Claude Haiku 4.5",
1485
+ reasoning: false,
1486
+ input: ["text", "image"],
1487
+ cost: ZERO_COST,
1488
+ contextWindow: 2e5,
1489
+ maxTokens: 65536
1490
+ },
1491
+ {
1492
+ id: "claude-fable-5",
1493
+ kiroModelId: "claude-fable-5",
1494
+ name: "Claude Fable 5",
1495
+ reasoning: true,
1496
+ input: ["text", "image"],
1497
+ cost: ZERO_COST,
1498
+ contextWindow: 1e6,
1499
+ maxTokens: 65536
1500
+ },
1501
+ {
1502
+ id: "gpt-5-6-luna",
1503
+ kiroModelId: "gpt-5.6-luna",
1504
+ name: "GPT-5.6 Luna",
1505
+ reasoning: true,
1506
+ input: ["text", "image"],
1507
+ cost: ZERO_COST,
1508
+ contextWindow: 272e3,
1509
+ maxTokens: 128e3
1510
+ },
1511
+ {
1512
+ id: "gpt-5-6-sol",
1513
+ kiroModelId: "gpt-5.6-sol",
1514
+ name: "GPT-5.6 Sol",
1515
+ reasoning: true,
1516
+ input: ["text"],
1517
+ cost: ZERO_COST,
1518
+ contextWindow: 272e3,
1519
+ maxTokens: 128e3
1520
+ },
1521
+ {
1522
+ id: "gpt-5-6-terra",
1523
+ kiroModelId: "gpt-5.6-terra",
1524
+ name: "GPT-5.6 Terra",
1525
+ reasoning: true,
1526
+ input: ["text"],
1527
+ cost: ZERO_COST,
1528
+ contextWindow: 272e3,
1529
+ maxTokens: 128e3
1530
+ },
1531
+ {
1532
+ id: "deepseek-3-2",
1533
+ kiroModelId: "deepseek-3.2",
1534
+ name: "DeepSeek 3.2",
1535
+ reasoning: true,
1536
+ input: ["text"],
1537
+ cost: ZERO_COST,
1538
+ contextWindow: 164e3,
1539
+ maxTokens: 8192
1540
+ },
1541
+ {
1542
+ id: "minimax-m2-5",
1543
+ kiroModelId: "minimax-m2.5",
1544
+ name: "MiniMax M2.5",
1545
+ reasoning: false,
1546
+ input: ["text"],
1547
+ cost: ZERO_COST,
1548
+ contextWindow: 196e3,
1549
+ maxTokens: 8192
1550
+ },
1551
+ {
1552
+ id: "minimax-m2-1",
1553
+ kiroModelId: "minimax-m2.1",
1554
+ name: "MiniMax M2.1",
1555
+ reasoning: false,
1556
+ input: ["text"],
1557
+ cost: ZERO_COST,
1558
+ contextWindow: 196e3,
1559
+ maxTokens: 8192
1560
+ },
1561
+ {
1562
+ id: "glm-5",
1563
+ kiroModelId: "glm-5",
1564
+ name: "GLM 5",
1565
+ reasoning: true,
1566
+ input: ["text"],
1567
+ cost: ZERO_COST,
1568
+ contextWindow: 2e5,
1569
+ maxTokens: 8192
1570
+ },
1571
+ {
1572
+ id: "qwen3-coder-next",
1573
+ kiroModelId: "qwen3-coder-next",
1574
+ name: "Qwen3 Coder Next",
1575
+ reasoning: true,
1576
+ input: ["text"],
1577
+ cost: ZERO_COST,
1578
+ contextWindow: 256e3,
1579
+ maxTokens: 8192
1580
+ },
1581
+ {
1582
+ id: "auto",
1583
+ kiroModelId: "auto",
1584
+ name: "Auto",
1585
+ reasoning: true,
1586
+ input: ["text", "image"],
1587
+ cost: ZERO_COST,
1588
+ contextWindow: 1e6,
1589
+ maxTokens: 65536
1545
1590
  }
1546
- };
1591
+ ];
1592
+ kiroModels = bootstrapKiroModels.map((model) => ({
1593
+ ...model,
1594
+ ...applyEffortLadder(model.reasoning ? getKiroEffortConfig(model.additionalModelRequestFieldsSchema, model.kiroModelId) : void 0),
1595
+ ...model.id.startsWith("claude-") ? { recoverTextToolCalls: false } : {}
1596
+ }));
1597
+ BOOTSTRAP_KIRO_MODEL_IDS = kiroModels.map((model) => model.kiroModelId);
1598
+ KIRO_MODEL_IDS = new Set(BOOTSTRAP_KIRO_MODEL_IDS);
1547
1599
  }
1548
1600
  });
1549
1601
 
@@ -1611,8 +1663,8 @@ var require_base64_js = __commonJS({
1611
1663
  }
1612
1664
  return arr;
1613
1665
  }
1614
- function tripletToBase64(num) {
1615
- return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
1666
+ function tripletToBase64(num2) {
1667
+ return lookup[num2 >> 18 & 63] + lookup[num2 >> 12 & 63] + lookup[num2 >> 6 & 63] + lookup[num2 & 63];
1616
1668
  }
1617
1669
  function encodeChunk(uint8, start, end) {
1618
1670
  var tmp;
@@ -1705,6 +1757,10 @@ var KiroBlockBuffer = class {
1705
1757
  getText(index) {
1706
1758
  return this.blocks.get(index)?.text ?? "";
1707
1759
  }
1760
+ /** Kinds of the live blocks, in allocation order. */
1761
+ kinds() {
1762
+ return [...this.blocks.values()].map((block) => block.kind);
1763
+ }
1708
1764
  /**
1709
1765
  * Rewrite one accumulated block before it is closed. Used by the recovery
1710
1766
  * passes that lift tool calls out of text and by echo-noise stripping, both
@@ -1794,23 +1850,262 @@ function parseBracketToolCalls(text) {
1794
1850
  }
1795
1851
  return { toolCalls, cleanedText };
1796
1852
  }
1797
-
1798
- // ../kiro-core/dist/cost.js
1799
- var PER_MILLION = 1e6;
1800
- function calculateKiroCost(cost, usage) {
1801
- const input = usage.input * cost.input / PER_MILLION;
1802
- const output = usage.output * cost.output / PER_MILLION;
1803
- const cacheRead = (usage.cacheRead ?? 0) * cost.cacheRead / PER_MILLION;
1804
- const cacheWrite = (usage.cacheWrite ?? 0) * cost.cacheWrite / PER_MILLION;
1805
- return { input, output, cacheRead, cacheWrite, total: input + output + cacheRead + cacheWrite };
1853
+
1854
+ // ../kiro-core/dist/cache-estimator.js
1855
+ var stateByConversation = /* @__PURE__ */ new Map();
1856
+ var MAX_TRACKED_CONVERSATIONS = 128;
1857
+ var warnedWireCacheCounters = false;
1858
+ function applyCacheEstimate(conversationId, usage, wireUsage, config, now = Date.now()) {
1859
+ const previous = stateByConversation.get(conversationId);
1860
+ const promptTokens = usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0) + usage.output;
1861
+ const wireReportedCache = wireUsage?.cacheReadInputTokens !== void 0 || wireUsage?.cacheWriteInputTokens !== void 0;
1862
+ if (wireReportedCache) {
1863
+ if (config.estimateCacheUsage && !warnedWireCacheCounters) {
1864
+ warnedWireCacheCounters = true;
1865
+ console.warn("[kiro-core] Kiro now reports cache token counters; cache estimation was skipped and may be disabled.");
1866
+ }
1867
+ noteSuccessfulTurn(conversationId, promptTokens, usage.input, now);
1868
+ return 0;
1869
+ }
1870
+ if (!config.estimateCacheUsage || usage.input <= 0)
1871
+ return 0;
1872
+ if (!previous) {
1873
+ noteSuccessfulTurn(conversationId, promptTokens, usage.input, now);
1874
+ return 0;
1875
+ }
1876
+ const expired = config.estimatedCacheTimeout > 0 && now - previous.turnTimestamp > config.estimatedCacheTimeout;
1877
+ const contextShrank = usage.input < previous.promptTokens * 0.6;
1878
+ if (expired || contextShrank) {
1879
+ noteSuccessfulTurn(conversationId, promptTokens, usage.input, now);
1880
+ return 0;
1881
+ }
1882
+ const estimatedRead = Math.min(previous.promptTokens, usage.input);
1883
+ if (estimatedRead > 0) {
1884
+ usage.input -= estimatedRead;
1885
+ usage.cacheRead = (usage.cacheRead ?? 0) + estimatedRead;
1886
+ usage.cacheEstimated = true;
1887
+ }
1888
+ noteSuccessfulTurn(conversationId, promptTokens, promptTokens, now);
1889
+ return estimatedRead;
1890
+ }
1891
+ function noteSuccessfulTurn(conversationId, promptTokens, input, now) {
1892
+ if (input <= 0 || promptTokens <= 0)
1893
+ return;
1894
+ stateByConversation.delete(conversationId);
1895
+ stateByConversation.set(conversationId, { promptTokens, turnTimestamp: now });
1896
+ if (stateByConversation.size > MAX_TRACKED_CONVERSATIONS) {
1897
+ const oldest = stateByConversation.keys().next().value;
1898
+ if (oldest !== void 0)
1899
+ stateByConversation.delete(oldest);
1900
+ }
1901
+ }
1902
+
1903
+ // ../kiro-core/dist/cost.js
1904
+ var PER_MILLION = 1e6;
1905
+ function calculateKiroCost(cost, usage) {
1906
+ const input = usage.input * cost.input / PER_MILLION;
1907
+ const output = usage.output * cost.output / PER_MILLION;
1908
+ const cacheRead = (usage.cacheRead ?? 0) * cost.cacheRead / PER_MILLION;
1909
+ const cacheWrite = (usage.cacheWrite ?? 0) * cost.cacheWrite / PER_MILLION;
1910
+ return { input, output, cacheRead, cacheWrite, total: input + output + cacheRead + cacheWrite };
1911
+ }
1912
+
1913
+ // ../kiro-core/dist/index.js
1914
+ init_debug();
1915
+ init_effort();
1916
+ init_endpoints();
1917
+
1918
+ // ../kiro-core/dist/retry.js
1919
+ init_models();
1920
+ var FIRST_TOKEN_TIMEOUT = 9e4;
1921
+ var REQUEST_HEADER_TIMEOUT = 9e4;
1922
+ function firstTokenTimeoutForModel(modelId) {
1923
+ if (retryConfig.firstTokenTimeoutMs !== FIRST_TOKEN_TIMEOUT) {
1924
+ return retryConfig.firstTokenTimeoutMs;
1925
+ }
1926
+ const model = kiroModels.find((m) => m.id === modelId);
1927
+ return model?.firstTokenTimeout ?? FIRST_TOKEN_TIMEOUT;
1928
+ }
1929
+ var retryConfig = {
1930
+ firstTokenTimeoutMs: FIRST_TOKEN_TIMEOUT,
1931
+ requestHeaderTimeoutMs: REQUEST_HEADER_TIMEOUT
1932
+ };
1933
+ function exponentialBackoff(attempt, baseMs, maxMs) {
1934
+ return Math.min(baseMs * 2 ** attempt, maxMs);
1935
+ }
1936
+ var MAX_RETRY_DELAY = 1e4;
1937
+ var REQUEST_RATE_FALLBACK_DELAY_MS = 1e4;
1938
+ function extractKiroReason(errorText) {
1939
+ if (!errorText)
1940
+ return void 0;
1941
+ try {
1942
+ const parsed = JSON.parse(errorText);
1943
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
1944
+ return void 0;
1945
+ const reason = parsed.reason;
1946
+ return typeof reason === "string" && reason.length > 0 ? reason : void 0;
1947
+ } catch {
1948
+ return void 0;
1949
+ }
1950
+ }
1951
+ function parseRetryAfterMs(headers, nowMs = Date.now()) {
1952
+ const get = headers?.get?.bind(headers);
1953
+ if (!get)
1954
+ return void 0;
1955
+ const milliseconds = nonNegativeNumber(get("retry-after-ms"));
1956
+ if (milliseconds !== void 0)
1957
+ return Math.round(milliseconds);
1958
+ const retryAfter = get("retry-after");
1959
+ if (retryAfter !== null && retryAfter.trim() !== "") {
1960
+ const seconds = Number(retryAfter);
1961
+ if (Number.isFinite(seconds)) {
1962
+ if (seconds >= 0) {
1963
+ const delayMs = seconds * 1e3;
1964
+ if (Number.isFinite(delayMs))
1965
+ return Math.round(delayMs);
1966
+ }
1967
+ } else {
1968
+ const dateMs = Date.parse(retryAfter);
1969
+ if (!Number.isNaN(dateMs))
1970
+ return Math.max(0, dateMs - nowMs);
1971
+ }
1972
+ }
1973
+ const resetAfterSeconds = nonNegativeNumber(get("x-ratelimit-reset-after"));
1974
+ if (resetAfterSeconds !== void 0) {
1975
+ const delayMs = resetAfterSeconds * 1e3;
1976
+ if (Number.isFinite(delayMs))
1977
+ return Math.round(delayMs);
1978
+ }
1979
+ return void 0;
1980
+ }
1981
+ function resolveRequestRateRetryDelay(headers, nowMs = Date.now()) {
1982
+ const advertisedDelayMs = parseRetryAfterMs(headers, nowMs);
1983
+ const requestedDelayMs = advertisedDelayMs ?? REQUEST_RATE_FALLBACK_DELAY_MS;
1984
+ return {
1985
+ delayMs: Math.min(requestedDelayMs, MAX_RETRY_DELAY),
1986
+ ...advertisedDelayMs !== void 0 ? { advertisedDelayMs } : {},
1987
+ capped: requestedDelayMs > MAX_RETRY_DELAY
1988
+ };
1989
+ }
1990
+ function nonNegativeNumber(value) {
1991
+ if (value === null || value.trim() === "")
1992
+ return void 0;
1993
+ const parsed = Number(value);
1994
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
1995
+ }
1996
+ var KIRO_REASON_CODES = Object.freeze({
1997
+ /** Request body exceeded the service's size threshold. */
1998
+ CONTENT_LENGTH_EXCEEDS_THRESHOLD: "CONTENT_LENGTH_EXCEEDS_THRESHOLD",
1999
+ /** Prose-only size rejection; the service sends no reason code for this one. */
2000
+ INPUT_TOO_LONG: "Input is too long",
2001
+ /** Monthly request quota exhausted — hard limit, not transient. */
2002
+ MONTHLY_REQUEST_COUNT: "MONTHLY_REQUEST_COUNT",
2003
+ /** Model capacity temporarily unavailable — transient, worth retrying. */
2004
+ INSUFFICIENT_MODEL_CAPACITY: "INSUFFICIENT_MODEL_CAPACITY",
2005
+ /** Short-window request throttle — retry only within the provider budget. */
2006
+ USER_REQUEST_RATE_EXCEEDED: "USER_REQUEST_RATE_EXCEEDED",
2007
+ /**
2008
+ * Generic request-validation rejection, returned for a malformed body of any
2009
+ * size (empty `content`, history referencing tools absent from the catalog).
2010
+ * Not a size signal: classifying it as "too big" makes the caller compact a
2011
+ * history that was never the problem, a loop it can never satisfy.
2012
+ */
2013
+ REQUEST_BODY_INVALID: "REQUEST_BODY_INVALID"
2014
+ });
2015
+ var TOO_BIG_PATTERNS = Object.freeze([
2016
+ KIRO_REASON_CODES.CONTENT_LENGTH_EXCEEDS_THRESHOLD,
2017
+ KIRO_REASON_CODES.INPUT_TOO_LONG
2018
+ ]);
2019
+ var NON_RETRYABLE_BODY_PATTERNS = Object.freeze([KIRO_REASON_CODES.MONTHLY_REQUEST_COUNT]);
2020
+ var CAPACITY_PATTERN = KIRO_REASON_CODES.INSUFFICIENT_MODEL_CAPACITY;
2021
+ var CAPACITY_MAX_RETRIES = 3;
2022
+ var CAPACITY_BASE_DELAY_MS = 5e3;
2023
+ var capacityRetryConfig = {
2024
+ maxRetries: CAPACITY_MAX_RETRIES,
2025
+ baseDelayMs: CAPACITY_BASE_DELAY_MS
2026
+ };
2027
+ function isTooBigError(status, errorText) {
2028
+ return status === 413 || status === 400 && TOO_BIG_PATTERNS.some((p) => errorText.includes(p));
2029
+ }
2030
+ function isNonRetryableBodyError(errorText) {
2031
+ return NON_RETRYABLE_BODY_PATTERNS.some((p) => errorText.includes(p));
2032
+ }
2033
+ function isCapacityError(errorText) {
2034
+ return errorText.includes(CAPACITY_PATTERN);
1806
2035
  }
1807
2036
 
1808
- // ../kiro-core/dist/index.js
1809
- init_debug();
1810
- init_effort();
1811
- init_endpoints();
2037
+ // ../kiro-core/dist/errors.js
2038
+ var REASON_CODE_MARKERS = [
2039
+ KIRO_REASON_CODES.CONTENT_LENGTH_EXCEEDS_THRESHOLD,
2040
+ KIRO_REASON_CODES.MONTHLY_REQUEST_COUNT,
2041
+ KIRO_REASON_CODES.INSUFFICIENT_MODEL_CAPACITY,
2042
+ KIRO_REASON_CODES.REQUEST_BODY_INVALID
2043
+ ];
2044
+ var KiroApiError = class extends Error {
2045
+ status;
2046
+ reasonCode;
2047
+ retryAfterMs;
2048
+ providerAttempts;
2049
+ constructor(message, status, reasonCode, retryAfterMs, providerAttempts) {
2050
+ super(message);
2051
+ this.status = status;
2052
+ this.reasonCode = reasonCode;
2053
+ this.retryAfterMs = retryAfterMs;
2054
+ this.providerAttempts = providerAttempts;
2055
+ this.name = "KiroApiError";
2056
+ }
2057
+ };
2058
+ function extractKiroReasonCode(errorText) {
2059
+ if (!errorText)
2060
+ return void 0;
2061
+ const trimmed = errorText.trim();
2062
+ if (trimmed.startsWith("{")) {
2063
+ try {
2064
+ const parsed = JSON.parse(trimmed);
2065
+ const reason = parsed.reason ?? parsed.reasonCode;
2066
+ if (typeof reason === "string" && reason.length > 0)
2067
+ return reason;
2068
+ } catch {
2069
+ }
2070
+ }
2071
+ return REASON_CODE_MARKERS.find((code) => errorText.includes(code));
2072
+ }
1812
2073
 
1813
2074
  // ../kiro-core/dist/event-parser.js
2075
+ var KIRO_EVENT_KEYS = [
2076
+ "assistantResponseEvent",
2077
+ "codeReferenceEvent",
2078
+ "contextUsageEvent",
2079
+ "documentCitationEvent",
2080
+ "error",
2081
+ "metadataEvent",
2082
+ "meteringEvent",
2083
+ "reasoningContentEvent",
2084
+ "serviceUnavailableError",
2085
+ "throttlingError",
2086
+ "toolResultEvent",
2087
+ "toolUseEvent",
2088
+ "validationError"
2089
+ ];
2090
+ var KIRO_EVENT_KEY_SET = new Set(KIRO_EVENT_KEYS);
2091
+ var KIRO_ERROR_MEMBERS = {
2092
+ error: { kind: "internalServer", exception: "InternalServerException" },
2093
+ throttlingError: { kind: "throttling", exception: "ThrottlingException" },
2094
+ validationError: { kind: "validation", exception: "ValidationException" },
2095
+ serviceUnavailableError: { kind: "serviceUnavailable", exception: "ServiceUnavailableException" }
2096
+ };
2097
+ var KIRO_ERROR_TOKENS = {
2098
+ ...KIRO_ERROR_MEMBERS,
2099
+ InternalServerException: KIRO_ERROR_MEMBERS.error,
2100
+ ThrottlingException: KIRO_ERROR_MEMBERS.throttlingError,
2101
+ ValidationException: KIRO_ERROR_MEMBERS.validationError,
2102
+ ServiceUnavailableException: KIRO_ERROR_MEMBERS.serviceUnavailableError
2103
+ };
2104
+ function lookupKiroErrorMember(key) {
2105
+ return Object.hasOwn(KIRO_ERROR_TOKENS, key) ? KIRO_ERROR_TOKENS[key] : void 0;
2106
+ }
2107
+ var num = (v) => typeof v === "number" ? v : void 0;
2108
+ var str = (v) => typeof v === "string" ? v : void 0;
1814
2109
  function tokenCount(value) {
1815
2110
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1816
2111
  }
@@ -1829,30 +2124,136 @@ var CACHE_WRITE_KEYS = [
1829
2124
  "cacheCreationInputTokens",
1830
2125
  "cacheWriteTokens"
1831
2126
  ];
1832
- function parseKiroEvent(parsed) {
1833
- if (parsed.content !== void 0)
1834
- return { type: "content", data: parsed.content };
1835
- if (typeof parsed.text === "string")
1836
- return { type: "thinkingText", data: parsed.text };
1837
- if (typeof parsed.signature === "string")
1838
- return { type: "thinkingSignature", data: parsed.signature };
2127
+ function toolInput(raw) {
2128
+ if (typeof raw === "string")
2129
+ return raw;
2130
+ if (raw && typeof raw === "object" && Object.keys(raw).length > 0) {
2131
+ return JSON.stringify(raw);
2132
+ }
2133
+ return "";
2134
+ }
2135
+ function parseToolUse(parsed) {
1839
2136
  if (parsed.name && parsed.toolUseId) {
1840
- const input = typeof parsed.input === "string" ? parsed.input : parsed.input && typeof parsed.input === "object" && Object.keys(parsed.input).length > 0 ? JSON.stringify(parsed.input) : "";
1841
2137
  return {
1842
2138
  type: "toolUse",
1843
2139
  data: {
1844
2140
  name: parsed.name,
1845
2141
  toolUseId: parsed.toolUseId,
1846
- input,
2142
+ input: toolInput(parsed.input),
1847
2143
  stop: parsed.stop
1848
2144
  }
1849
2145
  };
1850
2146
  }
2147
+ if (parsed.input !== void 0) {
2148
+ return { type: "toolUseInput", data: { input: toolInput(parsed.input) } };
2149
+ }
2150
+ if (parsed.stop !== void 0)
2151
+ return { type: "toolUseStop", data: { stop: parsed.stop } };
2152
+ return null;
2153
+ }
2154
+ function parseMetadata(parsed) {
2155
+ const tu = parsed.tokenUsage ?? {};
2156
+ const data = {
2157
+ inputTokens: tokenCount(tu.uncachedInputTokens) ?? tokenCount(tu.inputTokens),
2158
+ outputTokens: tokenCount(tu.outputTokens),
2159
+ totalTokens: tokenCount(tu.totalTokens),
2160
+ cacheReadInputTokens: firstTokenCount(tu, CACHE_READ_KEYS),
2161
+ cacheWriteInputTokens: firstTokenCount(tu, CACHE_WRITE_KEYS),
2162
+ contextUsagePercentage: num(tu.contextUsagePercentage),
2163
+ normalizedTokenUsage: num(tu.normalizedTokenUsage),
2164
+ rawStopReason: str(parsed.stopReason),
2165
+ stopDetails: parsed.stopDetails && typeof parsed.stopDetails === "object" ? parsed.stopDetails : void 0
2166
+ };
2167
+ for (const k of Object.keys(data)) {
2168
+ if (data[k] === void 0)
2169
+ delete data[k];
2170
+ }
2171
+ return Object.keys(data).length > 0 ? { type: "usage", data } : null;
2172
+ }
2173
+ function parseError(parsed, kind, fallbackName) {
2174
+ const rawError = parsed.error ?? parsed.Error;
2175
+ const error2 = typeof rawError === "string" ? rawError : rawError !== void 0 ? JSON.stringify(rawError) : str(parsed.name) ?? fallbackName;
2176
+ const message = parsed.message ?? parsed.Message ?? parsed.reason;
2177
+ const data = { error: error2, kind };
2178
+ if (typeof message === "string")
2179
+ data.message = message;
2180
+ const reason = str(parsed.reason);
2181
+ if (reason !== void 0)
2182
+ data.reason = reason;
2183
+ const retryAfterMilliseconds = num(parsed.retryAfterMilliseconds);
2184
+ if (retryAfterMilliseconds !== void 0)
2185
+ data.retryAfterMilliseconds = retryAfterMilliseconds;
2186
+ return { type: "error", data };
2187
+ }
2188
+ function parseKiroEvent(key, parsed) {
2189
+ switch (key) {
2190
+ case "assistantResponseEvent": {
2191
+ const content = str(parsed.content);
2192
+ return content !== void 0 ? { type: "content", data: content } : null;
2193
+ }
2194
+ case "reasoningContentEvent": {
2195
+ const text = str(parsed.text);
2196
+ if (text !== void 0)
2197
+ return { type: "thinkingText", data: text };
2198
+ const signature = str(parsed.signature);
2199
+ if (signature !== void 0)
2200
+ return { type: "thinkingSignature", data: signature };
2201
+ return { type: "ignored", data: { key } };
2202
+ }
2203
+ case "toolUseEvent":
2204
+ return parseToolUse(parsed);
2205
+ case "contextUsageEvent": {
2206
+ const pct = num(parsed.contextUsagePercentage);
2207
+ return pct !== void 0 ? { type: "contextUsage", data: { contextUsagePercentage: pct } } : null;
2208
+ }
2209
+ case "metadataEvent":
2210
+ return parseMetadata(parsed);
2211
+ case "meteringEvent":
2212
+ return {
2213
+ type: "metering",
2214
+ data: { credits: tokenCount(parsed.usage), unit: str(parsed.unit), unitPlural: str(parsed.unitPlural) }
2215
+ };
2216
+ // Reachable when a member that models an exception is delivered as an
2217
+ // ordinary event frame. The real wire uses exception framing, handled by
2218
+ // parseKiroExceptionFrame, but both routes must agree.
2219
+ case "error":
2220
+ case "throttlingError":
2221
+ case "validationError":
2222
+ case "serviceUnavailableError": {
2223
+ const member = lookupKiroErrorMember(key);
2224
+ return parseError(parsed, member.kind, member.exception);
2225
+ }
2226
+ // Known members with no consumer yet: explicitly ignored, not unparseable.
2227
+ case "codeReferenceEvent":
2228
+ case "documentCitationEvent":
2229
+ case "toolResultEvent":
2230
+ return { type: "ignored", data: { key } };
2231
+ default: {
2232
+ const member = lookupKiroErrorMember(key);
2233
+ if (member)
2234
+ return parseError(parsed, member.kind, member.exception);
2235
+ return parseKiroEventByShape(parsed);
2236
+ }
2237
+ }
2238
+ }
2239
+ function parseKiroExceptionFrame(key, parsed) {
2240
+ const member = lookupKiroErrorMember(key);
2241
+ if (!member)
2242
+ return null;
2243
+ const event = parseError(parsed, member.kind, member.exception);
2244
+ return event.data;
2245
+ }
2246
+ function parseKiroEventByShape(parsed) {
2247
+ if (parsed.content !== void 0)
2248
+ return { type: "content", data: parsed.content };
2249
+ if (typeof parsed.text === "string")
2250
+ return { type: "thinkingText", data: parsed.text };
2251
+ if (typeof parsed.signature === "string")
2252
+ return { type: "thinkingSignature", data: parsed.signature };
2253
+ if (parsed.name && parsed.toolUseId)
2254
+ return parseToolUse(parsed);
1851
2255
  if (parsed.input !== void 0 && !parsed.name) {
1852
- return {
1853
- type: "toolUseInput",
1854
- data: { input: typeof parsed.input === "string" ? parsed.input : JSON.stringify(parsed.input) }
1855
- };
2256
+ return { type: "toolUseInput", data: { input: toolInput(parsed.input) } };
1856
2257
  }
1857
2258
  if (parsed.stop !== void 0 && parsed.contextUsagePercentage === void 0)
1858
2259
  return { type: "toolUseStop", data: { stop: parsed.stop } };
@@ -1860,42 +2261,23 @@ function parseKiroEvent(parsed) {
1860
2261
  return { type: "contextUsage", data: { contextUsagePercentage: parsed.contextUsagePercentage } };
1861
2262
  if (parsed.followupPrompt !== void 0)
1862
2263
  return { type: "followupPrompt", data: parsed.followupPrompt };
2264
+ if (parsed.tokenUsage !== void 0 || parsed.stopReason !== void 0 || parsed.stopDetails !== void 0) {
2265
+ return parseMetadata(parsed);
2266
+ }
1863
2267
  if (parsed.error !== void 0 || parsed.Error !== void 0) {
1864
- const error2 = parsed.error || parsed.Error || "unknown";
1865
- const message = parsed.message || parsed.Message || parsed.reason;
1866
- return { type: "error", data: { error: typeof error2 === "string" ? error2 : JSON.stringify(error2), message } };
1867
- }
1868
- if (parsed.usage !== void 0) {
1869
- if (typeof parsed.usage === "number") {
1870
- const credits = tokenCount(parsed.usage);
1871
- if (credits === void 0)
1872
- return null;
1873
- return {
1874
- type: "usage",
1875
- data: {
1876
- credits,
1877
- ...typeof parsed.unit === "string" && parsed.unit ? { creditUnit: parsed.unit } : {}
1878
- }
1879
- };
1880
- }
1881
- const u = parsed.usage;
1882
- const cacheReadTokens = firstTokenCount(u, CACHE_READ_KEYS);
1883
- const cacheWriteTokens = firstTokenCount(u, CACHE_WRITE_KEYS);
2268
+ return parseError(parsed, "unknown", "unknown");
2269
+ }
2270
+ if (typeof parsed.usage === "number") {
1884
2271
  return {
1885
- type: "usage",
1886
- data: {
1887
- inputTokens: tokenCount(u.inputTokens),
1888
- outputTokens: tokenCount(u.outputTokens),
1889
- ...cacheReadTokens !== void 0 ? { cacheReadTokens } : {},
1890
- ...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
1891
- }
2272
+ type: "metering",
2273
+ data: { credits: tokenCount(parsed.usage), unit: str(parsed.unit), unitPlural: str(parsed.unitPlural) }
1892
2274
  };
1893
2275
  }
1894
2276
  return null;
1895
2277
  }
1896
2278
 
1897
2279
  // ../kiro-core/dist/transform.js
1898
- import { createHash } from "node:crypto";
2280
+ import { createHash as createHash2 } from "node:crypto";
1899
2281
  var TOOL_RESULT_LIMIT = 25e4;
1900
2282
  var EMPTY_CONTENT_PLACEHOLDER = "Please proceed with the task.";
1901
2283
  function sanitizeSurrogates(text) {
@@ -1913,7 +2295,7 @@ var KIRO_TOOL_USE_ID_PATTERN = /^[a-zA-Z0-9_.:-]{1,64}$/;
1913
2295
  function toKiroToolUseId(toolUseId) {
1914
2296
  if (KIRO_TOOL_USE_ID_PATTERN.test(toolUseId))
1915
2297
  return toolUseId;
1916
- const digest = createHash("sha256").update(toolUseId).digest("base64url").slice(0, 32);
2298
+ const digest = createHash2("sha256").update(toolUseId).digest("base64url").slice(0, 32);
1917
2299
  return `pi_${digest}`;
1918
2300
  }
1919
2301
  function normalizeMessages(messages) {
@@ -2927,8 +3309,8 @@ function bytePairEncode(piece, ranks) {
2927
3309
  return [ranks.get(piece.join(","))];
2928
3310
  return bytePairMerge(piece, ranks).map((p) => ranks.get(piece.slice(p.start, p.end).join(","))).filter((x) => x != null);
2929
3311
  }
2930
- function escapeRegex(str) {
2931
- return str.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
3312
+ function escapeRegex(str2) {
3313
+ return str2.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
2932
3314
  }
2933
3315
  var _Tiktoken = class {
2934
3316
  /** @internal */
@@ -3075,6 +3457,7 @@ var KiroResponseAssembler = class {
3075
3457
  totalContent = "";
3076
3458
  lastContentData = "";
3077
3459
  usageEvent = null;
3460
+ meteringEvent = null;
3078
3461
  receivedContextUsage = false;
3079
3462
  thinkingParser = null;
3080
3463
  nativeThinkingBlockIndex = null;
@@ -3082,16 +3465,19 @@ var KiroResponseAssembler = class {
3082
3465
  textBlockIndex = null;
3083
3466
  emittedToolCalls = 0;
3084
3467
  sawAnyToolCalls = false;
3468
+ droppedToolCalls = [];
3085
3469
  currentToolCall = null;
3470
+ stopReason = "stop";
3086
3471
  constructor(model, thinkingEnabled) {
3087
3472
  this.model = model;
3088
3473
  this.thinkingEnabled = thinkingEnabled;
3089
3474
  }
3090
- /** Clear per-attempt state. Block indexes and accumulated usage are kept. */
3475
+ /** Clear per-attempt state. Only block indexes are kept. */
3091
3476
  beginAttempt() {
3092
3477
  this.totalContent = "";
3093
3478
  this.lastContentData = "";
3094
3479
  this.usageEvent = null;
3480
+ this.meteringEvent = null;
3095
3481
  this.receivedContextUsage = false;
3096
3482
  this.thinkingParser = this.thinkingEnabled ? new ThinkingTagParser(this.blocks) : null;
3097
3483
  this.nativeThinkingBlockIndex = null;
@@ -3099,7 +3485,17 @@ var KiroResponseAssembler = class {
3099
3485
  this.textBlockIndex = null;
3100
3486
  this.emittedToolCalls = 0;
3101
3487
  this.sawAnyToolCalls = false;
3488
+ this.droppedToolCalls = [];
3102
3489
  this.currentToolCall = null;
3490
+ this.usage.input = 0;
3491
+ this.usage.output = 0;
3492
+ this.usage.totalTokens = 0;
3493
+ this.usage.cost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
3494
+ delete this.usage.cacheRead;
3495
+ delete this.usage.cacheWrite;
3496
+ delete this.usage.contextPercent;
3497
+ delete this.usage.credits;
3498
+ delete this.usage.creditUnit;
3103
3499
  }
3104
3500
  /** Hand over the events buffered so far. */
3105
3501
  takeEvents() {
@@ -3176,11 +3572,17 @@ var KiroResponseAssembler = class {
3176
3572
  break;
3177
3573
  }
3178
3574
  case "usage": {
3179
- this.usageEvent = event.data;
3575
+ this.usageEvent = { ...this.usageEvent ?? {}, ...event.data };
3180
3576
  if (debugEnabled())
3181
3577
  debugLog("response.usageRaw", payload);
3182
3578
  break;
3183
3579
  }
3580
+ case "metering": {
3581
+ this.meteringEvent = event.data;
3582
+ if (debugEnabled())
3583
+ debugLog("stream.metering", [event.data]);
3584
+ break;
3585
+ }
3184
3586
  }
3185
3587
  }
3186
3588
  /**
@@ -3188,8 +3590,12 @@ var KiroResponseAssembler = class {
3188
3590
  * text-dialect recovery and echo-stripping passes.
3189
3591
  */
3190
3592
  endTurn() {
3191
- if (this.currentToolCall && this.emitToolCall(this.currentToolCall))
3192
- this.emittedToolCalls++;
3593
+ if (this.currentToolCall) {
3594
+ if (this.emitToolCall(this.currentToolCall))
3595
+ this.emittedToolCalls++;
3596
+ else
3597
+ this.droppedToolCalls.push(this.currentToolCall.name);
3598
+ }
3193
3599
  this.currentToolCall = null;
3194
3600
  this.endNativeThinking();
3195
3601
  if (this.thinkingParser) {
@@ -3200,13 +3606,16 @@ var KiroResponseAssembler = class {
3200
3606
  this.stripEchoNoise();
3201
3607
  const responseText = this.textBlockIndex === null ? "" : this.blocks.getText(this.textBlockIndex);
3202
3608
  const hasText2 = responseText.length > 0;
3609
+ this.stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
3203
3610
  return {
3204
3611
  responseText,
3205
3612
  hasText: hasText2,
3206
3613
  sawAnyToolCalls: this.sawAnyToolCalls,
3207
3614
  emittedToolCalls: this.emittedToolCalls,
3208
3615
  isEchoLoop: hasText2 && !this.sawAnyToolCalls && ECHO_NOISE_PATTERN.test(responseText),
3209
- isEmpty: !hasText2 && !this.sawAnyToolCalls
3616
+ isEmpty: !hasText2 && !this.sawAnyToolCalls,
3617
+ stopReason: this.stopReason,
3618
+ droppedToolCalls: this.droppedToolCalls
3210
3619
  };
3211
3620
  }
3212
3621
  /** Drop an echo the caller decided not to retry, so it is not read as a continuation signal. */
@@ -3214,6 +3623,10 @@ var KiroResponseAssembler = class {
3214
3623
  if (this.textBlockIndex !== null)
3215
3624
  this.blocks.setText(this.textBlockIndex, "");
3216
3625
  }
3626
+ /** Kinds of the blocks this attempt produced, for the exhaustion diagnostic. */
3627
+ contentKinds() {
3628
+ return this.blocks.kinds();
3629
+ }
3217
3630
  /** Close the text block and settle usage and the stop reason. */
3218
3631
  complete() {
3219
3632
  if (this.textBlockIndex !== null)
@@ -3221,17 +3634,17 @@ var KiroResponseAssembler = class {
3221
3634
  if (this.usageEvent?.inputTokens !== void 0)
3222
3635
  this.usage.input = this.usageEvent.inputTokens;
3223
3636
  this.usage.output = this.usageEvent?.outputTokens ?? countTokens(this.totalContent);
3224
- this.usage.totalTokens = this.usage.input + this.usage.output;
3225
- if (this.usageEvent?.cacheReadTokens !== void 0)
3226
- this.usage.cacheRead = this.usageEvent.cacheReadTokens;
3227
- if (this.usageEvent?.cacheWriteTokens !== void 0)
3228
- this.usage.cacheWrite = this.usageEvent.cacheWriteTokens;
3229
- if (this.usageEvent?.credits !== void 0)
3230
- this.usage.credits = this.usageEvent.credits;
3231
- if (this.usageEvent?.creditUnit !== void 0)
3232
- this.usage.creditUnit = this.usageEvent.creditUnit;
3637
+ this.usage.totalTokens = this.usageEvent?.totalTokens ?? this.usage.input + (this.usageEvent?.cacheReadInputTokens ?? 0) + (this.usageEvent?.cacheWriteInputTokens ?? 0) + this.usage.output;
3638
+ if (this.usageEvent?.cacheReadInputTokens !== void 0)
3639
+ this.usage.cacheRead = this.usageEvent.cacheReadInputTokens;
3640
+ if (this.usageEvent?.cacheWriteInputTokens !== void 0)
3641
+ this.usage.cacheWrite = this.usageEvent.cacheWriteInputTokens;
3642
+ if (this.meteringEvent?.credits !== void 0)
3643
+ this.usage.credits = this.meteringEvent.credits;
3644
+ if (this.meteringEvent?.unit !== void 0)
3645
+ this.usage.creditUnit = this.meteringEvent.unit;
3233
3646
  this.usage.cost = calculateKiroCost(this.model.cost, this.usage);
3234
- const stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
3647
+ const stopReason = this.stopReason;
3235
3648
  debugLog("response.done", {
3236
3649
  stopReason,
3237
3650
  receivedContextUsage: this.receivedContextUsage,
@@ -3240,7 +3653,12 @@ var KiroResponseAssembler = class {
3240
3653
  textLen: this.textBlockIndex === null ? 0 : this.blocks.getText(this.textBlockIndex).length,
3241
3654
  usage: this.usage
3242
3655
  });
3243
- return { stopReason, usage: this.usage };
3656
+ return {
3657
+ stopReason,
3658
+ usage: this.usage,
3659
+ wireUsage: this.usageEvent,
3660
+ metering: this.meteringEvent
3661
+ };
3244
3662
  }
3245
3663
  ensureNativeThinkingBlock() {
3246
3664
  if (this.nativeThinkingBlockIndex === null)
@@ -3275,6 +3693,8 @@ var KiroResponseAssembler = class {
3275
3693
  return;
3276
3694
  if (this.emitToolCall(this.currentToolCall))
3277
3695
  this.emittedToolCalls++;
3696
+ else
3697
+ this.droppedToolCalls.push(this.currentToolCall.name);
3278
3698
  this.currentToolCall = null;
3279
3699
  }
3280
3700
  /**
@@ -3316,6 +3736,8 @@ var KiroResponseAssembler = class {
3316
3736
  for (const call of recovered) {
3317
3737
  if (this.emitToolCall({ toolUseId: call.toolUseId, name: call.name, input: JSON.stringify(call.arguments) })) {
3318
3738
  this.emittedToolCalls++;
3739
+ } else {
3740
+ this.droppedToolCalls.push(call.name);
3319
3741
  }
3320
3742
  }
3321
3743
  }
@@ -3334,13 +3756,13 @@ var KiroResponseAssembler = class {
3334
3756
  }
3335
3757
  };
3336
3758
 
3337
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/index.js
3759
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/index.js
3338
3760
  import { getRandomValues } from "node:crypto";
3339
3761
 
3340
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/is-array-buffer/is-array-buffer.js
3762
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/is-array-buffer/is-array-buffer.js
3341
3763
  var isArrayBuffer = (arg) => typeof ArrayBuffer === "function" && arg instanceof ArrayBuffer || Object.prototype.toString.call(arg) === "[object ArrayBuffer]";
3342
3764
 
3343
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-buffer-from/buffer-from.js
3765
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-buffer-from/buffer-from.js
3344
3766
  var fromArrayBuffer = (input, offset = 0, length = input.byteLength - offset) => {
3345
3767
  if (!isArrayBuffer(input)) {
3346
3768
  throw new TypeError(`The "input" argument must be ArrayBuffer. Received type ${typeof input} (${input})`);
@@ -3354,7 +3776,7 @@ var fromString = (input, encoding) => {
3354
3776
  return encoding ? Buffer.from(input, encoding) : Buffer.from(input);
3355
3777
  };
3356
3778
 
3357
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-base64/fromBase64.js
3779
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-base64/fromBase64.js
3358
3780
  var BASE64_REGEX = /^[A-Za-z0-9+/]*={0,2}$/;
3359
3781
  var fromBase64 = (input) => {
3360
3782
  if (input.length * 3 % 4 !== 0) {
@@ -3367,13 +3789,13 @@ var fromBase64 = (input) => {
3367
3789
  return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
3368
3790
  };
3369
3791
 
3370
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-utf8/fromUtf8.js
3792
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-utf8/fromUtf8.js
3371
3793
  var fromUtf8 = (input) => {
3372
3794
  const buf = fromString(input, "utf8");
3373
3795
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength / Uint8Array.BYTES_PER_ELEMENT);
3374
3796
  };
3375
3797
 
3376
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-base64/toBase64.js
3798
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-base64/toBase64.js
3377
3799
  var toBase64 = (_input) => {
3378
3800
  let input;
3379
3801
  if (typeof _input === "string") {
@@ -3387,7 +3809,7 @@ var toBase64 = (_input) => {
3387
3809
  return fromArrayBuffer(input.buffer, input.byteOffset, input.byteLength).toString("base64");
3388
3810
  };
3389
3811
 
3390
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-stream/blob/Uint8ArrayBlobAdapter.js
3812
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-stream/blob/Uint8ArrayBlobAdapter.js
3391
3813
  function bindUint8ArrayBlobAdapter(toUtf82, fromUtf82, toBase642, fromBase642) {
3392
3814
  return class Uint8ArrayBlobAdapter2 extends Uint8Array {
3393
3815
  static fromString(source, encoding = "utf-8") {
@@ -3412,7 +3834,7 @@ function bindUint8ArrayBlobAdapter(toUtf82, fromUtf82, toBase642, fromBase642) {
3412
3834
  };
3413
3835
  }
3414
3836
 
3415
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-utf8/toUtf8.js
3837
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-utf8/toUtf8.js
3416
3838
  var toUtf8 = (input) => {
3417
3839
  if (typeof input === "string") {
3418
3840
  return input;
@@ -3423,7 +3845,7 @@ var toUtf8 = (input) => {
3423
3845
  return fromArrayBuffer(input.buffer, input.byteOffset, input.byteLength).toString("utf8");
3424
3846
  };
3425
3847
 
3426
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/uuid/v4.js
3848
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/uuid/v4.js
3427
3849
  var decimalToHex = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
3428
3850
  function bindV4(getRandomValues2) {
3429
3851
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
@@ -3438,12 +3860,12 @@ function bindV4(getRandomValues2) {
3438
3860
  };
3439
3861
  }
3440
3862
 
3441
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/transport/hasOwn.js
3863
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/transport/hasOwn.js
3442
3864
  function hasOwn(o, k) {
3443
3865
  return Object.prototype.hasOwnProperty.call(o, k);
3444
3866
  }
3445
3867
 
3446
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/util-hex-encoding/hex-encoding.js
3868
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/util-hex-encoding/hex-encoding.js
3447
3869
  var SHORT_TO_HEX = {};
3448
3870
  var HEX_TO_SHORT = {};
3449
3871
  for (let i = 0; i < 256; i++) {
@@ -3477,13 +3899,13 @@ function toHex(bytes) {
3477
3899
  return out;
3478
3900
  }
3479
3901
 
3480
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/serde/index.js
3902
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/serde/index.js
3481
3903
  var Uint8ArrayBlobAdapter = class extends bindUint8ArrayBlobAdapter(toUtf8, fromUtf8, toBase64, fromBase64) {
3482
3904
  };
3483
3905
  var _getRandomValues = getRandomValues;
3484
3906
  var v4 = bindV4(_getRandomValues);
3485
3907
 
3486
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/checksum/crc32/Crc32Js.js
3908
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/checksum/crc32/Crc32Js.js
3487
3909
  var CRC32_TABLE = new Uint32Array(256);
3488
3910
  for (let i = 0; i < 256; ++i) {
3489
3911
  let c = i;
@@ -3515,7 +3937,7 @@ var Crc32Js = class {
3515
3937
  }
3516
3938
  };
3517
3939
 
3518
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/checksum/crc32/Crc32Node.js
3940
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/checksum/crc32/Crc32Node.js
3519
3941
  import * as zlib from "node:zlib";
3520
3942
  var zlibCrc32 = typeof zlib.crc32 === "function" ? zlib.crc32 : void 0;
3521
3943
  var Crc32Node = zlibCrc32 ? buildNativeClass(zlibCrc32) : Crc32Js;
@@ -3540,7 +3962,7 @@ function buildNativeClass(nativeCrc32) {
3540
3962
  };
3541
3963
  }
3542
3964
 
3543
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/Int64.js
3965
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/Int64.js
3544
3966
  var Int64 = class _Int64 {
3545
3967
  bytes;
3546
3968
  constructor(bytes) {
@@ -3585,7 +4007,7 @@ function negate(bytes) {
3585
4007
  }
3586
4008
  }
3587
4009
 
3588
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js
4010
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js
3589
4011
  var HeaderMarshaller = class {
3590
4012
  toUtf8;
3591
4013
  fromUtf8;
@@ -3771,7 +4193,7 @@ var TIMESTAMP_TAG = "timestamp";
3771
4193
  var UUID_TAG = "uuid";
3772
4194
  var UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
3773
4195
 
3774
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/splitMessage.js
4196
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/splitMessage.js
3775
4197
  var PRELUDE_MEMBER_LENGTH = 4;
3776
4198
  var PRELUDE_LENGTH = PRELUDE_MEMBER_LENGTH * 2;
3777
4199
  var CHECKSUM_LENGTH = 4;
@@ -3803,7 +4225,7 @@ function splitMessage({ byteLength, byteOffset, buffer }) {
3803
4225
  };
3804
4226
  }
3805
4227
 
3806
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/EventStreamCodec.js
4228
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/EventStreamCodec.js
3807
4229
  var EventStreamCodec = class {
3808
4230
  headerMarshaller;
3809
4231
  messageBuffer;
@@ -3869,7 +4291,7 @@ var EventStreamCodec = class {
3869
4291
  }
3870
4292
  };
3871
4293
 
3872
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/MessageDecoderStream.js
4294
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/MessageDecoderStream.js
3873
4295
  var MessageDecoderStream = class {
3874
4296
  options;
3875
4297
  constructor(options) {
@@ -3886,7 +4308,7 @@ var MessageDecoderStream = class {
3886
4308
  }
3887
4309
  };
3888
4310
 
3889
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/MessageEncoderStream.js
4311
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/MessageEncoderStream.js
3890
4312
  var MessageEncoderStream = class {
3891
4313
  options;
3892
4314
  constructor(options) {
@@ -3906,7 +4328,7 @@ var MessageEncoderStream = class {
3906
4328
  }
3907
4329
  };
3908
4330
 
3909
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/SmithyMessageDecoderStream.js
4331
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/SmithyMessageDecoderStream.js
3910
4332
  var SmithyMessageDecoderStream = class {
3911
4333
  options;
3912
4334
  constructor(options) {
@@ -3925,7 +4347,7 @@ var SmithyMessageDecoderStream = class {
3925
4347
  }
3926
4348
  };
3927
4349
 
3928
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/SmithyMessageEncoderStream.js
4350
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/SmithyMessageEncoderStream.js
3929
4351
  var SmithyMessageEncoderStream = class {
3930
4352
  options;
3931
4353
  constructor(options) {
@@ -3942,7 +4364,7 @@ var SmithyMessageEncoderStream = class {
3942
4364
  }
3943
4365
  };
3944
4366
 
3945
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/getChunkedStream.js
4367
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/getChunkedStream.js
3946
4368
  function getChunkedStream(source) {
3947
4369
  let currentMessageTotalLength = 0;
3948
4370
  let currentMessagePendingLength = 0;
@@ -4008,7 +4430,7 @@ function getChunkedStream(source) {
4008
4430
  };
4009
4431
  }
4010
4432
 
4011
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/getUnmarshalledStream.js
4433
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/getUnmarshalledStream.js
4012
4434
  function getMessageUnmarshaller(deserializer, toUtf82) {
4013
4435
  return async function(message) {
4014
4436
  const { value: messageType } = message.headers[":message-type"];
@@ -4040,7 +4462,7 @@ function getMessageUnmarshaller(deserializer, toUtf82) {
4040
4462
  };
4041
4463
  }
4042
4464
 
4043
- // ../../node_modules/.pnpm/@smithy+core@3.33.3/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/EventStreamMarshaller.js
4465
+ // ../../node_modules/.pnpm/@smithy+core@3.34.1/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-serde-universal/EventStreamMarshaller.js
4044
4466
  var EventStreamMarshaller = class {
4045
4467
  eventStreamCodec;
4046
4468
  utfEncoder;
@@ -4075,6 +4497,7 @@ function readKiroEventStream(body, options) {
4075
4497
  const outcome = { firstTokenTimedOut: false, idleTimedOut: false, error: null };
4076
4498
  const idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT;
4077
4499
  const bodyReader = body.getReader();
4500
+ const callerSignal = options.signal;
4078
4501
  async function* frames() {
4079
4502
  let idleTimer = null;
4080
4503
  const resetIdle = () => {
@@ -4086,6 +4509,14 @@ function readKiroEventStream(body, options) {
4086
4509
  });
4087
4510
  }, idleTimeoutMs);
4088
4511
  };
4512
+ const onCallerStreamAbort = () => {
4513
+ void bodyReader.cancel().catch(() => {
4514
+ });
4515
+ };
4516
+ if (callerSignal?.aborted)
4517
+ onCallerStreamAbort();
4518
+ else
4519
+ callerSignal?.addEventListener("abort", onCallerStreamAbort, { once: true });
4089
4520
  const bodyIterable = {
4090
4521
  async *[Symbol.asyncIterator]() {
4091
4522
  try {
@@ -4106,37 +4537,71 @@ function readKiroEventStream(body, options) {
4106
4537
  if (!entry)
4107
4538
  throw new Error("Received an empty event stream message");
4108
4539
  const [key, msg] = entry;
4540
+ if (msg.headers[":message-type"]?.value === "exception") {
4541
+ let parsedException = {};
4542
+ try {
4543
+ const decoded = JSON.parse(utf8Decoder.decode(msg.body));
4544
+ if (decoded && typeof decoded === "object")
4545
+ parsedException = decoded;
4546
+ } catch {
4547
+ }
4548
+ const data = parseKiroExceptionFrame(key, parsedException) ?? {
4549
+ error: key,
4550
+ kind: "unknown",
4551
+ ...typeof parsedException.message === "string" ? { message: parsedException.message } : {},
4552
+ ...typeof parsedException.reason === "string" ? { reason: parsedException.reason } : {},
4553
+ ...typeof parsedException.retryAfterMilliseconds === "number" ? { retryAfterMilliseconds: parsedException.retryAfterMilliseconds } : {}
4554
+ };
4555
+ const error2 = new Error(data.message ? `${data.error}: ${data.message}` : data.error);
4556
+ error2.name = data.error;
4557
+ error2.kiroError = data;
4558
+ return { [key]: error2 };
4559
+ }
4109
4560
  const parsed = JSON.parse(utf8Decoder.decode(msg.body));
4110
4561
  return { [key]: parsed };
4111
4562
  });
4112
4563
  const iterator = eventStream[Symbol.asyncIterator]();
4113
4564
  let gotFirstToken = false;
4114
- const FIRST_TOKEN_SENTINEL = Symbol("firstTokenTimeout");
4565
+ const FIRST_TOKEN_SENTINEL = /* @__PURE__ */ Symbol("firstTokenTimeout");
4115
4566
  try {
4116
4567
  while (true) {
4568
+ if (callerSignal?.aborted) {
4569
+ throw callerSignal.reason ?? new Error("Request aborted");
4570
+ }
4117
4571
  let iterResult;
4118
4572
  try {
4119
4573
  if (!gotFirstToken) {
4120
4574
  const readPromise = iterator.next();
4121
- const result = await Promise.race([
4122
- readPromise,
4123
- new Promise((resolve) => setTimeout(() => resolve(FIRST_TOKEN_SENTINEL), options.firstTokenTimeoutMs))
4124
- ]);
4125
- if (result === FIRST_TOKEN_SENTINEL) {
4126
- readPromise.catch(() => {
4127
- });
4128
- void bodyReader.cancel().catch(() => {
4129
- });
4130
- outcome.firstTokenTimedOut = true;
4131
- return;
4575
+ let firstTokenTimer;
4576
+ try {
4577
+ const result = await Promise.race([
4578
+ readPromise,
4579
+ new Promise((resolve) => {
4580
+ firstTokenTimer = setTimeout(() => resolve(FIRST_TOKEN_SENTINEL), options.firstTokenTimeoutMs);
4581
+ })
4582
+ ]);
4583
+ if (result === FIRST_TOKEN_SENTINEL) {
4584
+ readPromise.catch(() => {
4585
+ });
4586
+ void bodyReader.cancel().catch(() => {
4587
+ });
4588
+ outcome.firstTokenTimedOut = true;
4589
+ return;
4590
+ }
4591
+ iterResult = result;
4592
+ gotFirstToken = true;
4593
+ resetIdle();
4594
+ } finally {
4595
+ if (firstTokenTimer !== void 0)
4596
+ clearTimeout(firstTokenTimer);
4132
4597
  }
4133
- iterResult = result;
4134
- gotFirstToken = true;
4135
- resetIdle();
4136
4598
  } else {
4137
4599
  iterResult = await iterator.next();
4138
4600
  }
4139
4601
  } catch (e) {
4602
+ const kiroError = e?.kiroError;
4603
+ if (kiroError)
4604
+ outcome.errorData = kiroError;
4140
4605
  outcome.error = e instanceof Error ? e.message : (typeof e === "object" && e !== null ? JSON.stringify(e) : String(e)) || "Unknown stream error";
4141
4606
  return;
4142
4607
  }
@@ -4144,148 +4609,40 @@ function readKiroEventStream(body, options) {
4144
4609
  if (done)
4145
4610
  return;
4146
4611
  resetIdle();
4147
- const payload = Object.values(value)[0];
4148
- const event = parseKiroEvent(payload);
4612
+ const frameEntry = Object.entries(value)[0];
4613
+ if (!frameEntry)
4614
+ continue;
4615
+ const [frameKey, framePayload] = frameEntry;
4616
+ const event = parseKiroEvent(frameKey, framePayload ?? {});
4149
4617
  if (!event)
4150
4618
  continue;
4619
+ if (event.type === "ignored") {
4620
+ if (debugEnabled())
4621
+ debugLog("stream.events.ignored", [event.data.key]);
4622
+ continue;
4623
+ }
4151
4624
  if (debugEnabled())
4152
4625
  debugLog("stream.events", [event]);
4153
4626
  if (event.type === "error") {
4154
4627
  outcome.error = event.data.message ? `${event.data.error}: ${event.data.message}` : event.data.error;
4628
+ outcome.errorData = event.data;
4155
4629
  void bodyReader.cancel().catch(() => {
4156
4630
  });
4157
4631
  return;
4158
4632
  }
4159
- yield { event, payload };
4633
+ yield { event, payload: framePayload };
4160
4634
  }
4161
4635
  } finally {
4162
4636
  if (idleTimer)
4163
4637
  clearTimeout(idleTimer);
4638
+ callerSignal?.removeEventListener("abort", onCallerStreamAbort);
4164
4639
  }
4165
4640
  }
4166
4641
  return { frames: frames(), outcome };
4167
4642
  }
4168
4643
 
4169
- // ../kiro-core/dist/retry.js
4170
- init_models();
4171
- var FIRST_TOKEN_TIMEOUT = 9e4;
4172
- var REQUEST_HEADER_TIMEOUT = 9e4;
4173
- function firstTokenTimeoutForModel(modelId) {
4174
- if (retryConfig.firstTokenTimeoutMs !== FIRST_TOKEN_TIMEOUT) {
4175
- return retryConfig.firstTokenTimeoutMs;
4176
- }
4177
- const model = kiroModels.find((m) => m.id === modelId);
4178
- return model?.firstTokenTimeout ?? FIRST_TOKEN_TIMEOUT;
4179
- }
4180
- var retryConfig = {
4181
- firstTokenTimeoutMs: FIRST_TOKEN_TIMEOUT,
4182
- requestHeaderTimeoutMs: REQUEST_HEADER_TIMEOUT
4183
- };
4184
- function exponentialBackoff(attempt, baseMs, maxMs) {
4185
- return Math.min(baseMs * 2 ** attempt, maxMs);
4186
- }
4187
- var MAX_RETRY_DELAY = 1e4;
4188
- var REQUEST_RATE_FALLBACK_DELAY_MS = 1e4;
4189
- function extractKiroReason(errorText) {
4190
- if (!errorText)
4191
- return void 0;
4192
- try {
4193
- const parsed = JSON.parse(errorText);
4194
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
4195
- return void 0;
4196
- const reason = parsed.reason;
4197
- return typeof reason === "string" && reason.length > 0 ? reason : void 0;
4198
- } catch {
4199
- return void 0;
4200
- }
4201
- }
4202
- function parseRetryAfterMs(headers, nowMs = Date.now()) {
4203
- const get = headers?.get?.bind(headers);
4204
- if (!get)
4205
- return void 0;
4206
- const milliseconds = nonNegativeNumber(get("retry-after-ms"));
4207
- if (milliseconds !== void 0)
4208
- return Math.round(milliseconds);
4209
- const retryAfter = get("retry-after");
4210
- if (retryAfter !== null && retryAfter.trim() !== "") {
4211
- const seconds = Number(retryAfter);
4212
- if (Number.isFinite(seconds)) {
4213
- if (seconds >= 0) {
4214
- const delayMs = seconds * 1e3;
4215
- if (Number.isFinite(delayMs))
4216
- return Math.round(delayMs);
4217
- }
4218
- } else {
4219
- const dateMs = Date.parse(retryAfter);
4220
- if (!Number.isNaN(dateMs))
4221
- return Math.max(0, dateMs - nowMs);
4222
- }
4223
- }
4224
- const resetAfterSeconds = nonNegativeNumber(get("x-ratelimit-reset-after"));
4225
- if (resetAfterSeconds !== void 0) {
4226
- const delayMs = resetAfterSeconds * 1e3;
4227
- if (Number.isFinite(delayMs))
4228
- return Math.round(delayMs);
4229
- }
4230
- return void 0;
4231
- }
4232
- function resolveRequestRateRetryDelay(headers, nowMs = Date.now()) {
4233
- const advertisedDelayMs = parseRetryAfterMs(headers, nowMs);
4234
- const requestedDelayMs = advertisedDelayMs ?? REQUEST_RATE_FALLBACK_DELAY_MS;
4235
- return {
4236
- delayMs: Math.min(requestedDelayMs, MAX_RETRY_DELAY),
4237
- ...advertisedDelayMs !== void 0 ? { advertisedDelayMs } : {},
4238
- capped: requestedDelayMs > MAX_RETRY_DELAY
4239
- };
4240
- }
4241
- function nonNegativeNumber(value) {
4242
- if (value === null || value.trim() === "")
4243
- return void 0;
4244
- const parsed = Number(value);
4245
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
4246
- }
4247
- var KIRO_REASON_CODES = Object.freeze({
4248
- /** Request body exceeded the service's size threshold. */
4249
- CONTENT_LENGTH_EXCEEDS_THRESHOLD: "CONTENT_LENGTH_EXCEEDS_THRESHOLD",
4250
- /** Prose-only size rejection; the service sends no reason code for this one. */
4251
- INPUT_TOO_LONG: "Input is too long",
4252
- /** Monthly request quota exhausted — hard limit, not transient. */
4253
- MONTHLY_REQUEST_COUNT: "MONTHLY_REQUEST_COUNT",
4254
- /** Model capacity temporarily unavailable — transient, worth retrying. */
4255
- INSUFFICIENT_MODEL_CAPACITY: "INSUFFICIENT_MODEL_CAPACITY",
4256
- /** Short-window request throttle — retry only within the provider budget. */
4257
- USER_REQUEST_RATE_EXCEEDED: "USER_REQUEST_RATE_EXCEEDED",
4258
- /**
4259
- * Generic request-validation rejection, returned for a malformed body of any
4260
- * size (empty `content`, history referencing tools absent from the catalog).
4261
- * Not a size signal: classifying it as "too big" makes the caller compact a
4262
- * history that was never the problem, a loop it can never satisfy.
4263
- */
4264
- REQUEST_BODY_INVALID: "REQUEST_BODY_INVALID"
4265
- });
4266
- var TOO_BIG_PATTERNS = Object.freeze([
4267
- KIRO_REASON_CODES.CONTENT_LENGTH_EXCEEDS_THRESHOLD,
4268
- KIRO_REASON_CODES.INPUT_TOO_LONG
4269
- ]);
4270
- var NON_RETRYABLE_BODY_PATTERNS = Object.freeze([KIRO_REASON_CODES.MONTHLY_REQUEST_COUNT]);
4271
- var CAPACITY_PATTERN = KIRO_REASON_CODES.INSUFFICIENT_MODEL_CAPACITY;
4272
- var CAPACITY_MAX_RETRIES = 3;
4273
- var CAPACITY_BASE_DELAY_MS = 5e3;
4274
- var capacityRetryConfig = {
4275
- maxRetries: CAPACITY_MAX_RETRIES,
4276
- baseDelayMs: CAPACITY_BASE_DELAY_MS
4277
- };
4278
- function isTooBigError(status, errorText) {
4279
- return status === 413 || status === 400 && TOO_BIG_PATTERNS.some((p) => errorText.includes(p));
4280
- }
4281
- function isNonRetryableBodyError(errorText) {
4282
- return NON_RETRYABLE_BODY_PATTERNS.some((p) => errorText.includes(p));
4283
- }
4284
- function isCapacityError(errorText) {
4285
- return errorText.includes(CAPACITY_PATTERN);
4286
- }
4287
-
4288
4644
  // ../kiro-core/dist/stream.js
4645
+ import { createHash as createHash3 } from "node:crypto";
4289
4646
  init_debug();
4290
4647
  init_effort();
4291
4648
  init_endpoints();
@@ -4358,7 +4715,64 @@ function createResponseHeaderDeadline(callerSignal, timeoutMs) {
4358
4715
  };
4359
4716
  }
4360
4717
 
4718
+ // ../kiro-core/dist/usage-tracking.js
4719
+ var DEFAULT_USD_PER_CREDIT = 0.04;
4720
+ var DEFAULT_ESTIMATED_CACHE_TIMEOUT_MS = 5 * 60 * 1e3;
4721
+ var KIRO_USAGE_TRACKING_DISABLED = Object.freeze({
4722
+ estimateDollarValue: false,
4723
+ usdPerCredit: DEFAULT_USD_PER_CREDIT,
4724
+ estimateCacheUsage: false,
4725
+ estimatedCacheTimeout: DEFAULT_ESTIMATED_CACHE_TIMEOUT_MS
4726
+ });
4727
+ var CREDIT_UNITS = /* @__PURE__ */ new Set(["credit", "credits"]);
4728
+ function estimateKiroCreditCost(tracking, metering) {
4729
+ if (!tracking.estimateDollarValue || !metering)
4730
+ return void 0;
4731
+ if (typeof metering.unit !== "string" || !CREDIT_UNITS.has(metering.unit.toLowerCase()))
4732
+ return void 0;
4733
+ const { credits } = metering;
4734
+ if (typeof credits !== "number" || !Number.isFinite(credits) || credits < 0)
4735
+ return void 0;
4736
+ return credits * tracking.usdPerCredit;
4737
+ }
4738
+
4361
4739
  // ../kiro-core/dist/stream.js
4740
+ function describeAttempts(count) {
4741
+ return count === 1 ? "1 attempt" : `${count} attempts`;
4742
+ }
4743
+ var DIAGNOSTIC_QUOTE_LIMIT = 200;
4744
+ function clampForDiagnostic(text) {
4745
+ return text.length <= DIAGNOSTIC_QUOTE_LIMIT ? text : `${text.slice(0, DIAGNOSTIC_QUOTE_LIMIT)}\u2026 (truncated)`;
4746
+ }
4747
+ function encodeBytesForDiagnostic(bytes) {
4748
+ let encoded = "";
4749
+ for (const byte of bytes) {
4750
+ encoded += String.fromCharCode(65 + (byte >> 4), 65 + (byte & 15));
4751
+ }
4752
+ return encoded;
4753
+ }
4754
+ function encodeToolNameForDiagnostic(name) {
4755
+ const identity = typeof name === "string" ? name : `${typeof name}:${JSON.stringify(name)}`;
4756
+ let encoded = "";
4757
+ for (let i = 0; i < identity.length; i++) {
4758
+ const codeUnit = identity.charCodeAt(i);
4759
+ encoded += String.fromCharCode(65 + (codeUnit >> 12), 65 + (codeUnit >> 8 & 15), 65 + (codeUnit >> 4 & 15), 65 + (codeUnit & 15));
4760
+ }
4761
+ return encoded;
4762
+ }
4763
+ function describeDroppedToolNames(names) {
4764
+ const encoded = names.map((name) => `A-P:${encodeToolNameForDiagnostic(name)}`).join(", ");
4765
+ if (encoded.length <= DIAGNOSTIC_QUOTE_LIMIT)
4766
+ return encoded;
4767
+ const digest = createHash3("sha256").update(JSON.stringify(names)).digest();
4768
+ return `A-P-DIGEST:${encodeBytesForDiagnostic(digest)} (tool identities fingerprinted)`;
4769
+ }
4770
+ function describeReturnedContent(kinds) {
4771
+ const unique = [...new Set(kinds)].sort();
4772
+ if (unique.length === 0)
4773
+ return "returning empty content";
4774
+ return `returning only ${unique.join(" and ")} content`;
4775
+ }
4362
4776
  var skipProfileResolutionForTests = false;
4363
4777
  var TEST_PROFILE_ARN = "arn:aws:codewhisperer:us-east-1:000000000000:profile/test";
4364
4778
  async function* streamKiro(request) {
@@ -4369,7 +4783,6 @@ async function* streamKiro(request) {
4369
4783
  }
4370
4784
  let accessToken = initialAccessToken;
4371
4785
  const region = model.region ?? "us-east-1";
4372
- const endpoint = new URL("generateAssistantResponse", getKiroEndpoints(region).runtime).toString();
4373
4786
  let managementAuth = { accessToken, region };
4374
4787
  const cliCreds = getKiroCliCredentials() ?? getKiroCliCredentialsAllowExpired();
4375
4788
  const cliProfileArn = cliCreds?.access === accessToken ? cliCreds.profileArn : void 0;
@@ -4388,9 +4801,11 @@ async function* streamKiro(request) {
4388
4801
  managementAuth = { accessToken, region };
4389
4802
  profileArn = freshCreds.profileArn || (skipProfileResolutionForTests ? TEST_PROFILE_ARN : await resolveKiroProfileArn(managementAuth));
4390
4803
  }
4391
- if (!process.env.VITEST && isCacheStale(region)) {
4392
- updateKiroModelsCache(accessToken, region, profileArn).catch((error2) => {
4393
- console.warn(`[kiro-core] Failed to refresh Kiro model catalog in ${region}: ${formatSafeError(error2)}`);
4804
+ let runtimeRegion = getKiroRegionFromProfileArn(profileArn) ?? region;
4805
+ let endpoint = new URL("generateAssistantResponse", getKiroEndpoints(runtimeRegion).runtime).toString();
4806
+ if (!process.env.VITEST && isCacheStale(runtimeRegion)) {
4807
+ updateKiroModelsCache(accessToken, runtimeRegion, profileArn).catch((error2) => {
4808
+ console.warn(`[kiro-core] Failed to refresh Kiro model catalog in ${runtimeRegion}: ${formatSafeError(error2)}`);
4394
4809
  });
4395
4810
  }
4396
4811
  const kiroModelId = resolveKiroModel(model.id, model.kiroModelId);
@@ -4419,8 +4834,13 @@ async function* streamKiro(request) {
4419
4834
  ${systemPrompt}` : ""}`;
4420
4835
  }
4421
4836
  const assembler = new KiroResponseAssembler(model, thinkingEnabled);
4837
+ const usageTracking = request.usageTracking ?? KIRO_USAGE_TRACKING_DISABLED;
4422
4838
  let retryCount = 0;
4423
4839
  const maxRetries = 3;
4840
+ let emptyAttempts = 0;
4841
+ let echoAttempts = 0;
4842
+ let credentialRefreshTotal = 0;
4843
+ let capacityRetryTotal = 0;
4424
4844
  const conversationId = request.sessionId ?? crypto.randomUUID();
4425
4845
  requestLoop: while (retryCount <= maxRetries) {
4426
4846
  if (signal?.aborted)
@@ -4503,6 +4923,7 @@ ${systemPrompt}` : ""}`;
4503
4923
  });
4504
4924
  if (isCapacityError(errText) && capacityRetryCount < capacityRetryConfig.maxRetries) {
4505
4925
  capacityRetryCount++;
4926
+ capacityRetryTotal++;
4506
4927
  const delayMs = exponentialBackoff(capacityRetryCount - 1, capacityRetryConfig.baseDelayMs, 3e4);
4507
4928
  logCapacityEvent(`INSUFFICIENT_MODEL_CAPACITY \u2014 retrying in ${delayMs}ms (${capacityRetryCount}/${capacityRetryConfig.maxRetries})`);
4508
4929
  await abortableDelay(delayMs, signal);
@@ -4530,6 +4951,7 @@ ${systemPrompt}` : ""}`;
4530
4951
  }
4531
4952
  if (response.status === 403 && !isCapacityError(errText) && retryCount < maxRetries) {
4532
4953
  retryCount++;
4954
+ credentialRefreshTotal++;
4533
4955
  invalidateKiroProfileArn(managementAuth);
4534
4956
  const rejectedAccessToken = accessToken;
4535
4957
  const rejectedProfileArn = profileArn;
@@ -4541,16 +4963,23 @@ ${systemPrompt}` : ""}`;
4541
4963
  managementAuth = { accessToken, region };
4542
4964
  const inheritedDesktopProfileArn = rejectedCliCreds?.authMethod === "desktop" && freshCreds?.authMethod === "desktop" ? rejectedProfileArn : void 0;
4543
4965
  profileArn = freshCreds?.profileArn || inheritedDesktopProfileArn || (skipProfileResolutionForTests ? TEST_PROFILE_ARN : await resolveKiroProfileArn(managementAuth));
4966
+ runtimeRegion = getKiroRegionFromProfileArn(profileArn) ?? region;
4967
+ endpoint = new URL("generateAssistantResponse", getKiroEndpoints(runtimeRegion).runtime).toString();
4544
4968
  await abortableDelay(exponentialBackoff(retryCount - 1, 500, MAX_RETRY_DELAY), signal);
4545
4969
  break;
4546
4970
  }
4971
+ const errorMeta = {
4972
+ reasonCode: extractKiroReasonCode(errText),
4973
+ retryAfterMs: parseRetryAfterMs(response.headers),
4974
+ providerAttempts: { credentialRefresh: credentialRefreshTotal, capacity: capacityRetryTotal }
4975
+ };
4547
4976
  if (isNonRetryableBodyError(errText) || isCapacityError(errText)) {
4548
- throw new Error(`Kiro API error: ${errText || safeStatusText}`);
4977
+ throw new KiroApiError(`Kiro API error: ${errText || safeStatusText}`, response.status, errorMeta.reasonCode, errorMeta.retryAfterMs, errorMeta.providerAttempts);
4549
4978
  }
4550
4979
  if (isTooBigError(response.status, errText)) {
4551
- throw new Error(`Kiro API error: context_length_exceeded (${response.status} ${errText})`);
4980
+ throw new KiroApiError(`Kiro API error: context_length_exceeded (${response.status} ${errText})`, response.status, errorMeta.reasonCode, errorMeta.retryAfterMs, errorMeta.providerAttempts);
4552
4981
  }
4553
- throw new Error(`Kiro API error: ${response.status} ${safeStatusText} ${errText}`);
4982
+ throw new KiroApiError(`Kiro API error: ${response.status} ${safeStatusText} ${errText}`, response.status, errorMeta.reasonCode, errorMeta.retryAfterMs, errorMeta.providerAttempts);
4554
4983
  }
4555
4984
  break;
4556
4985
  }
@@ -4564,7 +4993,8 @@ ${systemPrompt}` : ""}`;
4564
4993
  throw new Error("No response body");
4565
4994
  assembler.beginAttempt();
4566
4995
  const { frames, outcome } = readKiroEventStream(response.body, {
4567
- firstTokenTimeoutMs: model.firstTokenTimeout ?? firstTokenTimeoutForModel(model.id)
4996
+ firstTokenTimeoutMs: model.firstTokenTimeout ?? firstTokenTimeoutForModel(model.id),
4997
+ signal
4568
4998
  });
4569
4999
  for await (const frame of frames) {
4570
5000
  assembler.handle(frame);
@@ -4574,6 +5004,11 @@ ${systemPrompt}` : ""}`;
4574
5004
  if (outcome.firstTokenTimedOut || outcome.idleTimedOut || outcome.error) {
4575
5005
  if (retryCount < maxRetries) {
4576
5006
  retryCount++;
5007
+ if (outcome.errorData && debugEnabled()) {
5008
+ debugLog("stream.error.typed", [outcome.errorData]);
5009
+ }
5010
+ assembler.discard();
5011
+ yield* assembler.takeEvents();
4577
5012
  await abortableDelay(exponentialBackoff(retryCount - 1, 1e3, MAX_RETRY_DELAY), signal);
4578
5013
  continue;
4579
5014
  }
@@ -4583,7 +5018,13 @@ ${systemPrompt}` : ""}`;
4583
5018
  }
4584
5019
  const summary = assembler.endTurn();
4585
5020
  yield* assembler.takeEvents();
4586
- if (summary.isEmpty || summary.isEchoLoop) {
5021
+ const degenerate = summary.isEmpty || summary.isEchoLoop;
5022
+ if (summary.isEchoLoop)
5023
+ echoAttempts++;
5024
+ else if (degenerate)
5025
+ emptyAttempts++;
5026
+ let errorMessage;
5027
+ if (degenerate) {
4587
5028
  const mayRetry = retryCount < maxRetries && (!summary.isEchoLoop || request.canDiscardEmittedBlocks === true);
4588
5029
  if (mayRetry) {
4589
5030
  retryCount++;
@@ -4595,15 +5036,39 @@ ${systemPrompt}` : ""}`;
4595
5036
  }
4596
5037
  if (summary.isEchoLoop) {
4597
5038
  assembler.stripEcho();
4598
- console.warn(`[kiro-core] Echo loop \u2014 stripping "Continue" response`);
5039
+ const alsoEmpty = emptyAttempts > 0 ? ` (plus ${describeAttempts(emptyAttempts)} with no text at all)` : "";
5040
+ console.warn(`[kiro-core] Echo loop persisted across ${describeAttempts(echoAttempts)}${alsoEmpty} \u2014 stripping "Continue" response (${summary.responseText.length} chars)`);
5041
+ errorMessage = `Kiro model echoed its own continuation prompt (${JSON.stringify(clampForDiagnostic(summary.responseText))}) on ${describeAttempts(echoAttempts)}${alsoEmpty} and emitted no tool calls; retry budget exhausted, text stripped, stopReason:"${summary.stopReason}"`;
4599
5042
  } else {
4600
- console.warn(`[kiro-core] Empty response after ${maxRetries} retries \u2014 giving up on this turn`);
5043
+ const alsoEchoed = echoAttempts > 0 ? ` (plus ${describeAttempts(echoAttempts)} that echoed the continuation prompt)` : "";
5044
+ console.warn(`[kiro-core] Empty response on ${describeAttempts(emptyAttempts)}${alsoEchoed}, retry budget exhausted \u2014 returning stopReason:"${summary.stopReason}" to avoid agent loop stall`);
5045
+ errorMessage = `Kiro returned no text and no tool calls on ${describeAttempts(emptyAttempts)}${alsoEchoed}; retry budget exhausted, ${describeReturnedContent(assembler.contentKinds())} with stopReason:"${summary.stopReason}"`;
4601
5046
  }
4602
5047
  }
4603
- const { stopReason, usage } = assembler.complete();
5048
+ if (summary.droppedToolCalls.length > 0) {
5049
+ const names = describeDroppedToolNames(summary.droppedToolCalls);
5050
+ const one = summary.droppedToolCalls.length === 1;
5051
+ const dropDiagnostic = `Kiro sent ${one ? "a tool call" : "tool calls"} with unparseable arguments (${names}); ${one ? "it was" : "they were"} dropped and never reached the agent, stopReason:"${summary.stopReason}"`;
5052
+ errorMessage = errorMessage ? `${errorMessage}. ${dropDiagnostic}` : dropDiagnostic;
5053
+ }
5054
+ const { stopReason, usage, wireUsage, metering } = assembler.complete();
4604
5055
  yield* assembler.takeEvents();
5056
+ if (!errorMessage) {
5057
+ const estimatedRead = applyCacheEstimate(conversationId, usage, wireUsage, usageTracking);
5058
+ if (estimatedRead > 0) {
5059
+ debugLog("usage.estimate", {
5060
+ conversationId,
5061
+ estimatedRead,
5062
+ input: usage.input,
5063
+ cacheRead: usage.cacheRead
5064
+ });
5065
+ }
5066
+ const estimatedCost = estimateKiroCreditCost(usageTracking, metering);
5067
+ if (estimatedCost !== void 0)
5068
+ usage.cost.total = estimatedCost;
5069
+ }
4605
5070
  yield { type: "usage", usage };
4606
- yield { type: "done", stopReason };
5071
+ yield { type: "done", stopReason, ...errorMessage ? { errorMessage } : {} };
4607
5072
  return;
4608
5073
  }
4609
5074
  }
@@ -4698,7 +5163,12 @@ async function loginKiro(callbacks) {
4698
5163
  return existing;
4699
5164
  }
4700
5165
  if (!callbacks.onPrompt) throw new Error(NO_SESSION_MESSAGE);
4701
- const apiKey = (await callbacks.onPrompt({ message: NO_SESSION_MESSAGE, placeholder: "ksk_\u2026", allowEmpty: true })).trim();
5166
+ const apiKey = (await callbacks.onPrompt({
5167
+ message: NO_SESSION_MESSAGE,
5168
+ placeholder: "ksk_\u2026",
5169
+ allowEmpty: true,
5170
+ secret: true
5171
+ })).trim();
4702
5172
  if (!apiKey) throw new Error(NO_SESSION_MESSAGE);
4703
5173
  return await loginKiroWithApiKey(apiKey, callbacks.onProgress);
4704
5174
  }
@@ -4976,10 +5446,20 @@ function streamKiroForOmp(model, context, options) {
4976
5446
  if (event.usage.contextPercent !== void 0) {
4977
5447
  output.usage.contextPercent = event.usage.contextPercent;
4978
5448
  }
5449
+ if (event.usage.credits !== void 0) {
5450
+ output.usage.credits = event.usage.credits;
5451
+ }
5452
+ if (event.usage.creditUnit !== void 0) {
5453
+ output.usage.creditUnit = event.usage.creditUnit;
5454
+ }
5455
+ if (event.usage.cacheEstimated !== void 0) {
5456
+ output.usage.cacheEstimated = event.usage.cacheEstimated;
5457
+ }
4979
5458
  break;
4980
5459
  }
4981
5460
  case "done":
4982
5461
  output.stopReason = event.stopReason;
5462
+ if (event.errorMessage) output.errorMessage = event.errorMessage;
4983
5463
  stream.push({ type: "done", reason: event.stopReason, message: output });
4984
5464
  break;
4985
5465
  }
@@ -5065,7 +5545,7 @@ function toUsageReport(provider, usage, fetchedAt = Date.now()) {
5065
5545
  }
5066
5546
  var kiroUsageProvider = {
5067
5547
  id: "kiro",
5068
- async fetchUsage(params) {
5548
+ async fetchUsage(params, _ctx) {
5069
5549
  const token = params.credential.accessToken ?? params.credential.apiKey;
5070
5550
  if (!token) return null;
5071
5551
  const usage = await fetchKiroUsage({