@pentoshi/clai 4.11.26 → 4.11.27
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.
- package/dist/agent/compaction/summary-execution.js +11 -1
- package/dist/agent/compaction/summary-execution.js.map +1 -1
- package/dist/agent/context-manager.d.ts +0 -1
- package/dist/agent/context-manager.js +0 -1
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/events.d.ts +1 -5
- package/dist/agent/plan/actions/plan-clear.js +1 -1
- package/dist/agent/plan/actions/plan-clear.js.map +1 -1
- package/dist/agent/plan/actions/plan-create.js +38 -17
- package/dist/agent/plan/actions/plan-create.js.map +1 -1
- package/dist/agent/plan/actions/task-add.js +15 -4
- package/dist/agent/plan/actions/task-add.js.map +1 -1
- package/dist/agent/plan/actions/task-move.js +16 -5
- package/dist/agent/plan/actions/task-move.js.map +1 -1
- package/dist/agent/plan/handle-plan-tool.js +20 -6
- package/dist/agent/plan/handle-plan-tool.js.map +1 -1
- package/dist/agent/reliability-policy.d.ts +0 -10
- package/dist/agent/reliability-policy.js +0 -23
- package/dist/agent/reliability-policy.js.map +1 -1
- package/dist/agent/request-accounting.js +10 -10
- package/dist/agent/request-accounting.js.map +1 -1
- package/dist/agent/request-budget.d.ts +11 -18
- package/dist/agent/request-budget.js +14 -53
- package/dist/agent/request-budget.js.map +1 -1
- package/dist/agent/runner.js +16 -12
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/stream-recovery.d.ts +1 -2
- package/dist/agent/stream-recovery.js +5 -10
- package/dist/agent/stream-recovery.js.map +1 -1
- package/dist/agent/subagents/worker.js +3 -2
- package/dist/agent/subagents/worker.js.map +1 -1
- package/dist/agent/turn/automatic-compaction-execution.js +2 -2
- package/dist/agent/turn/automatic-compaction-execution.js.map +1 -1
- package/dist/agent/turn/compaction-admission.d.ts +2 -2
- package/dist/agent/turn/compaction-admission.js +14 -17
- package/dist/agent/turn/compaction-admission.js.map +1 -1
- package/dist/agent/turn/compaction-coordinator.d.ts +2 -1
- package/dist/agent/turn/compaction-coordinator.js +12 -7
- package/dist/agent/turn/compaction-coordinator.js.map +1 -1
- package/dist/agent/turn/compaction-durable-envelope.js +1 -1
- package/dist/agent/turn/compaction-durable-envelope.js.map +1 -1
- package/dist/agent/turn/compaction-replay-selection.js +2 -3
- package/dist/agent/turn/compaction-replay-selection.js.map +1 -1
- package/dist/agent/turn/compaction-summarizer.js +1 -1
- package/dist/agent/turn/compaction-summarizer.js.map +1 -1
- package/dist/agent/turn/loop/answer-path.js +2 -2
- package/dist/agent/turn/loop/answer-path.js.map +1 -1
- package/dist/agent/turn/loop/completion-interpretation.d.ts +0 -1
- package/dist/agent/turn/loop/completion-interpretation.js +2 -7
- package/dist/agent/turn/loop/completion-interpretation.js.map +1 -1
- package/dist/agent/turn/loop/deps.d.ts +1 -0
- package/dist/agent/turn/loop/empty-response.d.ts +1 -1
- package/dist/agent/turn/loop/empty-response.js +2 -4
- package/dist/agent/turn/loop/empty-response.js.map +1 -1
- package/dist/agent/turn/loop/output-budget.d.ts +0 -1
- package/dist/agent/turn/loop/output-budget.js +4 -9
- package/dist/agent/turn/loop/output-budget.js.map +1 -1
- package/dist/agent/turn/loop/request-assembly.d.ts +1 -3
- package/dist/agent/turn/loop/request-assembly.js +15 -15
- package/dist/agent/turn/loop/request-assembly.js.map +1 -1
- package/dist/agent/turn/loop/round-request.js +1 -6
- package/dist/agent/turn/loop/round-request.js.map +1 -1
- package/dist/agent/turn/loop/run-rounds.js +9 -15
- package/dist/agent/turn/loop/run-rounds.js.map +1 -1
- package/dist/agent/turn/loop/state.d.ts +2 -3
- package/dist/agent/turn/loop/state.js +1 -2
- package/dist/agent/turn/loop/state.js.map +1 -1
- package/dist/agent/turn/loop/stream-failure.d.ts +0 -1
- package/dist/agent/turn/loop/stream-failure.js +5 -5
- package/dist/agent/turn/loop/stream-failure.js.map +1 -1
- package/dist/agent/turn/loop/stream-request.d.ts +0 -1
- package/dist/agent/turn/loop/stream-request.js +1 -3
- package/dist/agent/turn/loop/stream-request.js.map +1 -1
- package/dist/agent/turn/plan-persistence.d.ts +4 -5
- package/dist/agent/turn/plan-persistence.js +13 -4
- package/dist/agent/turn/plan-persistence.js.map +1 -1
- package/dist/agent/turn/provider-measurement.d.ts +6 -0
- package/dist/agent/turn/provider-measurement.js +19 -0
- package/dist/agent/turn/provider-measurement.js.map +1 -0
- package/dist/agent/turn/responder-job-linkage.js +2 -2
- package/dist/agent/turn/responder-job-linkage.js.map +1 -1
- package/dist/agent/turn/setup/compaction-services.d.ts +2 -1
- package/dist/agent/turn/setup/compaction-services.js +2 -1
- package/dist/agent/turn/setup/compaction-services.js.map +1 -1
- package/dist/agent/turn/setup/task-gate-setup.d.ts +3 -3
- package/dist/agent/turn/setup/task-gate-setup.js.map +1 -1
- package/dist/agent/turn/task-autostart.d.ts +2 -2
- package/dist/agent/turn/task-autostart.js +7 -9
- package/dist/agent/turn/task-autostart.js.map +1 -1
- package/dist/agent/turn/task-credit.d.ts +2 -2
- package/dist/agent/turn/task-credit.js +8 -5
- package/dist/agent/turn/task-credit.js.map +1 -1
- package/dist/agent/turn/tool-execution/deps.d.ts +3 -3
- package/dist/agent/turn/tool-execution/dispatch.js +3 -5
- package/dist/agent/turn/tool-execution/dispatch.js.map +1 -1
- package/dist/agent/turn/tool-execution/meta-tools.d.ts +1 -1
- package/dist/agent/turn/tool-execution/meta-tools.js +13 -11
- package/dist/agent/turn/tool-execution/meta-tools.js.map +1 -1
- package/dist/agent/turn/tool-execution/plan-tool-ledger.d.ts +2 -2
- package/dist/agent/turn/tool-execution/plan-tool-ledger.js +6 -6
- package/dist/agent/turn/tool-execution/plan-tool-ledger.js.map +1 -1
- package/dist/agent/turn/tool-execution/result-framing.d.ts +1 -1
- package/dist/agent/turn/tool-execution/result-framing.js +1 -2
- package/dist/agent/turn/tool-execution/result-framing.js.map +1 -1
- package/dist/agent/turn/tool-execution/single-tool.js +28 -16
- package/dist/agent/turn/tool-execution/single-tool.js.map +1 -1
- package/dist/app/adapters/agent-event-adapter.js +7 -7
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/controllers/plan-controller.js +4 -1
- package/dist/app/controllers/plan-controller.js.map +1 -1
- package/dist/app/controllers/session-compact-helper.js +11 -8
- package/dist/app/controllers/session-compact-helper.js.map +1 -1
- package/dist/app/controllers/session-context-usage.d.ts +6 -4
- package/dist/app/controllers/session-context-usage.js +94 -33
- package/dist/app/controllers/session-context-usage.js.map +1 -1
- package/dist/app/controllers/session-controller.d.ts +5 -6
- package/dist/app/controllers/session-controller.js +48 -40
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/controllers/session-responder.d.ts +2 -0
- package/dist/app/controllers/session-responder.js +18 -0
- package/dist/app/controllers/session-responder.js.map +1 -1
- package/dist/app/events/app-event.d.ts +3 -5
- package/dist/app/events/app-event.js.map +1 -1
- package/dist/classic/panels/pager-panel.js +3 -2
- package/dist/classic/panels/pager-panel.js.map +1 -1
- package/dist/commands/providers.d.ts +2 -0
- package/dist/commands/providers.js +49 -7
- package/dist/commands/providers.js.map +1 -1
- package/dist/llm/anthropic.d.ts +1 -0
- package/dist/llm/anthropic.js +20 -21
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/capabilities.d.ts +1 -4
- package/dist/llm/capabilities.js +24 -19
- package/dist/llm/capabilities.js.map +1 -1
- package/dist/llm/capability/state.js +0 -17
- package/dist/llm/capability/state.js.map +1 -1
- package/dist/llm/catalog-facts.js +40 -11
- package/dist/llm/catalog-facts.js.map +1 -1
- package/dist/llm/catalog-prefetch.js +9 -6
- package/dist/llm/catalog-prefetch.js.map +1 -1
- package/dist/llm/context-snapshot.d.ts +7 -3
- package/dist/llm/context-snapshot.js +35 -14
- package/dist/llm/context-snapshot.js.map +1 -1
- package/dist/llm/context-windows.d.ts +16 -0
- package/dist/llm/context-windows.js +54 -19
- package/dist/llm/context-windows.js.map +1 -1
- package/dist/llm/custom-providers.js +5 -4
- package/dist/llm/custom-providers.js.map +1 -1
- package/dist/llm/explabs.js +35 -26
- package/dist/llm/explabs.js.map +1 -1
- package/dist/llm/free.d.ts +1 -1
- package/dist/llm/free.js +26 -18
- package/dist/llm/free.js.map +1 -1
- package/dist/llm/gemini.js +25 -12
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/kiro-auth.d.ts +34 -3
- package/dist/llm/kiro-auth.js +315 -144
- package/dist/llm/kiro-auth.js.map +1 -1
- package/dist/llm/kiro-import-sources.d.ts +10 -0
- package/dist/llm/kiro-import-sources.js +117 -0
- package/dist/llm/kiro-import-sources.js.map +1 -0
- package/dist/llm/kiro-reasoning.d.ts +28 -0
- package/dist/llm/kiro-reasoning.js +150 -0
- package/dist/llm/kiro-reasoning.js.map +1 -0
- package/dist/llm/kiro-social-device.d.ts +21 -0
- package/dist/llm/kiro-social-device.js +101 -0
- package/dist/llm/kiro-social-device.js.map +1 -0
- package/dist/llm/kiro.d.ts +3 -1
- package/dist/llm/kiro.js +653 -187
- package/dist/llm/kiro.js.map +1 -1
- package/dist/llm/learned-capabilities.js +1 -3
- package/dist/llm/learned-capabilities.js.map +1 -1
- package/dist/llm/merge-gateway.js +18 -13
- package/dist/llm/merge-gateway.js.map +1 -1
- package/dist/llm/model-limit-store.d.ts +15 -0
- package/dist/llm/model-limit-store.js +121 -0
- package/dist/llm/model-limit-store.js.map +1 -0
- package/dist/llm/nvidia.d.ts +1 -0
- package/dist/llm/nvidia.js +15 -17
- package/dist/llm/nvidia.js.map +1 -1
- package/dist/llm/ollama-model-limits.d.ts +4 -0
- package/dist/llm/ollama-model-limits.js +91 -0
- package/dist/llm/ollama-model-limits.js.map +1 -0
- package/dist/llm/ollama.js +2 -1
- package/dist/llm/ollama.js.map +1 -1
- package/dist/llm/orcarouter.d.ts +1 -0
- package/dist/llm/orcarouter.js +8 -1
- package/dist/llm/orcarouter.js.map +1 -1
- package/dist/llm/provider-context-usage.d.ts +9 -0
- package/dist/llm/provider-context-usage.js +39 -0
- package/dist/llm/provider-context-usage.js.map +1 -0
- package/dist/llm/qwen-cloud.d.ts +1 -0
- package/dist/llm/qwen-cloud.js +44 -9
- package/dist/llm/qwen-cloud.js.map +1 -1
- package/dist/llm/reasoning-errors.d.ts +1 -0
- package/dist/llm/reasoning-errors.js +6 -0
- package/dist/llm/reasoning-errors.js.map +1 -1
- package/dist/llm/routing/attempt-complete.js +9 -2
- package/dist/llm/routing/attempt-complete.js.map +1 -1
- package/dist/llm/routing/attempt-request.d.ts +1 -0
- package/dist/llm/routing/attempt-request.js +23 -0
- package/dist/llm/routing/attempt-request.js.map +1 -1
- package/dist/llm/routing/attempt-stream.js +15 -2
- package/dist/llm/routing/attempt-stream.js.map +1 -1
- package/dist/llm/token-estimate-calibration.js +1 -2
- package/dist/llm/token-estimate-calibration.js.map +1 -1
- package/dist/llm/token-usage.d.ts +2 -0
- package/dist/llm/token-usage.js +1 -1
- package/dist/llm/token-usage.js.map +1 -1
- package/dist/llm/wire/anthropic-model-catalog.d.ts +1 -0
- package/dist/llm/wire/anthropic-model-catalog.js +30 -0
- package/dist/llm/wire/anthropic-model-catalog.js.map +1 -0
- package/dist/llm/wire/dashscope-model-catalog.d.ts +1 -0
- package/dist/llm/wire/dashscope-model-catalog.js +53 -0
- package/dist/llm/wire/dashscope-model-catalog.js.map +1 -0
- package/dist/llm/wire/orcarouter-model-catalog.d.ts +2 -0
- package/dist/llm/wire/orcarouter-model-catalog.js +91 -0
- package/dist/llm/wire/orcarouter-model-catalog.js.map +1 -0
- package/dist/noninteractive/stream-blocks.d.ts +0 -3
- package/dist/noninteractive/stream-blocks.js +0 -9
- package/dist/noninteractive/stream-blocks.js.map +1 -1
- package/dist/noninteractive/stream-renderer.js +1 -4
- package/dist/noninteractive/stream-renderer.js.map +1 -1
- package/dist/store/config/endpoints.d.ts +0 -6
- package/dist/store/config/endpoints.js +1 -35
- package/dist/store/config/endpoints.js.map +1 -1
- package/dist/store/context-limits.d.ts +4 -0
- package/dist/store/context-limits.js +29 -0
- package/dist/store/context-limits.js.map +1 -0
- package/dist/store/plan/jsonl-backend.js +1 -4
- package/dist/store/plan/jsonl-backend.js.map +1 -1
- package/dist/store/plan/mutation.js +31 -1
- package/dist/store/plan/mutation.js.map +1 -1
- package/dist/store/plan/sqlite-backend.js +27 -9
- package/dist/store/plan/sqlite-backend.js.map +1 -1
- package/dist/tui-v2/components/pager/pager-line.d.ts +2 -0
- package/dist/tui-v2/components/pager/pager-line.js +1 -2
- package/dist/tui-v2/components/pager/pager-line.js.map +1 -1
- package/dist/tui-v2/components/pager/pager.js +5 -2
- package/dist/tui-v2/components/pager/pager.js.map +1 -1
- package/dist/tui-v2/components/transcript/tool-card.js +1 -1
- package/dist/tui-v2/components/transcript/tool-card.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.js.map +1 -1
- package/dist/ui-core/bootstrap/composition-root.js +8 -5
- package/dist/ui-core/bootstrap/composition-root.js.map +1 -1
- package/dist/ui-core/bootstrap/session-resume.js +1 -2
- package/dist/ui-core/bootstrap/session-resume.js.map +1 -1
- package/dist/ui-core/commands/key-commands.d.ts +2 -0
- package/dist/ui-core/commands/key-commands.js +76 -20
- package/dist/ui-core/commands/key-commands.js.map +1 -1
- package/dist/ui-core/commands/session-commands.js +33 -9
- package/dist/ui-core/commands/session-commands.js.map +1 -1
- package/dist/ui-core/rendering/batch-sections.js +10 -1
- package/dist/ui-core/rendering/batch-sections.js.map +1 -1
- package/dist/ui-core/rendering/context-limit.d.ts +0 -1
- package/dist/ui-core/rendering/context-limit.js +2 -2
- package/dist/ui-core/rendering/context-limit.js.map +1 -1
- package/dist/ui-core/rendering/subagent-presentation.d.ts +2 -0
- package/dist/ui-core/rendering/subagent-presentation.js +20 -7
- package/dist/ui-core/rendering/subagent-presentation.js.map +1 -1
- package/dist/ui-core/rendering/subagent-source.js +15 -8
- package/dist/ui-core/rendering/subagent-source.js.map +1 -1
- package/dist/ui-core/state/transcript/apply-app-event.js +0 -1
- package/dist/ui-core/state/transcript/apply-app-event.js.map +1 -1
- package/dist/ui-core/state/transcript-types.js +1 -1
- package/dist/ui-core/state/transcript-types.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +1 -1
- package/dist/app/controllers/session-context-limits.d.ts +0 -8
- package/dist/app/controllers/session-context-limits.js +0 -35
- package/dist/app/controllers/session-context-limits.js.map +0 -1
- package/dist/store/config/compaction.d.ts +0 -1
- package/dist/store/config/compaction.js +0 -2
- package/dist/store/config/compaction.js.map +0 -1
package/dist/llm/kiro.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { defaultModels, } from "./provider.js";
|
|
3
3
|
import { ProviderError } from "./http.js";
|
|
4
|
-
import {
|
|
4
|
+
import { decodeKiroKey, discoverKiroModelsDetailed, getKiroUsageLimits, isKiroOAuthToken, KiroRefreshError, kiroCredentialNeedsRefresh, maybeRefreshKiroCredential, resolveKiroRuntimeRegion, } from "./kiro-auth.js";
|
|
5
5
|
import { currentSessionAffinity } from "./session-affinity.js";
|
|
6
|
-
import {
|
|
6
|
+
import { nearestAcceptedEffort } from "./reasoning-controls.js";
|
|
7
|
+
import { completeGenerationAttempt, generationFetch, } from "./operation-usage.js";
|
|
7
8
|
import { learnModelVisionCapability } from "./capability/vision-registry.js";
|
|
8
9
|
import { emitStreamReasoningDelta } from "./stream-events.js";
|
|
10
|
+
import { createReasoningArtifactProvenance, createReasoningArtifactReplayTarget, reasoningArtifactSignature, reasoningArtifactText, reasoningArtifactsForMessage, selectReasoningArtifactsForReplay, } from "./reasoning-artifacts.js";
|
|
11
|
+
import { createKiroReasoningAccumulator, kiroPrivateReasoningNote, kiroCatalogEfforts, kiroReasoningResult, sentKiroReasoningEffort, } from "./kiro-reasoning.js";
|
|
12
|
+
import { registerModelCatalogLimits, registerModelReasoningEfforts, } from "./capabilities.js";
|
|
13
|
+
import { modelContextWindow } from "./context-windows.js";
|
|
14
|
+
import { providerRatioPromptTokens, providerRatioUsage, } from "./provider-context-usage.js";
|
|
15
|
+
import { inBandBadRequestStatus } from "./reasoning-errors.js";
|
|
9
16
|
import { replaceProviderKey } from "../store/keys.js";
|
|
10
17
|
const KIRO_FALLBACK_BASE_MODELS = [
|
|
11
18
|
"auto",
|
|
@@ -39,6 +46,8 @@ for (let i = 0; i < 256; i++) {
|
|
|
39
46
|
}
|
|
40
47
|
CRC32_TABLE[i] = c >>> 0;
|
|
41
48
|
}
|
|
49
|
+
const KIRO_EVENTSTREAM_MAX_MESSAGE_BYTES = 24 * 1024 * 1024;
|
|
50
|
+
const KIRO_EVENTSTREAM_MAX_HEADERS_BYTES = 128 * 1024;
|
|
42
51
|
function crc32(buf, start = 0, end = buf.length) {
|
|
43
52
|
let crc = 0xffffffff;
|
|
44
53
|
for (let i = start; i < end; i++) {
|
|
@@ -48,59 +57,73 @@ function crc32(buf, start = 0, end = buf.length) {
|
|
|
48
57
|
}
|
|
49
58
|
function parseHeaders(buf) {
|
|
50
59
|
const headers = {};
|
|
60
|
+
const names = new Set();
|
|
51
61
|
let offset = 0;
|
|
62
|
+
const requireBytes = (count) => {
|
|
63
|
+
if (offset + count > buf.length) {
|
|
64
|
+
throw new ProviderError("Kiro event-stream header exceeds its declared bounds", 502);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
52
67
|
while (offset < buf.length) {
|
|
68
|
+
requireBytes(1);
|
|
53
69
|
const nameLen = buf.readUInt8(offset);
|
|
54
70
|
offset += 1;
|
|
71
|
+
requireBytes(nameLen + 1);
|
|
55
72
|
const name = buf.toString("utf8", offset, offset + nameLen);
|
|
56
73
|
offset += nameLen;
|
|
74
|
+
if (names.has(name)) {
|
|
75
|
+
throw new ProviderError(`Duplicate Kiro event-stream header: ${name}`, 502);
|
|
76
|
+
}
|
|
77
|
+
names.add(name);
|
|
57
78
|
const type = buf.readUInt8(offset);
|
|
58
79
|
offset += 1;
|
|
59
|
-
if (type === 0) {
|
|
60
|
-
headers[name] =
|
|
61
|
-
|
|
62
|
-
else if (type === 1) {
|
|
63
|
-
headers[name] = false;
|
|
80
|
+
if (type === 0 || type === 1) {
|
|
81
|
+
headers[name] = type === 0;
|
|
82
|
+
continue;
|
|
64
83
|
}
|
|
65
|
-
|
|
84
|
+
if (type === 2) {
|
|
85
|
+
requireBytes(1);
|
|
66
86
|
headers[name] = buf.readInt8(offset);
|
|
67
87
|
offset += 1;
|
|
88
|
+
continue;
|
|
68
89
|
}
|
|
69
|
-
|
|
90
|
+
if (type === 3) {
|
|
91
|
+
requireBytes(2);
|
|
70
92
|
headers[name] = buf.readInt16BE(offset);
|
|
71
93
|
offset += 2;
|
|
94
|
+
continue;
|
|
72
95
|
}
|
|
73
|
-
|
|
96
|
+
if (type === 4) {
|
|
97
|
+
requireBytes(4);
|
|
74
98
|
headers[name] = buf.readInt32BE(offset);
|
|
75
99
|
offset += 4;
|
|
100
|
+
continue;
|
|
76
101
|
}
|
|
77
|
-
|
|
78
|
-
|
|
102
|
+
if (type === 5 || type === 8) {
|
|
103
|
+
requireBytes(8);
|
|
104
|
+
const value = buf.readBigInt64BE(offset);
|
|
105
|
+
headers[name] = type === 5 ? value : new Date(Number(value));
|
|
79
106
|
offset += 8;
|
|
107
|
+
continue;
|
|
80
108
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
offset += 2;
|
|
84
|
-
headers[name] = buf.subarray(offset, offset + len);
|
|
85
|
-
offset += len;
|
|
86
|
-
}
|
|
87
|
-
else if (type === 7) {
|
|
109
|
+
if (type === 6 || type === 7) {
|
|
110
|
+
requireBytes(2);
|
|
88
111
|
const len = buf.readUInt16BE(offset);
|
|
89
112
|
offset += 2;
|
|
90
|
-
|
|
113
|
+
requireBytes(len);
|
|
114
|
+
headers[name] = type === 7
|
|
115
|
+
? buf.toString("utf8", offset, offset + len)
|
|
116
|
+
: buf.subarray(offset, offset + len);
|
|
91
117
|
offset += len;
|
|
118
|
+
continue;
|
|
92
119
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
offset += 8;
|
|
96
|
-
}
|
|
97
|
-
else if (type === 9) {
|
|
120
|
+
if (type === 9) {
|
|
121
|
+
requireBytes(16);
|
|
98
122
|
headers[name] = buf.subarray(offset, offset + 16).toString("hex");
|
|
99
123
|
offset += 16;
|
|
124
|
+
continue;
|
|
100
125
|
}
|
|
101
|
-
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
126
|
+
throw new ProviderError(`Unknown Kiro event-stream header type ${type}`, 502);
|
|
104
127
|
}
|
|
105
128
|
return headers;
|
|
106
129
|
}
|
|
@@ -118,15 +141,20 @@ async function* parseEventStream(stream) {
|
|
|
118
141
|
while (buffer.length >= 12) {
|
|
119
142
|
const totalLength = buffer.readUInt32BE(0);
|
|
120
143
|
if (totalLength < 16) {
|
|
121
|
-
|
|
122
|
-
|
|
144
|
+
throw new ProviderError("Invalid Kiro event-stream frame length", 502);
|
|
145
|
+
}
|
|
146
|
+
if (totalLength > KIRO_EVENTSTREAM_MAX_MESSAGE_BYTES) {
|
|
147
|
+
throw new ProviderError(`Kiro event-stream frame length exceeds the ${KIRO_EVENTSTREAM_MAX_MESSAGE_BYTES}-byte protocol bound`, 502);
|
|
123
148
|
}
|
|
124
149
|
const headersLength = buffer.readUInt32BE(4);
|
|
150
|
+
if (headersLength > KIRO_EVENTSTREAM_MAX_HEADERS_BYTES ||
|
|
151
|
+
headersLength > totalLength - 16) {
|
|
152
|
+
throw new ProviderError("Invalid Kiro event-stream header length", 502);
|
|
153
|
+
}
|
|
125
154
|
const preludeCrc = buffer.readUInt32BE(8);
|
|
126
155
|
const expectedPreludeCrc = crc32(buffer, 0, 8);
|
|
127
156
|
if (preludeCrc !== expectedPreludeCrc) {
|
|
128
|
-
|
|
129
|
-
continue;
|
|
157
|
+
throw new ProviderError("Kiro event-stream prelude checksum failed", 502);
|
|
130
158
|
}
|
|
131
159
|
if (buffer.length < totalLength) {
|
|
132
160
|
break;
|
|
@@ -134,8 +162,7 @@ async function* parseEventStream(stream) {
|
|
|
134
162
|
const messageCrc = buffer.readUInt32BE(totalLength - 4);
|
|
135
163
|
const expectedMessageCrc = crc32(buffer, 0, totalLength - 4);
|
|
136
164
|
if (messageCrc !== expectedMessageCrc) {
|
|
137
|
-
|
|
138
|
-
continue;
|
|
165
|
+
throw new ProviderError("Kiro event-stream message checksum failed", 502);
|
|
139
166
|
}
|
|
140
167
|
const headersBuffer = buffer.subarray(12, 12 + headersLength);
|
|
141
168
|
const payloadBuffer = buffer.subarray(12 + headersLength, totalLength - 4);
|
|
@@ -144,16 +171,27 @@ async function* parseEventStream(stream) {
|
|
|
144
171
|
let payload = {};
|
|
145
172
|
if (payloadBuffer.length > 0) {
|
|
146
173
|
try {
|
|
147
|
-
const
|
|
148
|
-
|
|
174
|
+
const decoded = JSON.parse(payloadBuffer.toString("utf8"));
|
|
175
|
+
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) {
|
|
176
|
+
throw new Error("payload is not an object");
|
|
177
|
+
}
|
|
178
|
+
payload = decoded;
|
|
149
179
|
}
|
|
150
|
-
catch {
|
|
151
|
-
|
|
180
|
+
catch (error) {
|
|
181
|
+
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
182
|
+
throw new ProviderError(`Invalid Kiro event-stream JSON payload${detail}`, 502);
|
|
152
183
|
}
|
|
153
184
|
}
|
|
154
185
|
yield { headers, payload };
|
|
155
186
|
}
|
|
156
187
|
}
|
|
188
|
+
if (buffer.length > 0) {
|
|
189
|
+
throw new ProviderError("Kiro event stream ended with a partial frame", 502);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
await reader.cancel(error).catch(() => { });
|
|
194
|
+
throw error;
|
|
157
195
|
}
|
|
158
196
|
finally {
|
|
159
197
|
reader.releaseLock();
|
|
@@ -183,8 +221,8 @@ export function resolveKiroModel(model) {
|
|
|
183
221
|
}
|
|
184
222
|
return { upstream, agentic, thinking };
|
|
185
223
|
}
|
|
186
|
-
function
|
|
187
|
-
return /^claude
|
|
224
|
+
function isLegacyThinkingDirectiveModel(model) {
|
|
225
|
+
return /^claude-(?:opus-4\.5|sonnet-4(?:\.5)?|haiku-4\.5)$/i.test(model);
|
|
188
226
|
}
|
|
189
227
|
function kiroEffortString(effort) {
|
|
190
228
|
if (!effort || effort === "none")
|
|
@@ -201,6 +239,145 @@ function kiroEffortString(effort) {
|
|
|
201
239
|
return "xhigh";
|
|
202
240
|
return "max";
|
|
203
241
|
}
|
|
242
|
+
function asKiroRecord(value) {
|
|
243
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
244
|
+
? value
|
|
245
|
+
: undefined;
|
|
246
|
+
}
|
|
247
|
+
function normalizeKiroStopReason(value) {
|
|
248
|
+
const reason = typeof value === "string" ? value.trim() : "";
|
|
249
|
+
const normalized = reason
|
|
250
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
251
|
+
.toLowerCase()
|
|
252
|
+
.replace(/[\s-]+/g, "_");
|
|
253
|
+
if (["endturn", "end_turn", "stop", "stop_sequence", "completed"].includes(normalized)) {
|
|
254
|
+
return "end_turn";
|
|
255
|
+
}
|
|
256
|
+
if (["tooluse", "tool_use", "tool_calls"].includes(normalized))
|
|
257
|
+
return "tool_use";
|
|
258
|
+
if (["maxtokens", "max_tokens", "max_output_tokens", "length"].includes(normalized)) {
|
|
259
|
+
return "max_tokens";
|
|
260
|
+
}
|
|
261
|
+
return normalized;
|
|
262
|
+
}
|
|
263
|
+
function kiroStopDisposition(reason, hasToolCalls) {
|
|
264
|
+
if (["malformed_model_output", "invalid_model_output"].includes(reason))
|
|
265
|
+
return "retryable";
|
|
266
|
+
if (reason === "refusal" || /(?:content.*filter|guardrail|safety|policy|blocked)/u.test(reason)) {
|
|
267
|
+
return "blocked";
|
|
268
|
+
}
|
|
269
|
+
if (["cancelled", "pause_turn"].includes(reason))
|
|
270
|
+
return "incomplete";
|
|
271
|
+
if (["max_tokens", "model_context_window_exceeded"].includes(reason)) {
|
|
272
|
+
return hasToolCalls ? "incomplete" : "length";
|
|
273
|
+
}
|
|
274
|
+
if (hasToolCalls || reason === "tool_use")
|
|
275
|
+
return "tool_calls";
|
|
276
|
+
if (!reason || reason === "end_turn")
|
|
277
|
+
return "complete";
|
|
278
|
+
return "unknown";
|
|
279
|
+
}
|
|
280
|
+
function mergeKiroStopReason(current, incoming) {
|
|
281
|
+
if (!incoming)
|
|
282
|
+
return current;
|
|
283
|
+
if (!current)
|
|
284
|
+
return incoming;
|
|
285
|
+
const severity = (reason) => {
|
|
286
|
+
const disposition = kiroStopDisposition(reason, false);
|
|
287
|
+
if (disposition === "blocked")
|
|
288
|
+
return 6;
|
|
289
|
+
if (disposition === "incomplete" || disposition === "unknown")
|
|
290
|
+
return 5;
|
|
291
|
+
if (disposition === "retryable")
|
|
292
|
+
return 4;
|
|
293
|
+
if (disposition === "length")
|
|
294
|
+
return 3;
|
|
295
|
+
if (disposition === "tool_calls")
|
|
296
|
+
return 2;
|
|
297
|
+
return 1;
|
|
298
|
+
};
|
|
299
|
+
return severity(incoming) > severity(current) ? incoming : current;
|
|
300
|
+
}
|
|
301
|
+
function firstKiroMetric(sources, names) {
|
|
302
|
+
for (const source of sources) {
|
|
303
|
+
for (const name of names) {
|
|
304
|
+
const value = source[name];
|
|
305
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
function schemaEnum(schema) {
|
|
313
|
+
return Array.isArray(schema?.enum)
|
|
314
|
+
? schema.enum.filter((value) => typeof value === "string")
|
|
315
|
+
: [];
|
|
316
|
+
}
|
|
317
|
+
function schemaProperty(schema, name) {
|
|
318
|
+
return asKiroRecord(asKiroRecord(schema?.properties)?.[name]);
|
|
319
|
+
}
|
|
320
|
+
function supportedEffort(requested, schema) {
|
|
321
|
+
const efforts = schemaEnum(schema);
|
|
322
|
+
if (efforts.length === 0)
|
|
323
|
+
return undefined;
|
|
324
|
+
const normalized = requested === "minimal" ? "low" : requested;
|
|
325
|
+
return nearestAcceptedEffort(normalized, efforts);
|
|
326
|
+
}
|
|
327
|
+
function schemaEffortFields(schema) {
|
|
328
|
+
const output = schemaProperty(schema, "output_config");
|
|
329
|
+
const outputEffort = schemaProperty(output, "effort");
|
|
330
|
+
if (outputEffort)
|
|
331
|
+
return { key: "output_config", schema: outputEffort };
|
|
332
|
+
const reasoning = schemaProperty(schema, "reasoning");
|
|
333
|
+
const reasoningEffort = schemaProperty(reasoning, "effort");
|
|
334
|
+
return reasoningEffort
|
|
335
|
+
? { key: "reasoning", schema: reasoningEffort }
|
|
336
|
+
: undefined;
|
|
337
|
+
}
|
|
338
|
+
function kiroAdditionalModelFields(request, info, wantsThinking) {
|
|
339
|
+
const schema = info?.additionalModelRequestFieldsSchema;
|
|
340
|
+
const thinkingSchema = schemaProperty(schema, "thinking");
|
|
341
|
+
const effortFields = schemaEffortFields(schema);
|
|
342
|
+
if (!wantsThinking && !request.thinking)
|
|
343
|
+
return undefined;
|
|
344
|
+
const requestedEffort = wantsThinking
|
|
345
|
+
? request.thinking?.effort ?? "high"
|
|
346
|
+
: "none";
|
|
347
|
+
if (!thinkingSchema && !effortFields)
|
|
348
|
+
return undefined;
|
|
349
|
+
const fields = {};
|
|
350
|
+
if (thinkingSchema) {
|
|
351
|
+
const types = schemaEnum(schemaProperty(thinkingSchema, "type"));
|
|
352
|
+
if (!wantsThinking && types.includes("disabled")) {
|
|
353
|
+
return { thinking: { type: "disabled" } };
|
|
354
|
+
}
|
|
355
|
+
if (types.includes("adaptive")) {
|
|
356
|
+
fields.thinking = { type: "adaptive", display: "summarized" };
|
|
357
|
+
}
|
|
358
|
+
else if (wantsThinking) {
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (effortFields) {
|
|
363
|
+
const effort = supportedEffort(requestedEffort, effortFields.schema);
|
|
364
|
+
if (effort)
|
|
365
|
+
fields[effortFields.key] = { effort };
|
|
366
|
+
}
|
|
367
|
+
const maxTokensSchema = schemaProperty(schema, "max_tokens");
|
|
368
|
+
if (wantsThinking && request.maxTokens && maxTokensSchema) {
|
|
369
|
+
const minimum = typeof maxTokensSchema.minimum === "number" ? maxTokensSchema.minimum : 1;
|
|
370
|
+
const maximum = typeof maxTokensSchema.maximum === "number"
|
|
371
|
+
? maxTokensSchema.maximum
|
|
372
|
+
: info?.maxOutputTokens ?? request.maxTokens;
|
|
373
|
+
fields.max_tokens = Math.min(maximum, Math.max(minimum, request.maxTokens));
|
|
374
|
+
}
|
|
375
|
+
return Object.keys(fields).length > 0 ? fields : undefined;
|
|
376
|
+
}
|
|
377
|
+
function legacyThinkingDirective(effort) {
|
|
378
|
+
const budget = KIRO_THINKING_BUDGET[kiroEffortString(effort) || "high"] ?? 16000;
|
|
379
|
+
return `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>`;
|
|
380
|
+
}
|
|
204
381
|
const KIRO_THINKING_BUDGET = {
|
|
205
382
|
low: 4000,
|
|
206
383
|
medium: 8000,
|
|
@@ -239,7 +416,12 @@ function resolveKiroCredential(auth) {
|
|
|
239
416
|
};
|
|
240
417
|
}
|
|
241
418
|
async function withKiroCredential(auth, run, onStatus) {
|
|
242
|
-
|
|
419
|
+
let credential = resolveKiroCredential(auth);
|
|
420
|
+
if (credential.refreshToken && kiroCredentialNeedsRefresh(credential)) {
|
|
421
|
+
const refreshed = await refreshStoredKiroKey(auth).catch(() => undefined);
|
|
422
|
+
if (refreshed)
|
|
423
|
+
credential = refreshed;
|
|
424
|
+
}
|
|
243
425
|
try {
|
|
244
426
|
return await run(credential);
|
|
245
427
|
}
|
|
@@ -248,27 +430,51 @@ async function withKiroCredential(auth, run, onStatus) {
|
|
|
248
430
|
if (status !== 401 && status !== 403)
|
|
249
431
|
throw error;
|
|
250
432
|
onStatus?.("ℹ Kiro authentication expired — attempting token refresh");
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
433
|
+
let newCredential;
|
|
434
|
+
try {
|
|
435
|
+
newCredential = await refreshStoredKiroKey(auth);
|
|
436
|
+
}
|
|
437
|
+
catch (refreshError) {
|
|
438
|
+
if (refreshError instanceof KiroRefreshError) {
|
|
439
|
+
throw new ProviderError(refreshError.message, status);
|
|
440
|
+
}
|
|
254
441
|
throw error;
|
|
255
442
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const newCredential = resolveKiroCredential({ ...auth, apiKey: refreshedKey });
|
|
443
|
+
if (!newCredential)
|
|
444
|
+
throw error;
|
|
259
445
|
onStatus?.("ℹ Kiro token refreshed — retrying request");
|
|
260
446
|
return run(newCredential);
|
|
261
447
|
}
|
|
262
448
|
}
|
|
263
|
-
function
|
|
264
|
-
const
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
449
|
+
async function refreshStoredKiroKey(auth) {
|
|
450
|
+
const oldKey = auth.apiKey ?? "";
|
|
451
|
+
const refreshedKey = await maybeRefreshKiroCredential(oldKey, auth.refreshToken);
|
|
452
|
+
if (!refreshedKey || refreshedKey === oldKey)
|
|
453
|
+
return undefined;
|
|
454
|
+
await replaceProviderKey("kiro", oldKey, refreshedKey).catch(() => { });
|
|
455
|
+
auth.apiKey = refreshedKey;
|
|
456
|
+
return resolveKiroCredential({ ...auth, apiKey: refreshedKey });
|
|
457
|
+
}
|
|
458
|
+
function getCandidateEndpoints(credential, generation) {
|
|
459
|
+
const region = resolveKiroRuntimeRegion(credential);
|
|
460
|
+
const apiRegion = region;
|
|
461
|
+
const modern = { url: `https://runtime.${apiRegion}.kiro.dev/`, awsTarget: true };
|
|
462
|
+
const q = {
|
|
463
|
+
url: `https://q.${region}.amazonaws.com/generateAssistantResponse`,
|
|
464
|
+
awsTarget: false,
|
|
465
|
+
};
|
|
466
|
+
const codewhisperer = {
|
|
467
|
+
url: `https://codewhisperer.${region}.amazonaws.com/generateAssistantResponse`,
|
|
468
|
+
awsTarget: true,
|
|
469
|
+
};
|
|
470
|
+
if (generation === "modern") {
|
|
471
|
+
return credential.authMethod === "api_key"
|
|
472
|
+
? [modern, q, codewhisperer]
|
|
473
|
+
: [modern, codewhisperer, q];
|
|
270
474
|
}
|
|
271
|
-
return
|
|
475
|
+
return credential.authMethod === "api_key"
|
|
476
|
+
? [q, modern, codewhisperer]
|
|
477
|
+
: [codewhisperer, modern, q];
|
|
272
478
|
}
|
|
273
479
|
function uuidFromHex(hex) {
|
|
274
480
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
@@ -290,12 +496,12 @@ function sanitizeToolName(name) {
|
|
|
290
496
|
function formatKiroTools(tools) {
|
|
291
497
|
if (!tools || tools.length === 0)
|
|
292
498
|
return [];
|
|
293
|
-
return tools.map((
|
|
499
|
+
return tools.map((tool) => ({
|
|
294
500
|
toolSpecification: {
|
|
295
|
-
name: sanitizeToolName(
|
|
296
|
-
description: (
|
|
501
|
+
name: sanitizeToolName(tool.wireName || tool.name),
|
|
502
|
+
description: (tool.description || `Tool: ${tool.name}`).slice(0, 10237),
|
|
297
503
|
inputSchema: {
|
|
298
|
-
json:
|
|
504
|
+
json: tool.parameters,
|
|
299
505
|
},
|
|
300
506
|
},
|
|
301
507
|
}));
|
|
@@ -312,21 +518,34 @@ function imageFormatFromMediaType(mediaType) {
|
|
|
312
518
|
return "webp";
|
|
313
519
|
return "png";
|
|
314
520
|
}
|
|
315
|
-
function buildKiroRequestBody(request, credential, upstreamModel, agentic, thinking) {
|
|
521
|
+
export function buildKiroRequestBody(request, credential, upstreamModel, agentic, thinking) {
|
|
316
522
|
const agenticInstruction = agentic
|
|
317
523
|
? "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
524
|
: "";
|
|
319
525
|
const systemParts = [];
|
|
320
526
|
if (agenticInstruction)
|
|
321
527
|
systemParts.push(agenticInstruction);
|
|
528
|
+
let sawLeadingSystem = false;
|
|
322
529
|
const nonSystemMessages = [];
|
|
323
530
|
for (const msg of request.messages) {
|
|
324
|
-
if (msg.role
|
|
531
|
+
if (msg.role !== "system") {
|
|
532
|
+
nonSystemMessages.push(msg);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (!sawLeadingSystem) {
|
|
536
|
+
sawLeadingSystem = true;
|
|
325
537
|
if (msg.content.trim())
|
|
326
538
|
systemParts.push(msg.content.trim());
|
|
539
|
+
continue;
|
|
327
540
|
}
|
|
328
|
-
|
|
329
|
-
nonSystemMessages.push(
|
|
541
|
+
if (msg.content.trim()) {
|
|
542
|
+
nonSystemMessages.push({
|
|
543
|
+
...msg,
|
|
544
|
+
role: "user",
|
|
545
|
+
content: msg.content.startsWith("[SYSTEM]")
|
|
546
|
+
? msg.content
|
|
547
|
+
: `[SYSTEM]\n${msg.content}`,
|
|
548
|
+
});
|
|
330
549
|
}
|
|
331
550
|
}
|
|
332
551
|
const systemPrompt = systemParts.join("\n\n").trim();
|
|
@@ -357,6 +576,40 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
357
576
|
}
|
|
358
577
|
}
|
|
359
578
|
else if (msg.role === "assistant") {
|
|
579
|
+
const replayTarget = createReasoningArtifactReplayTarget({
|
|
580
|
+
provider: "kiro",
|
|
581
|
+
model: upstreamModel,
|
|
582
|
+
dialect: "kiro-eventstream",
|
|
583
|
+
});
|
|
584
|
+
const replayedReasoning = request.forceReasoningReplay === false
|
|
585
|
+
? []
|
|
586
|
+
: selectReasoningArtifactsForReplay({
|
|
587
|
+
artifacts: reasoningArtifactsForMessage(msg),
|
|
588
|
+
target: replayTarget,
|
|
589
|
+
context: {
|
|
590
|
+
hasToolCalls: Boolean(msg.toolCalls?.length),
|
|
591
|
+
forceScope: request.forceReasoningReplay === true,
|
|
592
|
+
},
|
|
593
|
+
observe: request.onReasoningArtifactReplayDecision,
|
|
594
|
+
});
|
|
595
|
+
const signedReasoning = replayedReasoning.find((artifact) => reasoningArtifactText(artifact) && reasoningArtifactSignature(artifact));
|
|
596
|
+
const redactedReasoning = replayedReasoning.find((artifact) => {
|
|
597
|
+
const raw = asKiroRecord(artifact.raw);
|
|
598
|
+
return artifact.kind === "encrypted" && typeof raw?.redactedContent === "string";
|
|
599
|
+
});
|
|
600
|
+
const redactedRaw = redactedReasoning
|
|
601
|
+
? asKiroRecord(redactedReasoning.raw)
|
|
602
|
+
: undefined;
|
|
603
|
+
const reasoningContent = signedReasoning
|
|
604
|
+
? {
|
|
605
|
+
reasoningText: {
|
|
606
|
+
text: reasoningArtifactText(signedReasoning),
|
|
607
|
+
signature: reasoningArtifactSignature(signedReasoning),
|
|
608
|
+
},
|
|
609
|
+
}
|
|
610
|
+
: typeof redactedRaw?.redactedContent === "string"
|
|
611
|
+
? { redactedContent: redactedRaw.redactedContent }
|
|
612
|
+
: undefined;
|
|
360
613
|
const toolUses = (msg.toolCalls ?? [])
|
|
361
614
|
.filter((tc) => tc.id)
|
|
362
615
|
.map((tc) => ({
|
|
@@ -371,6 +624,9 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
371
624
|
? `${last.content}\n\n${msg.content}`
|
|
372
625
|
: msg.content;
|
|
373
626
|
}
|
|
627
|
+
if (reasoningContent && !last.reasoningContent) {
|
|
628
|
+
last.reasoningContent = reasoningContent;
|
|
629
|
+
}
|
|
374
630
|
if (toolUses.length > 0) {
|
|
375
631
|
last.toolUses = [...(last.toolUses ?? []), ...toolUses];
|
|
376
632
|
}
|
|
@@ -379,6 +635,7 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
379
635
|
turns.push({
|
|
380
636
|
role: "assistant",
|
|
381
637
|
content: msg.content || "",
|
|
638
|
+
reasoningContent,
|
|
382
639
|
toolUses: toolUses.length > 0 ? toolUses : undefined,
|
|
383
640
|
});
|
|
384
641
|
}
|
|
@@ -421,7 +678,24 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
421
678
|
: "continue";
|
|
422
679
|
}
|
|
423
680
|
}
|
|
681
|
+
const modelInfo = kiroModelCatalog().find((info) => info.modelId === upstreamModel);
|
|
424
682
|
const kiroTools = formatKiroTools(request.tools);
|
|
683
|
+
const wantsThinking = (request.thinking?.enabled ?? thinking) &&
|
|
684
|
+
request.thinking?.effort !== "none";
|
|
685
|
+
const additionalFields = kiroAdditionalModelFields(request, modelInfo, wantsThinking);
|
|
686
|
+
const thinkingDirective = !additionalFields &&
|
|
687
|
+
wantsThinking &&
|
|
688
|
+
isLegacyThinkingDirectiveModel(upstreamModel) &&
|
|
689
|
+
!modelInfo?.additionalModelRequestFieldsSchema
|
|
690
|
+
? legacyThinkingDirective(request.thinking?.effort)
|
|
691
|
+
: "";
|
|
692
|
+
if (thinkingDirective) {
|
|
693
|
+
for (const turn of turns) {
|
|
694
|
+
if (turn.role === "user") {
|
|
695
|
+
turn.content = `${thinkingDirective}\n\n${turn.content}`;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
425
699
|
const history = [];
|
|
426
700
|
for (let i = 0; i < turns.length - 1; i++) {
|
|
427
701
|
const turn = turns[i];
|
|
@@ -446,6 +720,9 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
446
720
|
history.push({
|
|
447
721
|
assistantResponseMessage: {
|
|
448
722
|
content: turn.content,
|
|
723
|
+
...(turn.reasoningContent
|
|
724
|
+
? { reasoningContent: turn.reasoningContent }
|
|
725
|
+
: {}),
|
|
449
726
|
...(turn.toolUses && turn.toolUses.length > 0
|
|
450
727
|
? { toolUses: turn.toolUses }
|
|
451
728
|
: {}),
|
|
@@ -485,28 +762,68 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
485
762
|
if (credential.profileArn) {
|
|
486
763
|
payload.profileArn = credential.profileArn;
|
|
487
764
|
}
|
|
488
|
-
|
|
489
|
-
|
|
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 ?? "")}`;
|
|
765
|
+
if (additionalFields) {
|
|
766
|
+
payload.additionalModelRequestFields = additionalFields;
|
|
497
767
|
}
|
|
498
768
|
return payload;
|
|
499
769
|
}
|
|
500
770
|
let cachedKiroModels = null;
|
|
501
771
|
let cachedKiroModelInfo = [];
|
|
772
|
+
let cachedKiroApiGeneration;
|
|
773
|
+
let cachedKiroCredentialId = "";
|
|
502
774
|
let lastKiroModelFetch = 0;
|
|
503
775
|
const MODEL_CACHE_TTL_MS = 30 * 60 * 1000;
|
|
776
|
+
function kiroCredentialId(credential) {
|
|
777
|
+
return createHash("sha256")
|
|
778
|
+
.update(credential.apiKey || credential.accessToken || credential.refreshToken || "")
|
|
779
|
+
.digest("hex");
|
|
780
|
+
}
|
|
781
|
+
function hasFreshKiroCatalog(credentialId) {
|
|
782
|
+
return (cachedKiroCredentialId === credentialId &&
|
|
783
|
+
cachedKiroModels !== null &&
|
|
784
|
+
Date.now() - lastKiroModelFetch < MODEL_CACHE_TTL_MS);
|
|
785
|
+
}
|
|
786
|
+
function kiroCatalogLimits(modelId, info) {
|
|
787
|
+
if (info.maxInputTokens === undefined && info.maxOutputTokens === undefined)
|
|
788
|
+
return [];
|
|
789
|
+
return [{
|
|
790
|
+
id: modelId,
|
|
791
|
+
...(info.maxInputTokens !== undefined ? { contextTokens: info.maxInputTokens } : {}),
|
|
792
|
+
...(info.maxOutputTokens !== undefined ? { maxOutputTokens: info.maxOutputTokens } : {}),
|
|
793
|
+
...(info.supportsImages !== undefined ? { vision: info.supportsImages } : {}),
|
|
794
|
+
}];
|
|
795
|
+
}
|
|
796
|
+
async function ensureKiroModelCatalog(credential) {
|
|
797
|
+
const credentialId = kiroCredentialId(credential);
|
|
798
|
+
if (hasFreshKiroCatalog(credentialId))
|
|
799
|
+
return;
|
|
800
|
+
const catalog = await discoverKiroModelsDetailed(credential);
|
|
801
|
+
cachedKiroCredentialId = credentialId;
|
|
802
|
+
cachedKiroModelInfo = catalog.models;
|
|
803
|
+
cachedKiroApiGeneration = catalog.generation;
|
|
804
|
+
cachedKiroModels = withKiroVariants(catalog.models.map((info) => info.modelId));
|
|
805
|
+
lastKiroModelFetch = Date.now();
|
|
806
|
+
const limits = [];
|
|
807
|
+
for (const info of catalog.models) {
|
|
808
|
+
if (info.supportsImages !== undefined) {
|
|
809
|
+
learnModelVisionCapability("kiro", info.modelId, info.supportsImages);
|
|
810
|
+
}
|
|
811
|
+
const efforts = kiroCatalogEfforts(info.additionalModelRequestFieldsSchema);
|
|
812
|
+
for (const variant of withKiroVariants([info.modelId])) {
|
|
813
|
+
registerModelReasoningEfforts("kiro", variant, efforts);
|
|
814
|
+
limits.push(...kiroCatalogLimits(variant, info));
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
registerModelCatalogLimits("kiro", limits);
|
|
818
|
+
}
|
|
504
819
|
export function kiroModelCatalog() {
|
|
505
820
|
return cachedKiroModelInfo;
|
|
506
821
|
}
|
|
507
822
|
export function resetKiroModelCacheForTesting() {
|
|
508
823
|
cachedKiroModels = null;
|
|
509
824
|
cachedKiroModelInfo = [];
|
|
825
|
+
cachedKiroApiGeneration = undefined;
|
|
826
|
+
cachedKiroCredentialId = "";
|
|
510
827
|
lastKiroModelFetch = 0;
|
|
511
828
|
}
|
|
512
829
|
export async function fetchKiroUsageLimits(auth, onStatus) {
|
|
@@ -541,56 +858,35 @@ export const kiroProvider = {
|
|
|
541
858
|
return trimmed.length >= 8;
|
|
542
859
|
},
|
|
543
860
|
async listModels(auth) {
|
|
544
|
-
const
|
|
545
|
-
|
|
861
|
+
const credential = resolveKiroCredential(auth);
|
|
862
|
+
const credentialId = kiroCredentialId(credential);
|
|
863
|
+
const cacheIsFresh = cachedKiroCredentialId === credentialId &&
|
|
864
|
+
cachedKiroModels !== null &&
|
|
865
|
+
Date.now() - lastKiroModelFetch < MODEL_CACHE_TTL_MS;
|
|
866
|
+
if (cacheIsFresh)
|
|
546
867
|
return cachedKiroModels;
|
|
547
|
-
}
|
|
548
868
|
try {
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
const variants = withKiroVariants(infos.map((info) => info.modelId));
|
|
559
|
-
cachedKiroModels = variants;
|
|
560
|
-
lastKiroModelFetch = now;
|
|
561
|
-
return variants;
|
|
869
|
+
const refreshedId = await withKiroCredential(auth, async (current) => {
|
|
870
|
+
await ensureKiroModelCatalog(current);
|
|
871
|
+
return kiroCredentialId(current);
|
|
872
|
+
});
|
|
873
|
+
if ((cachedKiroCredentialId === credentialId ||
|
|
874
|
+
cachedKiroCredentialId === refreshedId) &&
|
|
875
|
+
cachedKiroModels) {
|
|
876
|
+
return cachedKiroModels;
|
|
562
877
|
}
|
|
563
878
|
}
|
|
564
879
|
catch { }
|
|
565
|
-
return
|
|
880
|
+
return [...kiroFallbackModels];
|
|
566
881
|
},
|
|
567
882
|
async ping(auth) {
|
|
568
883
|
const credential = resolveKiroCredential(auth);
|
|
569
|
-
|
|
570
|
-
|
|
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
|
-
}
|
|
884
|
+
try {
|
|
885
|
+
await discoverKiroModelsDetailed(credential);
|
|
586
886
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
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);
|
|
887
|
+
catch (error) {
|
|
888
|
+
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
889
|
+
throw new ProviderError(`Kiro AI ping failed${detail}. Run \`clai auth kiro\` to sign in.`);
|
|
594
890
|
}
|
|
595
891
|
},
|
|
596
892
|
async complete(request, auth, onStatus) {
|
|
@@ -600,13 +896,17 @@ export const kiroProvider = {
|
|
|
600
896
|
const requestedModel = request.model ?? defaultModels.kiro;
|
|
601
897
|
const { upstream, agentic, thinking } = resolveKiroModel(requestedModel);
|
|
602
898
|
return withKiroCredential(auth, async (credential) => {
|
|
899
|
+
await ensureKiroModelCatalog(credential).catch(() => { });
|
|
603
900
|
const body = buildKiroRequestBody(request, credential, upstream, agentic, thinking);
|
|
604
|
-
const
|
|
901
|
+
const catalogIsFresh = hasFreshKiroCatalog(kiroCredentialId(credential));
|
|
902
|
+
const endpoints = getCandidateEndpoints(credential, catalogIsFresh ? cachedKiroApiGeneration : undefined);
|
|
605
903
|
let lastError;
|
|
606
904
|
for (const endpoint of endpoints) {
|
|
607
905
|
try {
|
|
608
906
|
const headers = {
|
|
609
|
-
"Content-Type":
|
|
907
|
+
"Content-Type": endpoint.awsTarget
|
|
908
|
+
? "application/x-amz-json-1.0"
|
|
909
|
+
: "application/json",
|
|
610
910
|
Accept: "application/vnd.amazon.eventstream",
|
|
611
911
|
"Amz-Sdk-Request": "attempt=1; max=3",
|
|
612
912
|
"Amz-Sdk-Invocation-Id": randomUUID(),
|
|
@@ -616,7 +916,7 @@ export const kiroProvider = {
|
|
|
616
916
|
"x-amzn-codewhisperer-optout": "true",
|
|
617
917
|
"x-amzn-codewhisperer-machine-id": "kiro-desktop",
|
|
618
918
|
};
|
|
619
|
-
if (endpoint.
|
|
919
|
+
if (endpoint.awsTarget) {
|
|
620
920
|
headers["X-Amz-Target"] =
|
|
621
921
|
"AmazonCodeWhispererStreamingService.GenerateAssistantResponse";
|
|
622
922
|
}
|
|
@@ -634,7 +934,7 @@ export const kiroProvider = {
|
|
|
634
934
|
headers["x-amzn-codewhisperer-profile-arn"] = credential.profileArn;
|
|
635
935
|
}
|
|
636
936
|
}
|
|
637
|
-
const response = await generationFetch(endpoint, {
|
|
937
|
+
const response = await generationFetch(endpoint.url, {
|
|
638
938
|
method: "POST",
|
|
639
939
|
headers,
|
|
640
940
|
body: JSON.stringify(body),
|
|
@@ -643,7 +943,12 @@ export const kiroProvider = {
|
|
|
643
943
|
if (!response.ok) {
|
|
644
944
|
const errorText = await response.text().catch(() => "");
|
|
645
945
|
if (response.status === 401 || response.status === 403) {
|
|
646
|
-
|
|
946
|
+
const authError = new ProviderError(`Kiro authentication failed (${response.status}): ${errorText}`, response.status);
|
|
947
|
+
if (response.status === 401 && credential.refreshToken) {
|
|
948
|
+
throw authError;
|
|
949
|
+
}
|
|
950
|
+
lastError = authError;
|
|
951
|
+
continue;
|
|
647
952
|
}
|
|
648
953
|
if (response.status === 400) {
|
|
649
954
|
throw new ProviderError(`Kiro request invalid (${response.status}): ${errorText}`, response.status, errorText);
|
|
@@ -655,9 +960,11 @@ export const kiroProvider = {
|
|
|
655
960
|
throw new ProviderError("Empty response body from Kiro endpoint", 500);
|
|
656
961
|
}
|
|
657
962
|
let fullText = "";
|
|
658
|
-
|
|
963
|
+
const pendingStreamEvents = [];
|
|
964
|
+
const reasoning = createKiroReasoningAccumulator((text) => pendingStreamEvents.push({ kind: "reasoning", text }));
|
|
659
965
|
let insideThinkingTag = false;
|
|
660
966
|
let finishReason = "stop";
|
|
967
|
+
let stopReason = "";
|
|
661
968
|
const accumulatedTools = [];
|
|
662
969
|
let currentToolIndex = -1;
|
|
663
970
|
let promptTokens = 0;
|
|
@@ -667,13 +974,35 @@ export const kiroProvider = {
|
|
|
667
974
|
const usageCharges = [];
|
|
668
975
|
let contextUsagePercentage;
|
|
669
976
|
for await (const frame of parseEventStream(response.body)) {
|
|
977
|
+
const messageType = typeof frame.headers[":message-type"] === "string"
|
|
978
|
+
? frame.headers[":message-type"]
|
|
979
|
+
: "event";
|
|
980
|
+
const headerExceptionType = typeof frame.headers[":exception-type"] === "string"
|
|
981
|
+
? frame.headers[":exception-type"]
|
|
982
|
+
: "";
|
|
670
983
|
const eventType = (typeof frame.headers[":event-type"] === "string"
|
|
671
984
|
? frame.headers[":event-type"]
|
|
672
985
|
: undefined) ||
|
|
673
|
-
|
|
986
|
+
headerExceptionType ||
|
|
987
|
+
Object.keys(frame.payload).find((key) => key.endsWith("Event") || key.endsWith("Exception")) ||
|
|
674
988
|
"";
|
|
675
|
-
const
|
|
676
|
-
|
|
989
|
+
const nestedPayload = asKiroRecord(frame.payload[eventType]);
|
|
990
|
+
const eventPayload = nestedPayload ?? frame.payload;
|
|
991
|
+
if (messageType === "exception" || headerExceptionType || eventType.endsWith("Exception")) {
|
|
992
|
+
const message = typeof eventPayload.message === "string"
|
|
993
|
+
? eventPayload.message
|
|
994
|
+
: typeof eventPayload.reason === "string"
|
|
995
|
+
? eventPayload.reason
|
|
996
|
+
: "Kiro stream exception";
|
|
997
|
+
throw new ProviderError(`${headerExceptionType || eventType || "Kiro stream exception"}: ${message}`, inBandBadRequestStatus({
|
|
998
|
+
type: headerExceptionType || eventType,
|
|
999
|
+
code: eventPayload.code,
|
|
1000
|
+
message,
|
|
1001
|
+
}) ??
|
|
1002
|
+
(/THINKING_SIGNATURE_INVALID|THINKING_SIGNATURE_MISMATCH/i.test(`${headerExceptionType} ${eventType} ${message}`)
|
|
1003
|
+
? 400
|
|
1004
|
+
: 502), JSON.stringify(eventPayload));
|
|
1005
|
+
}
|
|
677
1006
|
if (typeof eventPayload.usage === "number" &&
|
|
678
1007
|
Number.isFinite(eventPayload.usage) &&
|
|
679
1008
|
eventPayload.usage >= 0 &&
|
|
@@ -728,25 +1057,41 @@ export const kiroProvider = {
|
|
|
728
1057
|
}
|
|
729
1058
|
}
|
|
730
1059
|
}
|
|
731
|
-
|
|
732
|
-
reasoningText += reasoningChunk;
|
|
733
|
-
emitStreamReasoningDelta(request.onStreamEvent, reasoningChunk);
|
|
734
|
-
}
|
|
1060
|
+
reasoning.push(reasoningChunk);
|
|
735
1061
|
if (visibleChunk) {
|
|
736
1062
|
fullText += visibleChunk;
|
|
737
|
-
|
|
1063
|
+
pendingStreamEvents.push({ kind: "token", text: visibleChunk });
|
|
738
1064
|
}
|
|
739
1065
|
}
|
|
740
1066
|
}
|
|
741
1067
|
else if (eventType === "reasoningContentEvent" ||
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
1068
|
+
/reasoning/i.test(eventType) ||
|
|
1069
|
+
eventPayload.reasoningText !== undefined) {
|
|
1070
|
+
const reasoningPayload = asKiroRecord(eventPayload.reasoningText);
|
|
1071
|
+
const chunk = typeof eventPayload.text === "string"
|
|
1072
|
+
? eventPayload.text
|
|
1073
|
+
: typeof eventPayload.content === "string"
|
|
1074
|
+
? eventPayload.content
|
|
1075
|
+
: typeof eventPayload.reasoningText === "string"
|
|
1076
|
+
? eventPayload.reasoningText
|
|
1077
|
+
: typeof reasoningPayload?.text === "string"
|
|
1078
|
+
? reasoningPayload.text
|
|
1079
|
+
: typeof reasoningPayload?.Text === "string"
|
|
1080
|
+
? reasoningPayload.Text
|
|
1081
|
+
: "";
|
|
1082
|
+
reasoning.sign(typeof eventPayload.signature === "string"
|
|
1083
|
+
? eventPayload.signature
|
|
1084
|
+
: typeof eventPayload.Signature === "string"
|
|
1085
|
+
? eventPayload.Signature
|
|
1086
|
+
: typeof reasoningPayload?.signature === "string"
|
|
1087
|
+
? reasoningPayload.signature
|
|
1088
|
+
: typeof reasoningPayload?.Signature === "string"
|
|
1089
|
+
? reasoningPayload.Signature
|
|
1090
|
+
: "");
|
|
1091
|
+
reasoning.redact(typeof eventPayload.redactedContent === "string"
|
|
1092
|
+
? eventPayload.redactedContent
|
|
1093
|
+
: "");
|
|
1094
|
+
reasoning.push(chunk);
|
|
750
1095
|
}
|
|
751
1096
|
else if (eventType === "codeEvent") {
|
|
752
1097
|
const chunk = typeof eventPayload.content === "string"
|
|
@@ -754,54 +1099,67 @@ export const kiroProvider = {
|
|
|
754
1099
|
: "";
|
|
755
1100
|
if (chunk) {
|
|
756
1101
|
fullText += chunk;
|
|
757
|
-
|
|
1102
|
+
pendingStreamEvents.push({ kind: "token", text: chunk });
|
|
758
1103
|
}
|
|
759
1104
|
}
|
|
760
1105
|
else if (eventType === "toolUseEvent") {
|
|
761
|
-
const
|
|
1106
|
+
const explicitToolId = typeof eventPayload.toolUseId === "string"
|
|
762
1107
|
? eventPayload.toolUseId
|
|
763
|
-
:
|
|
1108
|
+
: typeof eventPayload.tool_use_id === "string"
|
|
1109
|
+
? eventPayload.tool_use_id
|
|
1110
|
+
: undefined;
|
|
764
1111
|
const name = typeof eventPayload.name === "string" ? eventPayload.name : "";
|
|
765
1112
|
const input = eventPayload.input;
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1113
|
+
const stopped = eventPayload.stop === true;
|
|
1114
|
+
let existing = explicitToolId
|
|
1115
|
+
? accumulatedTools.find((tool) => tool.id === explicitToolId)
|
|
1116
|
+
: accumulatedTools[currentToolIndex];
|
|
1117
|
+
if (explicitToolId &&
|
|
1118
|
+
!existing &&
|
|
1119
|
+
currentToolIndex >= 0 &&
|
|
1120
|
+
accumulatedTools[currentToolIndex]?.syntheticId) {
|
|
1121
|
+
const activeTool = accumulatedTools[currentToolIndex];
|
|
1122
|
+
activeTool.id = explicitToolId;
|
|
1123
|
+
activeTool.syntheticId = false;
|
|
1124
|
+
existing = activeTool;
|
|
1125
|
+
}
|
|
1126
|
+
if (!existing && (explicitToolId || name || input !== undefined)) {
|
|
1127
|
+
existing = {
|
|
1128
|
+
id: explicitToolId ?? `tool_${accumulatedTools.length + 1}`,
|
|
1129
|
+
name,
|
|
1130
|
+
rawArgs: "",
|
|
1131
|
+
syntheticId: explicitToolId === undefined,
|
|
1132
|
+
};
|
|
769
1133
|
accumulatedTools.push(existing);
|
|
770
|
-
currentToolIndex = accumulatedTools.length - 1;
|
|
771
1134
|
}
|
|
772
|
-
|
|
1135
|
+
if (!existing) {
|
|
1136
|
+
if (stopped)
|
|
1137
|
+
currentToolIndex = -1;
|
|
1138
|
+
continue;
|
|
1139
|
+
}
|
|
773
1140
|
if (typeof input === "string") {
|
|
774
1141
|
existing.rawArgs += input;
|
|
775
|
-
chunkBytes = Buffer.byteLength(input, "utf8");
|
|
776
1142
|
}
|
|
777
1143
|
else if (input && typeof input === "object") {
|
|
778
1144
|
existing.rawArgs = JSON.stringify(input);
|
|
779
|
-
chunkBytes = Buffer.byteLength(existing.rawArgs, "utf8");
|
|
780
1145
|
}
|
|
781
|
-
if (name && !existing.name)
|
|
1146
|
+
if (name && !existing.name)
|
|
782
1147
|
existing.name = name;
|
|
783
|
-
|
|
1148
|
+
currentToolIndex = accumulatedTools.indexOf(existing);
|
|
1149
|
+
const argumentsBytes = Buffer.byteLength(existing.rawArgs, "utf8");
|
|
784
1150
|
const delta = {
|
|
785
1151
|
index: currentToolIndex,
|
|
786
1152
|
id: existing.id,
|
|
787
1153
|
name: existing.name,
|
|
788
|
-
argumentsBytes
|
|
1154
|
+
argumentsBytes,
|
|
789
1155
|
};
|
|
790
|
-
|
|
1156
|
+
pendingStreamEvents.push({ kind: "tool", delta });
|
|
791
1157
|
finishReason = "tool_calls";
|
|
1158
|
+
if (stopped)
|
|
1159
|
+
currentToolIndex = -1;
|
|
792
1160
|
}
|
|
793
1161
|
else if (eventType === "messageStopEvent") {
|
|
794
|
-
|
|
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
|
-
}
|
|
1162
|
+
stopReason = mergeKiroStopReason(stopReason, normalizeKiroStopReason(eventPayload.stopReason ?? eventPayload.stop_reason));
|
|
805
1163
|
}
|
|
806
1164
|
else if (eventType === "contextUsageEvent") {
|
|
807
1165
|
if (typeof eventPayload.contextUsagePercentage === "number") {
|
|
@@ -809,21 +1167,56 @@ export const kiroProvider = {
|
|
|
809
1167
|
}
|
|
810
1168
|
}
|
|
811
1169
|
else if (eventType === "metricsEvent" ||
|
|
812
|
-
eventType === "meteringEvent"
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1170
|
+
eventType === "meteringEvent" ||
|
|
1171
|
+
eventType === "metadataEvent" ||
|
|
1172
|
+
eventType === "MetadataEvent") {
|
|
1173
|
+
const usagePayload = asKiroRecord(eventPayload.usage);
|
|
1174
|
+
const tokenUsagePayload = asKiroRecord(eventPayload.tokenUsage);
|
|
1175
|
+
const usageSources = [
|
|
1176
|
+
eventPayload,
|
|
1177
|
+
...(usagePayload ? [usagePayload] : []),
|
|
1178
|
+
...(tokenUsagePayload ? [tokenUsagePayload] : []),
|
|
1179
|
+
];
|
|
1180
|
+
const inputTokens = firstKiroMetric(usageSources, [
|
|
1181
|
+
"inputTokens",
|
|
1182
|
+
"input_tokens",
|
|
1183
|
+
"promptTokens",
|
|
1184
|
+
"prompt_tokens",
|
|
1185
|
+
]);
|
|
1186
|
+
const outputTokens = firstKiroMetric(usageSources, [
|
|
1187
|
+
"outputTokens",
|
|
1188
|
+
"output_tokens",
|
|
1189
|
+
"completionTokens",
|
|
1190
|
+
"completion_tokens",
|
|
1191
|
+
]);
|
|
1192
|
+
const cacheReadTokens = firstKiroMetric(usageSources, [
|
|
1193
|
+
"cacheReadTokens",
|
|
1194
|
+
"cache_read_tokens",
|
|
1195
|
+
"cacheReadInputTokens",
|
|
1196
|
+
"cache_read_input_tokens",
|
|
1197
|
+
"cachedTokens",
|
|
1198
|
+
]);
|
|
1199
|
+
const cacheWriteTokens = firstKiroMetric(usageSources, [
|
|
1200
|
+
"cacheCreationTokens",
|
|
1201
|
+
"cache_creation_tokens",
|
|
1202
|
+
"cacheWriteTokens",
|
|
1203
|
+
"cache_write_tokens",
|
|
1204
|
+
"cacheWriteInputTokens",
|
|
1205
|
+
"cacheCreationInputTokens",
|
|
1206
|
+
"cache_creation_input_tokens",
|
|
1207
|
+
]);
|
|
1208
|
+
if (inputTokens !== undefined)
|
|
1209
|
+
promptTokens = inputTokens;
|
|
1210
|
+
if (outputTokens !== undefined)
|
|
1211
|
+
completionTokens = outputTokens;
|
|
1212
|
+
if (cacheReadTokens !== undefined) {
|
|
1213
|
+
cachedTokens = Math.max(cachedTokens, cacheReadTokens);
|
|
818
1214
|
}
|
|
819
|
-
if (
|
|
820
|
-
|
|
1215
|
+
if (cacheWriteTokens !== undefined) {
|
|
1216
|
+
cacheCreationTokens = Math.max(cacheCreationTokens, cacheWriteTokens);
|
|
821
1217
|
}
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
if (typeof eventPayload.cacheWriteInputTokens === "number") {
|
|
826
|
-
cacheCreationTokens = eventPayload.cacheWriteInputTokens;
|
|
1218
|
+
if (/^metadataevent$/i.test(eventType)) {
|
|
1219
|
+
stopReason = mergeKiroStopReason(stopReason, normalizeKiroStopReason(eventPayload.stopReason ?? eventPayload.stop_reason));
|
|
827
1220
|
}
|
|
828
1221
|
}
|
|
829
1222
|
}
|
|
@@ -842,11 +1235,49 @@ export const kiroProvider = {
|
|
|
842
1235
|
rawArguments: t.rawArgs,
|
|
843
1236
|
};
|
|
844
1237
|
});
|
|
845
|
-
|
|
1238
|
+
reasoning.finish();
|
|
1239
|
+
const hasReasoningEvidence = Boolean(reasoning.text.trim() || reasoning.signature || reasoning.redactedContent);
|
|
1240
|
+
const stopDisposition = kiroStopDisposition(stopReason, toolCalls.length > 0);
|
|
1241
|
+
if (stopDisposition === "blocked") {
|
|
1242
|
+
throw new ProviderError(`Kiro blocked the response under its content safety policy (${stopReason})`, 400);
|
|
1243
|
+
}
|
|
1244
|
+
if (stopDisposition === "retryable" ||
|
|
1245
|
+
stopDisposition === "incomplete" ||
|
|
1246
|
+
stopDisposition === "unknown") {
|
|
1247
|
+
throw new ProviderError(`Kiro ended with non-success stop reason: ${stopReason}`, 502);
|
|
1248
|
+
}
|
|
1249
|
+
if (!fullText.trim() &&
|
|
1250
|
+
!hasReasoningEvidence &&
|
|
1251
|
+
toolCalls.length === 0) {
|
|
1252
|
+
throw new ProviderError("Kiro completed without a visible answer.");
|
|
1253
|
+
}
|
|
1254
|
+
if (toolCalls.length === 0 && ["...", "…"].includes(fullText.trim())) {
|
|
1255
|
+
throw new ProviderError("Kiro completed without a visible answer.");
|
|
1256
|
+
}
|
|
1257
|
+
if (reasoning.opaque && (fullText.trim() || toolCalls.length > 0)) {
|
|
1258
|
+
pendingStreamEvents.push({
|
|
1259
|
+
kind: "reasoning",
|
|
1260
|
+
text: kiroPrivateReasoningNote({
|
|
1261
|
+
model: upstream,
|
|
1262
|
+
effort: sentKiroReasoningEffort(asKiroRecord(body.additionalModelRequestFields)),
|
|
1263
|
+
signatureChars: reasoning.signature.length,
|
|
1264
|
+
}),
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
if (stopDisposition === "length") {
|
|
1268
|
+
finishReason = "length";
|
|
1269
|
+
}
|
|
1270
|
+
else if (toolCalls.length > 0) {
|
|
846
1271
|
finishReason = "tool_calls";
|
|
847
1272
|
}
|
|
848
|
-
const
|
|
849
|
-
?.maxInputTokens
|
|
1273
|
+
const advertisedWindow = kiroModelCatalog().find((info) => info.modelId === upstream)
|
|
1274
|
+
?.maxInputTokens;
|
|
1275
|
+
const catalogWindow = advertisedWindow !== undefined &&
|
|
1276
|
+
Number.isFinite(advertisedWindow) &&
|
|
1277
|
+
advertisedWindow > 0
|
|
1278
|
+
? Math.floor(advertisedWindow)
|
|
1279
|
+
: undefined;
|
|
1280
|
+
const estimatedPromptTokens = providerRatioPromptTokens(contextUsagePercentage, catalogWindow ?? modelContextWindow(upstream, "kiro"));
|
|
850
1281
|
const tokenUsage = promptTokens > 0 || completionTokens > 0
|
|
851
1282
|
? {
|
|
852
1283
|
promptTokens,
|
|
@@ -859,14 +1290,19 @@ export const kiroProvider = {
|
|
|
859
1290
|
? Math.max(0, promptTokens - cachedTokens)
|
|
860
1291
|
: promptTokens,
|
|
861
1292
|
}
|
|
862
|
-
:
|
|
863
|
-
? {
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1293
|
+
: catalogWindow !== undefined
|
|
1294
|
+
? providerRatioUsage({
|
|
1295
|
+
percentUsed: contextUsagePercentage,
|
|
1296
|
+
windowTokens: catalogWindow,
|
|
1297
|
+
})
|
|
1298
|
+
: estimatedPromptTokens !== undefined
|
|
1299
|
+
? {
|
|
1300
|
+
promptTokens: estimatedPromptTokens,
|
|
1301
|
+
completionTokens: 0,
|
|
1302
|
+
totalTokens: estimatedPromptTokens,
|
|
1303
|
+
exact: false,
|
|
1304
|
+
}
|
|
1305
|
+
: undefined;
|
|
870
1306
|
const usage = tokenUsage
|
|
871
1307
|
? {
|
|
872
1308
|
...tokenUsage,
|
|
@@ -882,6 +1318,26 @@ export const kiroProvider = {
|
|
|
882
1318
|
charges: usageCharges,
|
|
883
1319
|
}
|
|
884
1320
|
: undefined;
|
|
1321
|
+
const reasoningResult = kiroReasoningResult({
|
|
1322
|
+
reasoning,
|
|
1323
|
+
provenance: createReasoningArtifactProvenance({
|
|
1324
|
+
provider: "kiro",
|
|
1325
|
+
model: upstream,
|
|
1326
|
+
dialect: "kiro-eventstream",
|
|
1327
|
+
}),
|
|
1328
|
+
hasToolCalls: toolCalls.length > 0,
|
|
1329
|
+
});
|
|
1330
|
+
for (const event of pendingStreamEvents) {
|
|
1331
|
+
if (event.kind === "token") {
|
|
1332
|
+
onToken(event.text);
|
|
1333
|
+
}
|
|
1334
|
+
else if (event.kind === "reasoning") {
|
|
1335
|
+
emitStreamReasoningDelta(request.onStreamEvent, event.text);
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
request.onToolCallDelta?.(event.delta);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
885
1341
|
return {
|
|
886
1342
|
text: fullText,
|
|
887
1343
|
provider: "kiro",
|
|
@@ -890,13 +1346,23 @@ export const kiroProvider = {
|
|
|
890
1346
|
finishReason,
|
|
891
1347
|
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
892
1348
|
usage,
|
|
893
|
-
|
|
894
|
-
?
|
|
1349
|
+
reasoningArtifacts: reasoningResult.artifacts.length > 0
|
|
1350
|
+
? reasoningResult.artifacts
|
|
895
1351
|
: undefined,
|
|
1352
|
+
reasoningBlock: reasoningResult.block,
|
|
896
1353
|
};
|
|
897
1354
|
}
|
|
898
1355
|
catch (err) {
|
|
899
|
-
if (
|
|
1356
|
+
if (request.signal?.aborted) {
|
|
1357
|
+
completeGenerationAttempt("cancelled");
|
|
1358
|
+
throw err;
|
|
1359
|
+
}
|
|
1360
|
+
const status = err instanceof ProviderError ? err.status : undefined;
|
|
1361
|
+
completeGenerationAttempt("failure", undefined, status);
|
|
1362
|
+
if (err instanceof ProviderError &&
|
|
1363
|
+
(status === 400 ||
|
|
1364
|
+
status === undefined ||
|
|
1365
|
+
(status === 401 && Boolean(credential.refreshToken)))) {
|
|
900
1366
|
throw err;
|
|
901
1367
|
}
|
|
902
1368
|
lastError = err instanceof Error ? err : new Error(String(err));
|