@pentoshi/clai 4.11.24 → 4.11.26

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 (143) hide show
  1. package/README.md +91 -34
  2. package/dist/agent/stream-recovery.d.ts +1 -0
  3. package/dist/agent/stream-recovery.js +9 -0
  4. package/dist/agent/stream-recovery.js.map +1 -1
  5. package/dist/agent/turn/compaction-coordinator.js +2 -2
  6. package/dist/agent/turn/compaction-coordinator.js.map +1 -1
  7. package/dist/agent/turn/loop/stream-failure.js +4 -1
  8. package/dist/agent/turn/loop/stream-failure.js.map +1 -1
  9. package/dist/app/adapters/agent-event-adapter.js +1 -0
  10. package/dist/app/adapters/agent-event-adapter.js.map +1 -1
  11. package/dist/app/commands/catalog.js +32 -1
  12. package/dist/app/commands/catalog.js.map +1 -1
  13. package/dist/app/controllers/session-compact-helper.js +6 -8
  14. package/dist/app/controllers/session-compact-helper.js.map +1 -1
  15. package/dist/app/controllers/session-controller.d.ts +1 -0
  16. package/dist/app/controllers/session-controller.js +3 -9
  17. package/dist/app/controllers/session-controller.js.map +1 -1
  18. package/dist/app/controllers/session-usage-ledger.d.ts +7 -1
  19. package/dist/app/controllers/session-usage-ledger.js +76 -2
  20. package/dist/app/controllers/session-usage-ledger.js.map +1 -1
  21. package/dist/app/events/app-event.d.ts +2 -1
  22. package/dist/app/events/app-event.js.map +1 -1
  23. package/dist/commands/providers.d.ts +14 -0
  24. package/dist/commands/providers.js +223 -0
  25. package/dist/commands/providers.js.map +1 -1
  26. package/dist/index.js +13 -3
  27. package/dist/index.js.map +1 -1
  28. package/dist/llm/capabilities.js +10 -3
  29. package/dist/llm/capabilities.js.map +1 -1
  30. package/dist/llm/capability/state.d.ts +1 -1
  31. package/dist/llm/capability/tool-dialect.js +2 -0
  32. package/dist/llm/capability/tool-dialect.js.map +1 -1
  33. package/dist/llm/capability/vision-patterns.js +5 -0
  34. package/dist/llm/capability/vision-patterns.js.map +1 -1
  35. package/dist/llm/cline-auth.d.ts +12 -1
  36. package/dist/llm/cline-auth.js +229 -88
  37. package/dist/llm/cline-auth.js.map +1 -1
  38. package/dist/llm/cline.js +146 -48
  39. package/dist/llm/cline.js.map +1 -1
  40. package/dist/llm/codex-auth.d.ts +3 -1
  41. package/dist/llm/codex-auth.js +42 -8
  42. package/dist/llm/codex-auth.js.map +1 -1
  43. package/dist/llm/codex.js +17 -14
  44. package/dist/llm/codex.js.map +1 -1
  45. package/dist/llm/context-windows.js +6 -0
  46. package/dist/llm/context-windows.js.map +1 -1
  47. package/dist/llm/free.js +30 -9
  48. package/dist/llm/free.js.map +1 -1
  49. package/dist/llm/kiro-auth.d.ts +145 -0
  50. package/dist/llm/kiro-auth.js +1179 -0
  51. package/dist/llm/kiro-auth.js.map +1 -0
  52. package/dist/llm/kiro.d.ts +14 -0
  53. package/dist/llm/kiro.js +909 -0
  54. package/dist/llm/kiro.js.map +1 -0
  55. package/dist/llm/mimo.d.ts +2 -0
  56. package/dist/llm/mimo.js +89 -0
  57. package/dist/llm/mimo.js.map +1 -0
  58. package/dist/llm/model-families.js +9 -0
  59. package/dist/llm/model-families.js.map +1 -1
  60. package/dist/llm/model-layers/model-rules.js +54 -0
  61. package/dist/llm/model-layers/model-rules.js.map +1 -1
  62. package/dist/llm/provider-balance.d.ts +31 -0
  63. package/dist/llm/provider-balance.js +118 -0
  64. package/dist/llm/provider-balance.js.map +1 -0
  65. package/dist/llm/provider-identity.d.ts +1 -0
  66. package/dist/llm/provider-identity.js +15 -0
  67. package/dist/llm/provider-identity.js.map +1 -1
  68. package/dist/llm/provider-info-text.js +99 -1
  69. package/dist/llm/provider-info-text.js.map +1 -1
  70. package/dist/llm/provider-profile-layers.d.ts +1 -0
  71. package/dist/llm/provider-profile-layers.js +67 -1
  72. package/dist/llm/provider-profile-layers.js.map +1 -1
  73. package/dist/llm/provider-profiles.js +5 -1
  74. package/dist/llm/provider-profiles.js.map +1 -1
  75. package/dist/llm/provider.d.ts +1 -0
  76. package/dist/llm/provider.js.map +1 -1
  77. package/dist/llm/reasoning-capability.js +2 -0
  78. package/dist/llm/reasoning-capability.js.map +1 -1
  79. package/dist/llm/reasoning-errors.d.ts +1 -0
  80. package/dist/llm/reasoning-errors.js +10 -1
  81. package/dist/llm/reasoning-errors.js.map +1 -1
  82. package/dist/llm/responses-complete.js +7 -1
  83. package/dist/llm/responses-complete.js.map +1 -1
  84. package/dist/llm/responses-config.d.ts +1 -1
  85. package/dist/llm/responses-config.js.map +1 -1
  86. package/dist/llm/responses-http.d.ts +2 -2
  87. package/dist/llm/responses-http.js +2 -2
  88. package/dist/llm/responses-http.js.map +1 -1
  89. package/dist/llm/responses-stream.js +9 -3
  90. package/dist/llm/responses-stream.js.map +1 -1
  91. package/dist/llm/router.js +14 -12
  92. package/dist/llm/router.js.map +1 -1
  93. package/dist/llm/routing/provider-selection.js +6 -0
  94. package/dist/llm/routing/provider-selection.js.map +1 -1
  95. package/dist/llm/sampling.js +6 -0
  96. package/dist/llm/sampling.js.map +1 -1
  97. package/dist/llm/wire/chat-body.js +47 -12
  98. package/dist/llm/wire/chat-body.js.map +1 -1
  99. package/dist/noninteractive/stream-blocks.js +3 -0
  100. package/dist/noninteractive/stream-blocks.js.map +1 -1
  101. package/dist/store/config.js +2 -0
  102. package/dist/store/config.js.map +1 -1
  103. package/dist/store/history/jsonl-backend.js +2 -1
  104. package/dist/store/history/jsonl-backend.js.map +1 -1
  105. package/dist/store/history/jsonl-lock.js +23 -3
  106. package/dist/store/history/jsonl-lock.js.map +1 -1
  107. package/dist/store/history/lifecycle.js +3 -2
  108. package/dist/store/history/lifecycle.js.map +1 -1
  109. package/dist/types.d.ts +8 -1
  110. package/dist/types.js +2 -0
  111. package/dist/types.js.map +1 -1
  112. package/dist/ui-core/bootstrap/composition-root.js +1 -0
  113. package/dist/ui-core/bootstrap/composition-root.js.map +1 -1
  114. package/dist/ui-core/bootstrap/session-resume.d.ts +3 -0
  115. package/dist/ui-core/bootstrap/session-resume.js +52 -0
  116. package/dist/ui-core/bootstrap/session-resume.js.map +1 -1
  117. package/dist/ui-core/commands/key-commands.d.ts +9 -0
  118. package/dist/ui-core/commands/key-commands.js +438 -16
  119. package/dist/ui-core/commands/key-commands.js.map +1 -1
  120. package/dist/ui-core/commands/picker-commands.js +21 -0
  121. package/dist/ui-core/commands/picker-commands.js.map +1 -1
  122. package/dist/ui-core/commands/pickers/search-reasoning.d.ts +2 -0
  123. package/dist/ui-core/commands/pickers/search-reasoning.js +1 -1
  124. package/dist/ui-core/commands/pickers/search-reasoning.js.map +1 -1
  125. package/dist/ui-core/commands/session-commands.d.ts +4 -0
  126. package/dist/ui-core/commands/session-commands.js +94 -2
  127. package/dist/ui-core/commands/session-commands.js.map +1 -1
  128. package/dist/ui-core/rendering/format-usage.js +29 -6
  129. package/dist/ui-core/rendering/format-usage.js.map +1 -1
  130. package/dist/ui-core/state/hydrate/classic-transcript.js +4 -0
  131. package/dist/ui-core/state/hydrate/classic-transcript.js.map +1 -1
  132. package/dist/ui-core/state/transcript/apply-app-event.js +17 -0
  133. package/dist/ui-core/state/transcript/apply-app-event.js.map +1 -1
  134. package/dist/ui-core/state/transcript-hydrate.js +165 -80
  135. package/dist/ui-core/state/transcript-hydrate.js.map +1 -1
  136. package/dist/ui-core/state/transcript-store.js +7 -1
  137. package/dist/ui-core/state/transcript-store.js.map +1 -1
  138. package/dist/ui-core/state/transcript-types.d.ts +2 -0
  139. package/dist/ui-core/state/transcript-types.js +5 -2
  140. package/dist/ui-core/state/transcript-types.js.map +1 -1
  141. package/dist/version.generated.d.ts +2 -2
  142. package/dist/version.generated.js +2 -2
  143. package/package.json +1 -1
@@ -0,0 +1,909 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { defaultModels, } from "./provider.js";
3
+ import { ProviderError } from "./http.js";
4
+ import { assertValidAwsRegion, decodeKiroKey, getKiroUsageLimits, isKiroOAuthToken, listKiroModelsDetailed, maybeRefreshKiroCredential, } from "./kiro-auth.js";
5
+ import { currentSessionAffinity } from "./session-affinity.js";
6
+ import { generationFetch } from "./operation-usage.js";
7
+ import { learnModelVisionCapability } from "./capability/vision-registry.js";
8
+ import { emitStreamReasoningDelta } from "./stream-events.js";
9
+ import { replaceProviderKey } from "../store/keys.js";
10
+ const KIRO_FALLBACK_BASE_MODELS = [
11
+ "auto",
12
+ "claude-sonnet-4.5",
13
+ "claude-sonnet-4",
14
+ "claude-haiku-4.5",
15
+ "deepseek-3.2",
16
+ "minimax-m2.5",
17
+ "minimax-m2.1",
18
+ "glm-5",
19
+ "qwen3-coder-next",
20
+ ];
21
+ function withKiroVariants(baseIds) {
22
+ const variants = [];
23
+ for (const id of baseIds) {
24
+ variants.push(id);
25
+ if (id === "auto")
26
+ continue;
27
+ variants.push(`${id}-thinking`);
28
+ variants.push(`${id}-agentic`);
29
+ variants.push(`${id}-thinking-agentic`);
30
+ }
31
+ return variants;
32
+ }
33
+ export const kiroFallbackModels = withKiroVariants(KIRO_FALLBACK_BASE_MODELS);
34
+ const CRC32_TABLE = new Uint32Array(256);
35
+ for (let i = 0; i < 256; i++) {
36
+ let c = i;
37
+ for (let j = 0; j < 8; j++) {
38
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
39
+ }
40
+ CRC32_TABLE[i] = c >>> 0;
41
+ }
42
+ function crc32(buf, start = 0, end = buf.length) {
43
+ let crc = 0xffffffff;
44
+ for (let i = start; i < end; i++) {
45
+ crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ buf[i]) & 0xff];
46
+ }
47
+ return (crc ^ 0xffffffff) >>> 0;
48
+ }
49
+ function parseHeaders(buf) {
50
+ const headers = {};
51
+ let offset = 0;
52
+ while (offset < buf.length) {
53
+ const nameLen = buf.readUInt8(offset);
54
+ offset += 1;
55
+ const name = buf.toString("utf8", offset, offset + nameLen);
56
+ offset += nameLen;
57
+ const type = buf.readUInt8(offset);
58
+ offset += 1;
59
+ if (type === 0) {
60
+ headers[name] = true;
61
+ }
62
+ else if (type === 1) {
63
+ headers[name] = false;
64
+ }
65
+ else if (type === 2) {
66
+ headers[name] = buf.readInt8(offset);
67
+ offset += 1;
68
+ }
69
+ else if (type === 3) {
70
+ headers[name] = buf.readInt16BE(offset);
71
+ offset += 2;
72
+ }
73
+ else if (type === 4) {
74
+ headers[name] = buf.readInt32BE(offset);
75
+ offset += 4;
76
+ }
77
+ else if (type === 5) {
78
+ headers[name] = buf.readBigInt64BE(offset);
79
+ offset += 8;
80
+ }
81
+ else if (type === 6) {
82
+ const len = buf.readUInt16BE(offset);
83
+ offset += 2;
84
+ headers[name] = buf.subarray(offset, offset + len);
85
+ offset += len;
86
+ }
87
+ else if (type === 7) {
88
+ const len = buf.readUInt16BE(offset);
89
+ offset += 2;
90
+ headers[name] = buf.toString("utf8", offset, offset + len);
91
+ offset += len;
92
+ }
93
+ else if (type === 8) {
94
+ headers[name] = new Date(Number(buf.readBigInt64BE(offset)));
95
+ offset += 8;
96
+ }
97
+ else if (type === 9) {
98
+ headers[name] = buf.subarray(offset, offset + 16).toString("hex");
99
+ offset += 16;
100
+ }
101
+ else {
102
+ break;
103
+ }
104
+ }
105
+ return headers;
106
+ }
107
+ async function* parseEventStream(stream) {
108
+ const reader = stream.getReader();
109
+ let buffer = Buffer.alloc(0);
110
+ try {
111
+ for (;;) {
112
+ const { done, value } = await reader.read();
113
+ if (done)
114
+ break;
115
+ if (value) {
116
+ buffer = Buffer.concat([buffer, Buffer.from(value)]);
117
+ }
118
+ while (buffer.length >= 12) {
119
+ const totalLength = buffer.readUInt32BE(0);
120
+ if (totalLength < 16) {
121
+ buffer = buffer.subarray(1);
122
+ continue;
123
+ }
124
+ const headersLength = buffer.readUInt32BE(4);
125
+ const preludeCrc = buffer.readUInt32BE(8);
126
+ const expectedPreludeCrc = crc32(buffer, 0, 8);
127
+ if (preludeCrc !== expectedPreludeCrc) {
128
+ buffer = buffer.subarray(1);
129
+ continue;
130
+ }
131
+ if (buffer.length < totalLength) {
132
+ break;
133
+ }
134
+ const messageCrc = buffer.readUInt32BE(totalLength - 4);
135
+ const expectedMessageCrc = crc32(buffer, 0, totalLength - 4);
136
+ if (messageCrc !== expectedMessageCrc) {
137
+ buffer = buffer.subarray(totalLength);
138
+ continue;
139
+ }
140
+ const headersBuffer = buffer.subarray(12, 12 + headersLength);
141
+ const payloadBuffer = buffer.subarray(12 + headersLength, totalLength - 4);
142
+ buffer = buffer.subarray(totalLength);
143
+ const headers = parseHeaders(headersBuffer);
144
+ let payload = {};
145
+ if (payloadBuffer.length > 0) {
146
+ try {
147
+ const raw = payloadBuffer.toString("utf8");
148
+ payload = JSON.parse(raw);
149
+ }
150
+ catch {
151
+ payload = { raw: payloadBuffer.toString("utf8") };
152
+ }
153
+ }
154
+ yield { headers, payload };
155
+ }
156
+ }
157
+ }
158
+ finally {
159
+ reader.releaseLock();
160
+ }
161
+ }
162
+ export function isThinkingModel(model) {
163
+ return model.endsWith("-thinking") || model.includes("-thinking-");
164
+ }
165
+ export function isAgenticModel(model) {
166
+ return model.endsWith("-agentic");
167
+ }
168
+ const KIRO_UPSTREAM_MODEL_PATTERN = /^(claude|gpt|o\d|amazon|nova|titan|deepseek|meta|mistral|qwen|minimax|glm|kimi|llama)/i;
169
+ export function resolveKiroModel(model) {
170
+ let upstream = model.trim();
171
+ let agentic = false;
172
+ let thinking = false;
173
+ if (upstream.endsWith("-agentic")) {
174
+ agentic = true;
175
+ upstream = upstream.slice(0, -"-agentic".length);
176
+ }
177
+ if (upstream.endsWith("-thinking")) {
178
+ thinking = true;
179
+ upstream = upstream.slice(0, -"-thinking".length);
180
+ }
181
+ if (!KIRO_UPSTREAM_MODEL_PATTERN.test(upstream)) {
182
+ upstream = defaultModels.kiro;
183
+ }
184
+ return { upstream, agentic, thinking };
185
+ }
186
+ function isAdaptiveThinkingModel(model) {
187
+ return /^claude/i.test(model);
188
+ }
189
+ function kiroEffortString(effort) {
190
+ if (!effort || effort === "none")
191
+ return "";
192
+ if (effort === "minimal")
193
+ return "low";
194
+ if (effort === "low")
195
+ return "low";
196
+ if (effort === "medium")
197
+ return "medium";
198
+ if (effort === "high")
199
+ return "high";
200
+ if (effort === "xhigh")
201
+ return "xhigh";
202
+ return "max";
203
+ }
204
+ const KIRO_THINKING_BUDGET = {
205
+ low: 4000,
206
+ medium: 8000,
207
+ high: 16000,
208
+ xhigh: 32000,
209
+ max: 64000,
210
+ };
211
+ function resolveKiroCredential(auth) {
212
+ const raw = auth.apiKey?.trim();
213
+ if (!raw) {
214
+ throw new Error("Kiro AI authentication required. Run `clai auth kiro` to sign in or `clai set kiro <key>`.");
215
+ }
216
+ const decoded = decodeKiroKey(raw);
217
+ if (decoded)
218
+ return decoded;
219
+ if (raw.startsWith("aorAAAAAG")) {
220
+ return {
221
+ accessToken: "",
222
+ refreshToken: raw,
223
+ authMethod: "imported",
224
+ region: "us-east-1",
225
+ };
226
+ }
227
+ if (raw.startsWith("ey") && raw.includes(".")) {
228
+ return {
229
+ accessToken: raw,
230
+ authMethod: "external_idp",
231
+ region: "us-east-1",
232
+ };
233
+ }
234
+ return {
235
+ accessToken: raw,
236
+ apiKey: raw,
237
+ authMethod: "api_key",
238
+ region: "us-east-1",
239
+ };
240
+ }
241
+ async function withKiroCredential(auth, run, onStatus) {
242
+ const credential = resolveKiroCredential(auth);
243
+ try {
244
+ return await run(credential);
245
+ }
246
+ catch (error) {
247
+ const status = error instanceof ProviderError ? error.status : undefined;
248
+ if (status !== 401 && status !== 403)
249
+ throw error;
250
+ onStatus?.("ℹ Kiro authentication expired — attempting token refresh");
251
+ const oldKey = auth.apiKey ?? "";
252
+ const refreshedKey = await maybeRefreshKiroCredential(oldKey, auth.refreshToken);
253
+ if (!refreshedKey || refreshedKey === oldKey) {
254
+ throw error;
255
+ }
256
+ await replaceProviderKey("kiro", oldKey, refreshedKey).catch(() => { });
257
+ auth.apiKey = refreshedKey;
258
+ const newCredential = resolveKiroCredential({ ...auth, apiKey: refreshedKey });
259
+ onStatus?.("ℹ Kiro token refreshed — retrying request");
260
+ return run(newCredential);
261
+ }
262
+ }
263
+ function getCandidateEndpoints(credential) {
264
+ const region = assertValidAwsRegion(credential.region);
265
+ const qUrl = `https://q.${region}.amazonaws.com/generateAssistantResponse`;
266
+ const cwUrl = `https://codewhisperer.${region}.amazonaws.com/generateAssistantResponse`;
267
+ const rtUrl = `https://runtime.${region}.kiro.dev/generateAssistantResponse`;
268
+ if (credential.authMethod === "api_key") {
269
+ return [qUrl, cwUrl, rtUrl];
270
+ }
271
+ return [cwUrl, rtUrl, qUrl];
272
+ }
273
+ function uuidFromHex(hex) {
274
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
275
+ }
276
+ function kiroConversationId(seedContent) {
277
+ const affinity = currentSessionAffinity();
278
+ if (affinity) {
279
+ return uuidFromHex(createHash("md5").update(`kiro-${affinity}`).digest("hex"));
280
+ }
281
+ const seed = seedContent.trim();
282
+ if (seed) {
283
+ return uuidFromHex(createHash("md5").update(`kiro-${seed.slice(0, 4000)}`).digest("hex"));
284
+ }
285
+ return randomUUID();
286
+ }
287
+ function sanitizeToolName(name) {
288
+ return name.slice(0, 64).replace(/[^a-zA-Z0-9_-]/g, "_") || "tool";
289
+ }
290
+ function formatKiroTools(tools) {
291
+ if (!tools || tools.length === 0)
292
+ return [];
293
+ return tools.map((t) => ({
294
+ toolSpecification: {
295
+ name: sanitizeToolName(t.wireName || t.name),
296
+ description: (t.description || "").slice(0, 10237),
297
+ inputSchema: {
298
+ json: t.parameters,
299
+ },
300
+ },
301
+ }));
302
+ }
303
+ function imageFormatFromMediaType(mediaType) {
304
+ const lower = mediaType.toLowerCase();
305
+ if (lower.includes("jpeg") || lower.includes("jpg"))
306
+ return "jpeg";
307
+ if (lower.includes("png"))
308
+ return "png";
309
+ if (lower.includes("gif"))
310
+ return "gif";
311
+ if (lower.includes("webp"))
312
+ return "webp";
313
+ return "png";
314
+ }
315
+ function buildKiroRequestBody(request, credential, upstreamModel, agentic, thinking) {
316
+ const agenticInstruction = agentic
317
+ ? "When modifying or creating files, keep writes concise:\n- Maximum 350 lines per file write/tool call (recommended 300 lines or fewer).\n- Prefer targeted, incremental edits instead of rewriting entire files.\n- For large files, write or append in chunks across multiple tool calls."
318
+ : "";
319
+ const systemParts = [];
320
+ if (agenticInstruction)
321
+ systemParts.push(agenticInstruction);
322
+ const nonSystemMessages = [];
323
+ for (const msg of request.messages) {
324
+ if (msg.role === "system") {
325
+ if (msg.content.trim())
326
+ systemParts.push(msg.content.trim());
327
+ }
328
+ else {
329
+ nonSystemMessages.push(msg);
330
+ }
331
+ }
332
+ const systemPrompt = systemParts.join("\n\n").trim();
333
+ const turns = [];
334
+ for (const msg of nonSystemMessages) {
335
+ if (msg.role === "user") {
336
+ const images = (msg.images ?? []).map((img) => ({
337
+ format: imageFormatFromMediaType(img.mediaType),
338
+ source: { bytes: img.dataBase64 },
339
+ }));
340
+ const last = turns[turns.length - 1];
341
+ if (last && last.role === "user") {
342
+ if (msg.content) {
343
+ last.content = last.content
344
+ ? `${last.content}\n\n${msg.content}`
345
+ : msg.content;
346
+ }
347
+ if (images.length > 0) {
348
+ last.images = [...(last.images ?? []), ...images];
349
+ }
350
+ }
351
+ else {
352
+ turns.push({
353
+ role: "user",
354
+ content: msg.content || "",
355
+ images: images.length > 0 ? images : undefined,
356
+ });
357
+ }
358
+ }
359
+ else if (msg.role === "assistant") {
360
+ const toolUses = (msg.toolCalls ?? [])
361
+ .filter((tc) => tc.id)
362
+ .map((tc) => ({
363
+ toolUseId: tc.id,
364
+ name: sanitizeToolName(tc.name),
365
+ input: tc.args ?? {},
366
+ }));
367
+ const last = turns[turns.length - 1];
368
+ if (last && last.role === "assistant") {
369
+ if (msg.content) {
370
+ last.content = last.content
371
+ ? `${last.content}\n\n${msg.content}`
372
+ : msg.content;
373
+ }
374
+ if (toolUses.length > 0) {
375
+ last.toolUses = [...(last.toolUses ?? []), ...toolUses];
376
+ }
377
+ }
378
+ else {
379
+ turns.push({
380
+ role: "assistant",
381
+ content: msg.content || "",
382
+ toolUses: toolUses.length > 0 ? toolUses : undefined,
383
+ });
384
+ }
385
+ }
386
+ else if (msg.role === "tool") {
387
+ const toolResult = {
388
+ toolUseId: msg.toolCallId || "tool_result",
389
+ content: [{ text: msg.content || "" }],
390
+ status: msg.ok === false ? "error" : "success",
391
+ };
392
+ const last = turns[turns.length - 1];
393
+ if (last && last.role === "user") {
394
+ last.toolResults = [...(last.toolResults ?? []), toolResult];
395
+ }
396
+ else {
397
+ turns.push({
398
+ role: "user",
399
+ content: "",
400
+ toolResults: [toolResult],
401
+ });
402
+ }
403
+ }
404
+ }
405
+ if (turns.length === 0) {
406
+ turns.push({ role: "user", content: "continue" });
407
+ }
408
+ if (systemPrompt && turns[0] && turns[0].role === "user") {
409
+ turns[0].content = turns[0].content
410
+ ? `${systemPrompt}\n\n${turns[0].content}`
411
+ : systemPrompt;
412
+ }
413
+ if (turns[turns.length - 1]?.role !== "user") {
414
+ turns.push({ role: "user", content: "continue" });
415
+ }
416
+ for (const turn of turns) {
417
+ if (turn.role === "user" && !turn.content.trim()) {
418
+ turn.content =
419
+ turn.toolResults && turn.toolResults.length > 0
420
+ ? "Tool results provided."
421
+ : "continue";
422
+ }
423
+ }
424
+ const kiroTools = formatKiroTools(request.tools);
425
+ const history = [];
426
+ for (let i = 0; i < turns.length - 1; i++) {
427
+ const turn = turns[i];
428
+ if (turn.role === "user") {
429
+ const userContext = {};
430
+ if (turn.toolResults && turn.toolResults.length > 0) {
431
+ userContext.toolResults = turn.toolResults;
432
+ }
433
+ history.push({
434
+ userInputMessage: {
435
+ content: turn.content,
436
+ modelId: upstreamModel,
437
+ origin: "AI_EDITOR",
438
+ userInputMessageContext: userContext,
439
+ ...(turn.images && turn.images.length > 0
440
+ ? { images: turn.images }
441
+ : {}),
442
+ },
443
+ });
444
+ }
445
+ else {
446
+ history.push({
447
+ assistantResponseMessage: {
448
+ content: turn.content,
449
+ ...(turn.toolUses && turn.toolUses.length > 0
450
+ ? { toolUses: turn.toolUses }
451
+ : {}),
452
+ },
453
+ });
454
+ }
455
+ }
456
+ const lastTurn = turns[turns.length - 1];
457
+ const currentContext = {};
458
+ if (kiroTools.length > 0) {
459
+ currentContext.tools = kiroTools;
460
+ }
461
+ if (lastTurn.toolResults && lastTurn.toolResults.length > 0) {
462
+ currentContext.toolResults = lastTurn.toolResults;
463
+ }
464
+ const currentMessage = {
465
+ userInputMessage: {
466
+ content: lastTurn.content,
467
+ modelId: upstreamModel,
468
+ origin: "AI_EDITOR",
469
+ userInputMessageContext: currentContext,
470
+ ...(lastTurn.images && lastTurn.images.length > 0
471
+ ? { images: lastTurn.images }
472
+ : {}),
473
+ },
474
+ };
475
+ const firstUserContent = turns.find((t) => t.role === "user" && t.content.trim())?.content ?? "";
476
+ const conversationId = kiroConversationId(firstUserContent);
477
+ const payload = {
478
+ conversationState: {
479
+ conversationId,
480
+ chatTriggerType: "MANUAL",
481
+ history,
482
+ currentMessage,
483
+ },
484
+ };
485
+ if (credential.profileArn) {
486
+ payload.profileArn = credential.profileArn;
487
+ }
488
+ const wantsThinking = thinking || request.thinking?.enabled === true;
489
+ const effort = kiroEffortString(request.thinking?.effort) || "high";
490
+ if (wantsThinking && isAdaptiveThinkingModel(upstreamModel)) {
491
+ const budget = KIRO_THINKING_BUDGET[effort] ?? 16000;
492
+ const directive = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>`;
493
+ const uim = payload.conversationState
494
+ .currentMessage;
495
+ const msg = uim.userInputMessage;
496
+ msg.content = `${directive}\n\n${String(msg.content ?? "")}`;
497
+ }
498
+ return payload;
499
+ }
500
+ let cachedKiroModels = null;
501
+ let cachedKiroModelInfo = [];
502
+ let lastKiroModelFetch = 0;
503
+ const MODEL_CACHE_TTL_MS = 30 * 60 * 1000;
504
+ export function kiroModelCatalog() {
505
+ return cachedKiroModelInfo;
506
+ }
507
+ export function resetKiroModelCacheForTesting() {
508
+ cachedKiroModels = null;
509
+ cachedKiroModelInfo = [];
510
+ lastKiroModelFetch = 0;
511
+ }
512
+ export async function fetchKiroUsageLimits(auth, onStatus) {
513
+ return withKiroCredential(auth, getKiroUsageLimits, onStatus);
514
+ }
515
+ const KIRO_MODEL_RANK = (id) => {
516
+ const base = resolveKiroModel(id).upstream;
517
+ if (base === "auto")
518
+ return 0;
519
+ if (/^claude-/.test(base))
520
+ return 1;
521
+ return 2;
522
+ };
523
+ export const kiroProvider = {
524
+ id: "kiro",
525
+ displayName: "Kiro AI",
526
+ defaultModel: defaultModels.kiro,
527
+ envVar: "KIRO_API_KEY",
528
+ sortModels(models) {
529
+ return [...models].sort((a, b) => KIRO_MODEL_RANK(a) - KIRO_MODEL_RANK(b) || a.localeCompare(b));
530
+ },
531
+ validateKey(key) {
532
+ const trimmed = key.trim();
533
+ if (!trimmed)
534
+ return false;
535
+ if (isKiroOAuthToken(trimmed))
536
+ return decodeKiroKey(trimmed) !== undefined;
537
+ if (trimmed.startsWith("aorAAAAAG"))
538
+ return true;
539
+ if (trimmed.startsWith("ey") && trimmed.includes("."))
540
+ return true;
541
+ return trimmed.length >= 8;
542
+ },
543
+ async listModels(auth) {
544
+ const now = Date.now();
545
+ if (cachedKiroModels && now - lastKiroModelFetch < MODEL_CACHE_TTL_MS) {
546
+ return cachedKiroModels;
547
+ }
548
+ try {
549
+ const credential = resolveKiroCredential(auth);
550
+ const infos = await listKiroModelsDetailed(credential);
551
+ if (infos.length > 0) {
552
+ cachedKiroModelInfo = infos;
553
+ for (const info of infos) {
554
+ if (info.supportsImages !== undefined) {
555
+ learnModelVisionCapability("kiro", info.modelId, info.supportsImages);
556
+ }
557
+ }
558
+ const variants = withKiroVariants(infos.map((info) => info.modelId));
559
+ cachedKiroModels = variants;
560
+ lastKiroModelFetch = now;
561
+ return variants;
562
+ }
563
+ }
564
+ catch { }
565
+ return cachedKiroModels ?? [...kiroFallbackModels];
566
+ },
567
+ async ping(auth) {
568
+ const credential = resolveKiroCredential(auth);
569
+ const region = assertValidAwsRegion(credential.region);
570
+ const params = new URLSearchParams({ origin: "AI_EDITOR" });
571
+ const endpoint = `https://q.${region}.amazonaws.com/ListAvailableModels?${params.toString()}`;
572
+ const headers = {
573
+ Accept: "application/json",
574
+ "User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0",
575
+ "X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
576
+ };
577
+ if (credential.authMethod === "api_key" && credential.apiKey) {
578
+ headers["Authorization"] = `Bearer ${credential.apiKey}`;
579
+ headers["TokenType"] = "API_KEY";
580
+ }
581
+ else if (credential.accessToken) {
582
+ headers["Authorization"] = `Bearer ${credential.accessToken}`;
583
+ if (credential.authMethod === "external_idp") {
584
+ headers["TokenType"] = "EXTERNAL_IDP";
585
+ }
586
+ }
587
+ const response = await fetch(endpoint, {
588
+ method: "GET",
589
+ headers,
590
+ signal: AbortSignal.timeout(15_000),
591
+ });
592
+ if (!response.ok) {
593
+ throw new ProviderError(`Kiro AI ping failed (HTTP ${response.status}). Run \`clai auth kiro\` to sign in.`, response.status);
594
+ }
595
+ },
596
+ async complete(request, auth, onStatus) {
597
+ return this.stream(request, auth, () => { }, onStatus);
598
+ },
599
+ async stream(request, auth, onToken, onStatus) {
600
+ const requestedModel = request.model ?? defaultModels.kiro;
601
+ const { upstream, agentic, thinking } = resolveKiroModel(requestedModel);
602
+ return withKiroCredential(auth, async (credential) => {
603
+ const body = buildKiroRequestBody(request, credential, upstream, agentic, thinking);
604
+ const endpoints = getCandidateEndpoints(credential);
605
+ let lastError;
606
+ for (const endpoint of endpoints) {
607
+ try {
608
+ const headers = {
609
+ "Content-Type": "application/json",
610
+ Accept: "application/vnd.amazon.eventstream",
611
+ "Amz-Sdk-Request": "attempt=1; max=3",
612
+ "Amz-Sdk-Invocation-Id": randomUUID(),
613
+ "User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
614
+ "X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
615
+ "x-amzn-kiro-agent-mode": "vibe",
616
+ "x-amzn-codewhisperer-optout": "true",
617
+ "x-amzn-codewhisperer-machine-id": "kiro-desktop",
618
+ };
619
+ if (endpoint.includes("codewhisperer")) {
620
+ headers["X-Amz-Target"] =
621
+ "AmazonCodeWhispererStreamingService.GenerateAssistantResponse";
622
+ }
623
+ if (credential.authMethod === "api_key" && credential.apiKey) {
624
+ headers["Authorization"] = `Bearer ${credential.apiKey}`;
625
+ headers["TokenType"] = "API_KEY";
626
+ }
627
+ else if (credential.accessToken) {
628
+ headers["Authorization"] = `Bearer ${credential.accessToken}`;
629
+ headers["x-amz-sso-bearer"] = credential.accessToken;
630
+ if (credential.authMethod === "external_idp") {
631
+ headers["TokenType"] = "EXTERNAL_IDP";
632
+ }
633
+ if (credential.profileArn) {
634
+ headers["x-amzn-codewhisperer-profile-arn"] = credential.profileArn;
635
+ }
636
+ }
637
+ const response = await generationFetch(endpoint, {
638
+ method: "POST",
639
+ headers,
640
+ body: JSON.stringify(body),
641
+ ...(request.signal ? { signal: request.signal } : {}),
642
+ });
643
+ if (!response.ok) {
644
+ const errorText = await response.text().catch(() => "");
645
+ if (response.status === 401 || response.status === 403) {
646
+ throw new ProviderError(`Kiro authentication failed (${response.status}): ${errorText}`, response.status);
647
+ }
648
+ if (response.status === 400) {
649
+ throw new ProviderError(`Kiro request invalid (${response.status}): ${errorText}`, response.status, errorText);
650
+ }
651
+ lastError = new ProviderError(`Kiro endpoint error (${response.status}): ${errorText}`, response.status);
652
+ continue;
653
+ }
654
+ if (!response.body) {
655
+ throw new ProviderError("Empty response body from Kiro endpoint", 500);
656
+ }
657
+ let fullText = "";
658
+ let reasoningText = "";
659
+ let insideThinkingTag = false;
660
+ let finishReason = "stop";
661
+ const accumulatedTools = [];
662
+ let currentToolIndex = -1;
663
+ let promptTokens = 0;
664
+ let completionTokens = 0;
665
+ let cachedTokens = 0;
666
+ let cacheCreationTokens = 0;
667
+ const usageCharges = [];
668
+ let contextUsagePercentage;
669
+ for await (const frame of parseEventStream(response.body)) {
670
+ const eventType = (typeof frame.headers[":event-type"] === "string"
671
+ ? frame.headers[":event-type"]
672
+ : undefined) ||
673
+ Object.keys(frame.payload).find((k) => k.endsWith("Event")) ||
674
+ "";
675
+ const eventPayload = frame.payload[eventType] ||
676
+ frame.payload;
677
+ if (typeof eventPayload.usage === "number" &&
678
+ Number.isFinite(eventPayload.usage) &&
679
+ eventPayload.usage >= 0 &&
680
+ typeof eventPayload.unit === "string" &&
681
+ eventPayload.unit.trim()) {
682
+ usageCharges.push({
683
+ amount: eventPayload.usage,
684
+ unit: typeof eventPayload.unitPlural === "string" &&
685
+ eventPayload.unitPlural.trim()
686
+ ? eventPayload.unitPlural.trim()
687
+ : eventPayload.unit.trim(),
688
+ ...(typeof eventPayload.currency === "string"
689
+ ? { currency: eventPayload.currency }
690
+ : {}),
691
+ });
692
+ }
693
+ if (eventType === "assistantResponseEvent" ||
694
+ eventType.includes("Response")) {
695
+ if (typeof eventPayload.contextUsagePercentage === "number") {
696
+ contextUsagePercentage = eventPayload.contextUsagePercentage;
697
+ }
698
+ const chunk = typeof eventPayload.content === "string"
699
+ ? eventPayload.content
700
+ : "";
701
+ if (chunk) {
702
+ let visibleChunk = "";
703
+ let reasoningChunk = "";
704
+ let i = 0;
705
+ while (i < chunk.length) {
706
+ if (!insideThinkingTag) {
707
+ const tagStart = chunk.indexOf("<thinking>", i);
708
+ if (tagStart !== -1) {
709
+ visibleChunk += chunk.slice(i, tagStart);
710
+ insideThinkingTag = true;
711
+ i = tagStart + 10;
712
+ }
713
+ else {
714
+ visibleChunk += chunk.slice(i);
715
+ break;
716
+ }
717
+ }
718
+ else {
719
+ const tagEnd = chunk.indexOf("</thinking>", i);
720
+ if (tagEnd !== -1) {
721
+ reasoningChunk += chunk.slice(i, tagEnd);
722
+ insideThinkingTag = false;
723
+ i = tagEnd + 11;
724
+ }
725
+ else {
726
+ reasoningChunk += chunk.slice(i);
727
+ break;
728
+ }
729
+ }
730
+ }
731
+ if (reasoningChunk) {
732
+ reasoningText += reasoningChunk;
733
+ emitStreamReasoningDelta(request.onStreamEvent, reasoningChunk);
734
+ }
735
+ if (visibleChunk) {
736
+ fullText += visibleChunk;
737
+ onToken(visibleChunk);
738
+ }
739
+ }
740
+ }
741
+ else if (eventType === "reasoningContentEvent" ||
742
+ eventType.includes("Reasoning")) {
743
+ const chunk = typeof eventPayload.content === "string"
744
+ ? eventPayload.content
745
+ : "";
746
+ if (chunk) {
747
+ reasoningText += chunk;
748
+ emitStreamReasoningDelta(request.onStreamEvent, chunk);
749
+ }
750
+ }
751
+ else if (eventType === "codeEvent") {
752
+ const chunk = typeof eventPayload.content === "string"
753
+ ? eventPayload.content
754
+ : "";
755
+ if (chunk) {
756
+ fullText += chunk;
757
+ onToken(chunk);
758
+ }
759
+ }
760
+ else if (eventType === "toolUseEvent") {
761
+ const toolId = typeof eventPayload.toolUseId === "string"
762
+ ? eventPayload.toolUseId
763
+ : `tool_${accumulatedTools.length + 1}`;
764
+ const name = typeof eventPayload.name === "string" ? eventPayload.name : "";
765
+ const input = eventPayload.input;
766
+ let existing = accumulatedTools.find((t) => t.id === toolId);
767
+ if (!existing) {
768
+ existing = { id: toolId, name, rawArgs: "" };
769
+ accumulatedTools.push(existing);
770
+ currentToolIndex = accumulatedTools.length - 1;
771
+ }
772
+ let chunkBytes = 0;
773
+ if (typeof input === "string") {
774
+ existing.rawArgs += input;
775
+ chunkBytes = Buffer.byteLength(input, "utf8");
776
+ }
777
+ else if (input && typeof input === "object") {
778
+ existing.rawArgs = JSON.stringify(input);
779
+ chunkBytes = Buffer.byteLength(existing.rawArgs, "utf8");
780
+ }
781
+ if (name && !existing.name) {
782
+ existing.name = name;
783
+ }
784
+ const delta = {
785
+ index: currentToolIndex,
786
+ id: existing.id,
787
+ name: existing.name,
788
+ argumentsBytes: chunkBytes,
789
+ };
790
+ request.onToolCallDelta?.(delta);
791
+ finishReason = "tool_calls";
792
+ }
793
+ else if (eventType === "messageStopEvent") {
794
+ const stop = typeof eventPayload.stopReason === "string"
795
+ ? eventPayload.stopReason
796
+ : "";
797
+ if (stop) {
798
+ finishReason =
799
+ stop === "tool_use" || stop === "tool_calls"
800
+ ? "tool_calls"
801
+ : stop === "max_tokens" || stop === "length"
802
+ ? "length"
803
+ : "stop";
804
+ }
805
+ }
806
+ else if (eventType === "contextUsageEvent") {
807
+ if (typeof eventPayload.contextUsagePercentage === "number") {
808
+ contextUsagePercentage = eventPayload.contextUsagePercentage;
809
+ }
810
+ }
811
+ else if (eventType === "metricsEvent" ||
812
+ eventType === "meteringEvent") {
813
+ if (typeof eventPayload.inputTokens === "number") {
814
+ promptTokens = eventPayload.inputTokens;
815
+ }
816
+ if (typeof eventPayload.outputTokens === "number") {
817
+ completionTokens = eventPayload.outputTokens;
818
+ }
819
+ if (typeof eventPayload.cachedTokens === "number") {
820
+ cachedTokens = eventPayload.cachedTokens;
821
+ }
822
+ if (typeof eventPayload.cacheReadInputTokens === "number") {
823
+ cachedTokens = Math.max(cachedTokens, eventPayload.cacheReadInputTokens);
824
+ }
825
+ if (typeof eventPayload.cacheWriteInputTokens === "number") {
826
+ cacheCreationTokens = eventPayload.cacheWriteInputTokens;
827
+ }
828
+ }
829
+ }
830
+ const toolCalls = accumulatedTools.map((t) => {
831
+ let parsedArgs = {};
832
+ try {
833
+ parsedArgs = JSON.parse(t.rawArgs || "{}");
834
+ }
835
+ catch {
836
+ parsedArgs = { raw: t.rawArgs };
837
+ }
838
+ return {
839
+ id: t.id,
840
+ name: t.name,
841
+ args: parsedArgs,
842
+ rawArguments: t.rawArgs,
843
+ };
844
+ });
845
+ if (toolCalls.length > 0) {
846
+ finishReason = "tool_calls";
847
+ }
848
+ const catalogWindow = kiroModelCatalog().find((info) => info.modelId === upstream)
849
+ ?.maxInputTokens ?? 200_000;
850
+ const tokenUsage = promptTokens > 0 || completionTokens > 0
851
+ ? {
852
+ promptTokens,
853
+ completionTokens,
854
+ totalTokens: promptTokens + completionTokens,
855
+ exact: true,
856
+ cachedPromptTokens: cachedTokens > 0 ? cachedTokens : undefined,
857
+ cacheCreationTokens: cacheCreationTokens > 0 ? cacheCreationTokens : undefined,
858
+ uncachedPromptTokens: cachedTokens > 0
859
+ ? Math.max(0, promptTokens - cachedTokens)
860
+ : promptTokens,
861
+ }
862
+ : contextUsagePercentage !== undefined
863
+ ? {
864
+ promptTokens: Math.round((contextUsagePercentage / 100) * catalogWindow),
865
+ completionTokens: 0,
866
+ totalTokens: Math.round((contextUsagePercentage / 100) * catalogWindow),
867
+ exact: false,
868
+ }
869
+ : undefined;
870
+ const usage = tokenUsage
871
+ ? {
872
+ ...tokenUsage,
873
+ ...(usageCharges.length > 0 ? { charges: usageCharges } : {}),
874
+ }
875
+ : usageCharges.length > 0
876
+ ? {
877
+ promptTokens: 0,
878
+ promptTokensKnown: false,
879
+ completionTokens: 0,
880
+ totalTokens: 0,
881
+ exact: false,
882
+ charges: usageCharges,
883
+ }
884
+ : undefined;
885
+ return {
886
+ text: fullText,
887
+ provider: "kiro",
888
+ model: requestedModel,
889
+ api: "kiro-eventstream",
890
+ finishReason,
891
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
892
+ usage,
893
+ reasoningBlock: reasoningText.trim()
894
+ ? { text: reasoningText.trim() }
895
+ : undefined,
896
+ };
897
+ }
898
+ catch (err) {
899
+ if (err instanceof ProviderError && (err.status === 401 || err.status === 403 || err.status === 400)) {
900
+ throw err;
901
+ }
902
+ lastError = err instanceof Error ? err : new Error(String(err));
903
+ }
904
+ }
905
+ throw lastError ?? new Error("All Kiro endpoints failed");
906
+ }, onStatus);
907
+ },
908
+ };
909
+ //# sourceMappingURL=kiro.js.map