@pentoshi/clai 4.11.25 → 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/README.md +91 -34
- 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 +8 -7
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/commands/catalog.js +1 -1
- package/dist/app/commands/catalog.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 +6 -6
- package/dist/app/controllers/session-controller.js +51 -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/controllers/session-usage-ledger.d.ts +7 -1
- package/dist/app/controllers/session-usage-ledger.js +76 -2
- package/dist/app/controllers/session-usage-ledger.js.map +1 -1
- package/dist/app/events/app-event.d.ts +5 -6
- 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 +65 -2
- package/dist/llm/kiro-auth.js +463 -130
- 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 +7 -1
- package/dist/llm/kiro.js +757 -228
- 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-layers/model-rules.js +22 -1
- package/dist/llm/model-layers/model-rules.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-balance.d.ts +31 -0
- package/dist/llm/provider-balance.js +118 -0
- package/dist/llm/provider-balance.js.map +1 -0
- 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/provider-info-text.js +19 -7
- package/dist/llm/provider-info-text.js.map +1 -1
- package/dist/llm/provider-profile-layers.js +1 -1
- package/dist/llm/provider-profile-layers.js.map +1 -1
- package/dist/llm/provider.d.ts +1 -0
- package/dist/llm/provider.js.map +1 -1
- 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 +2 -0
- package/dist/llm/reasoning-errors.js +16 -1
- 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/history/jsonl-backend.js +2 -1
- package/dist/store/history/jsonl-backend.js.map +1 -1
- package/dist/store/history/jsonl-lock.js +23 -3
- package/dist/store/history/jsonl-lock.js.map +1 -1
- package/dist/store/history/lifecycle.js +3 -2
- package/dist/store/history/lifecycle.js.map +1 -1
- 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 +10 -1
- package/dist/types.js.map +1 -1
- package/dist/ui-core/bootstrap/composition-root.js +9 -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/picker-commands.js +3 -0
- package/dist/ui-core/commands/picker-commands.js.map +1 -1
- package/dist/ui-core/commands/pickers/search-reasoning.d.ts +2 -0
- package/dist/ui-core/commands/pickers/search-reasoning.js +1 -1
- package/dist/ui-core/commands/pickers/search-reasoning.js.map +1 -1
- package/dist/ui-core/commands/session-commands.d.ts +4 -0
- package/dist/ui-core/commands/session-commands.js +127 -11
- 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/format-usage.js +29 -6
- package/dist/ui-core/rendering/format-usage.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,23 +1,43 @@
|
|
|
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 { nearestAcceptedEffort } from "./reasoning-controls.js";
|
|
7
|
+
import { completeGenerationAttempt, generationFetch, } from "./operation-usage.js";
|
|
8
|
+
import { learnModelVisionCapability } from "./capability/vision-registry.js";
|
|
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";
|
|
6
16
|
import { replaceProviderKey } from "../store/keys.js";
|
|
7
|
-
|
|
17
|
+
const KIRO_FALLBACK_BASE_MODELS = [
|
|
18
|
+
"auto",
|
|
8
19
|
"claude-sonnet-4.5",
|
|
9
|
-
"claude-sonnet-4
|
|
10
|
-
"claude-sonnet-4.5-agentic",
|
|
11
|
-
"claude-sonnet-4.5-thinking-agentic",
|
|
12
|
-
"claude-opus-5",
|
|
13
|
-
"claude-opus-5-thinking",
|
|
14
|
-
"claude-opus-5-agentic",
|
|
15
|
-
"claude-opus-5-thinking-agentic",
|
|
20
|
+
"claude-sonnet-4",
|
|
16
21
|
"claude-haiku-4.5",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
22
|
+
"deepseek-3.2",
|
|
23
|
+
"minimax-m2.5",
|
|
24
|
+
"minimax-m2.1",
|
|
25
|
+
"glm-5",
|
|
26
|
+
"qwen3-coder-next",
|
|
20
27
|
];
|
|
28
|
+
function withKiroVariants(baseIds) {
|
|
29
|
+
const variants = [];
|
|
30
|
+
for (const id of baseIds) {
|
|
31
|
+
variants.push(id);
|
|
32
|
+
if (id === "auto")
|
|
33
|
+
continue;
|
|
34
|
+
variants.push(`${id}-thinking`);
|
|
35
|
+
variants.push(`${id}-agentic`);
|
|
36
|
+
variants.push(`${id}-thinking-agentic`);
|
|
37
|
+
}
|
|
38
|
+
return variants;
|
|
39
|
+
}
|
|
40
|
+
export const kiroFallbackModels = withKiroVariants(KIRO_FALLBACK_BASE_MODELS);
|
|
21
41
|
const CRC32_TABLE = new Uint32Array(256);
|
|
22
42
|
for (let i = 0; i < 256; i++) {
|
|
23
43
|
let c = i;
|
|
@@ -26,6 +46,8 @@ for (let i = 0; i < 256; i++) {
|
|
|
26
46
|
}
|
|
27
47
|
CRC32_TABLE[i] = c >>> 0;
|
|
28
48
|
}
|
|
49
|
+
const KIRO_EVENTSTREAM_MAX_MESSAGE_BYTES = 24 * 1024 * 1024;
|
|
50
|
+
const KIRO_EVENTSTREAM_MAX_HEADERS_BYTES = 128 * 1024;
|
|
29
51
|
function crc32(buf, start = 0, end = buf.length) {
|
|
30
52
|
let crc = 0xffffffff;
|
|
31
53
|
for (let i = start; i < end; i++) {
|
|
@@ -35,59 +57,73 @@ function crc32(buf, start = 0, end = buf.length) {
|
|
|
35
57
|
}
|
|
36
58
|
function parseHeaders(buf) {
|
|
37
59
|
const headers = {};
|
|
60
|
+
const names = new Set();
|
|
38
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
|
+
};
|
|
39
67
|
while (offset < buf.length) {
|
|
68
|
+
requireBytes(1);
|
|
40
69
|
const nameLen = buf.readUInt8(offset);
|
|
41
70
|
offset += 1;
|
|
71
|
+
requireBytes(nameLen + 1);
|
|
42
72
|
const name = buf.toString("utf8", offset, offset + nameLen);
|
|
43
73
|
offset += nameLen;
|
|
74
|
+
if (names.has(name)) {
|
|
75
|
+
throw new ProviderError(`Duplicate Kiro event-stream header: ${name}`, 502);
|
|
76
|
+
}
|
|
77
|
+
names.add(name);
|
|
44
78
|
const type = buf.readUInt8(offset);
|
|
45
79
|
offset += 1;
|
|
46
|
-
if (type === 0) {
|
|
47
|
-
headers[name] =
|
|
80
|
+
if (type === 0 || type === 1) {
|
|
81
|
+
headers[name] = type === 0;
|
|
82
|
+
continue;
|
|
48
83
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
else if (type === 2) {
|
|
84
|
+
if (type === 2) {
|
|
85
|
+
requireBytes(1);
|
|
53
86
|
headers[name] = buf.readInt8(offset);
|
|
54
87
|
offset += 1;
|
|
88
|
+
continue;
|
|
55
89
|
}
|
|
56
|
-
|
|
90
|
+
if (type === 3) {
|
|
91
|
+
requireBytes(2);
|
|
57
92
|
headers[name] = buf.readInt16BE(offset);
|
|
58
93
|
offset += 2;
|
|
94
|
+
continue;
|
|
59
95
|
}
|
|
60
|
-
|
|
96
|
+
if (type === 4) {
|
|
97
|
+
requireBytes(4);
|
|
61
98
|
headers[name] = buf.readInt32BE(offset);
|
|
62
99
|
offset += 4;
|
|
100
|
+
continue;
|
|
63
101
|
}
|
|
64
|
-
|
|
65
|
-
|
|
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));
|
|
66
106
|
offset += 8;
|
|
107
|
+
continue;
|
|
67
108
|
}
|
|
68
|
-
|
|
109
|
+
if (type === 6 || type === 7) {
|
|
110
|
+
requireBytes(2);
|
|
69
111
|
const len = buf.readUInt16BE(offset);
|
|
70
112
|
offset += 2;
|
|
71
|
-
|
|
113
|
+
requireBytes(len);
|
|
114
|
+
headers[name] = type === 7
|
|
115
|
+
? buf.toString("utf8", offset, offset + len)
|
|
116
|
+
: buf.subarray(offset, offset + len);
|
|
72
117
|
offset += len;
|
|
118
|
+
continue;
|
|
73
119
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
offset += 2;
|
|
77
|
-
headers[name] = buf.toString("utf8", offset, offset + len);
|
|
78
|
-
offset += len;
|
|
79
|
-
}
|
|
80
|
-
else if (type === 8) {
|
|
81
|
-
headers[name] = new Date(Number(buf.readBigInt64BE(offset)));
|
|
82
|
-
offset += 8;
|
|
83
|
-
}
|
|
84
|
-
else if (type === 9) {
|
|
120
|
+
if (type === 9) {
|
|
121
|
+
requireBytes(16);
|
|
85
122
|
headers[name] = buf.subarray(offset, offset + 16).toString("hex");
|
|
86
123
|
offset += 16;
|
|
124
|
+
continue;
|
|
87
125
|
}
|
|
88
|
-
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
126
|
+
throw new ProviderError(`Unknown Kiro event-stream header type ${type}`, 502);
|
|
91
127
|
}
|
|
92
128
|
return headers;
|
|
93
129
|
}
|
|
@@ -105,15 +141,20 @@ async function* parseEventStream(stream) {
|
|
|
105
141
|
while (buffer.length >= 12) {
|
|
106
142
|
const totalLength = buffer.readUInt32BE(0);
|
|
107
143
|
if (totalLength < 16) {
|
|
108
|
-
|
|
109
|
-
|
|
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);
|
|
110
148
|
}
|
|
111
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
|
+
}
|
|
112
154
|
const preludeCrc = buffer.readUInt32BE(8);
|
|
113
155
|
const expectedPreludeCrc = crc32(buffer, 0, 8);
|
|
114
156
|
if (preludeCrc !== expectedPreludeCrc) {
|
|
115
|
-
|
|
116
|
-
continue;
|
|
157
|
+
throw new ProviderError("Kiro event-stream prelude checksum failed", 502);
|
|
117
158
|
}
|
|
118
159
|
if (buffer.length < totalLength) {
|
|
119
160
|
break;
|
|
@@ -121,8 +162,7 @@ async function* parseEventStream(stream) {
|
|
|
121
162
|
const messageCrc = buffer.readUInt32BE(totalLength - 4);
|
|
122
163
|
const expectedMessageCrc = crc32(buffer, 0, totalLength - 4);
|
|
123
164
|
if (messageCrc !== expectedMessageCrc) {
|
|
124
|
-
|
|
125
|
-
continue;
|
|
165
|
+
throw new ProviderError("Kiro event-stream message checksum failed", 502);
|
|
126
166
|
}
|
|
127
167
|
const headersBuffer = buffer.subarray(12, 12 + headersLength);
|
|
128
168
|
const payloadBuffer = buffer.subarray(12 + headersLength, totalLength - 4);
|
|
@@ -131,16 +171,27 @@ async function* parseEventStream(stream) {
|
|
|
131
171
|
let payload = {};
|
|
132
172
|
if (payloadBuffer.length > 0) {
|
|
133
173
|
try {
|
|
134
|
-
const
|
|
135
|
-
|
|
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;
|
|
136
179
|
}
|
|
137
|
-
catch {
|
|
138
|
-
|
|
180
|
+
catch (error) {
|
|
181
|
+
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
182
|
+
throw new ProviderError(`Invalid Kiro event-stream JSON payload${detail}`, 502);
|
|
139
183
|
}
|
|
140
184
|
}
|
|
141
185
|
yield { headers, payload };
|
|
142
186
|
}
|
|
143
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;
|
|
144
195
|
}
|
|
145
196
|
finally {
|
|
146
197
|
reader.releaseLock();
|
|
@@ -170,25 +221,169 @@ export function resolveKiroModel(model) {
|
|
|
170
221
|
}
|
|
171
222
|
return { upstream, agentic, thinking };
|
|
172
223
|
}
|
|
173
|
-
function
|
|
174
|
-
return /^(
|
|
175
|
-
}
|
|
176
|
-
function isAdaptiveThinkingModel(model) {
|
|
177
|
-
return /^claude/i.test(model);
|
|
224
|
+
function isLegacyThinkingDirectiveModel(model) {
|
|
225
|
+
return /^claude-(?:opus-4\.5|sonnet-4(?:\.5)?|haiku-4\.5)$/i.test(model);
|
|
178
226
|
}
|
|
179
227
|
function kiroEffortString(effort) {
|
|
180
228
|
if (!effort || effort === "none")
|
|
181
229
|
return "";
|
|
182
|
-
if (effort === "minimal"
|
|
230
|
+
if (effort === "minimal")
|
|
231
|
+
return "low";
|
|
232
|
+
if (effort === "low")
|
|
183
233
|
return "low";
|
|
184
234
|
if (effort === "medium")
|
|
185
235
|
return "medium";
|
|
186
|
-
|
|
236
|
+
if (effort === "high")
|
|
237
|
+
return "high";
|
|
238
|
+
if (effort === "xhigh")
|
|
239
|
+
return "xhigh";
|
|
240
|
+
return "max";
|
|
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>`;
|
|
187
380
|
}
|
|
188
381
|
const KIRO_THINKING_BUDGET = {
|
|
189
382
|
low: 4000,
|
|
190
383
|
medium: 8000,
|
|
191
384
|
high: 16000,
|
|
385
|
+
xhigh: 32000,
|
|
386
|
+
max: 64000,
|
|
192
387
|
};
|
|
193
388
|
function resolveKiroCredential(auth) {
|
|
194
389
|
const raw = auth.apiKey?.trim();
|
|
@@ -221,7 +416,12 @@ function resolveKiroCredential(auth) {
|
|
|
221
416
|
};
|
|
222
417
|
}
|
|
223
418
|
async function withKiroCredential(auth, run, onStatus) {
|
|
224
|
-
|
|
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
|
+
}
|
|
225
425
|
try {
|
|
226
426
|
return await run(credential);
|
|
227
427
|
}
|
|
@@ -230,27 +430,51 @@ async function withKiroCredential(auth, run, onStatus) {
|
|
|
230
430
|
if (status !== 401 && status !== 403)
|
|
231
431
|
throw error;
|
|
232
432
|
onStatus?.("ℹ Kiro authentication expired — attempting token refresh");
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
+
}
|
|
236
441
|
throw error;
|
|
237
442
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const newCredential = resolveKiroCredential({ ...auth, apiKey: refreshedKey });
|
|
443
|
+
if (!newCredential)
|
|
444
|
+
throw error;
|
|
241
445
|
onStatus?.("ℹ Kiro token refreshed — retrying request");
|
|
242
446
|
return run(newCredential);
|
|
243
447
|
}
|
|
244
448
|
}
|
|
245
|
-
function
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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];
|
|
252
474
|
}
|
|
253
|
-
return
|
|
475
|
+
return credential.authMethod === "api_key"
|
|
476
|
+
? [q, modern, codewhisperer]
|
|
477
|
+
: [codewhisperer, modern, q];
|
|
254
478
|
}
|
|
255
479
|
function uuidFromHex(hex) {
|
|
256
480
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
@@ -272,12 +496,12 @@ function sanitizeToolName(name) {
|
|
|
272
496
|
function formatKiroTools(tools) {
|
|
273
497
|
if (!tools || tools.length === 0)
|
|
274
498
|
return [];
|
|
275
|
-
return tools.map((
|
|
499
|
+
return tools.map((tool) => ({
|
|
276
500
|
toolSpecification: {
|
|
277
|
-
name: sanitizeToolName(
|
|
278
|
-
description: (
|
|
501
|
+
name: sanitizeToolName(tool.wireName || tool.name),
|
|
502
|
+
description: (tool.description || `Tool: ${tool.name}`).slice(0, 10237),
|
|
279
503
|
inputSchema: {
|
|
280
|
-
json:
|
|
504
|
+
json: tool.parameters,
|
|
281
505
|
},
|
|
282
506
|
},
|
|
283
507
|
}));
|
|
@@ -294,21 +518,34 @@ function imageFormatFromMediaType(mediaType) {
|
|
|
294
518
|
return "webp";
|
|
295
519
|
return "png";
|
|
296
520
|
}
|
|
297
|
-
function buildKiroRequestBody(request, credential, upstreamModel, agentic, thinking) {
|
|
521
|
+
export function buildKiroRequestBody(request, credential, upstreamModel, agentic, thinking) {
|
|
298
522
|
const agenticInstruction = agentic
|
|
299
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."
|
|
300
524
|
: "";
|
|
301
525
|
const systemParts = [];
|
|
302
526
|
if (agenticInstruction)
|
|
303
527
|
systemParts.push(agenticInstruction);
|
|
528
|
+
let sawLeadingSystem = false;
|
|
304
529
|
const nonSystemMessages = [];
|
|
305
530
|
for (const msg of request.messages) {
|
|
306
|
-
if (msg.role
|
|
531
|
+
if (msg.role !== "system") {
|
|
532
|
+
nonSystemMessages.push(msg);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (!sawLeadingSystem) {
|
|
536
|
+
sawLeadingSystem = true;
|
|
307
537
|
if (msg.content.trim())
|
|
308
538
|
systemParts.push(msg.content.trim());
|
|
539
|
+
continue;
|
|
309
540
|
}
|
|
310
|
-
|
|
311
|
-
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
|
+
});
|
|
312
549
|
}
|
|
313
550
|
}
|
|
314
551
|
const systemPrompt = systemParts.join("\n\n").trim();
|
|
@@ -339,6 +576,40 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
339
576
|
}
|
|
340
577
|
}
|
|
341
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;
|
|
342
613
|
const toolUses = (msg.toolCalls ?? [])
|
|
343
614
|
.filter((tc) => tc.id)
|
|
344
615
|
.map((tc) => ({
|
|
@@ -353,6 +624,9 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
353
624
|
? `${last.content}\n\n${msg.content}`
|
|
354
625
|
: msg.content;
|
|
355
626
|
}
|
|
627
|
+
if (reasoningContent && !last.reasoningContent) {
|
|
628
|
+
last.reasoningContent = reasoningContent;
|
|
629
|
+
}
|
|
356
630
|
if (toolUses.length > 0) {
|
|
357
631
|
last.toolUses = [...(last.toolUses ?? []), ...toolUses];
|
|
358
632
|
}
|
|
@@ -361,6 +635,7 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
361
635
|
turns.push({
|
|
362
636
|
role: "assistant",
|
|
363
637
|
content: msg.content || "",
|
|
638
|
+
reasoningContent,
|
|
364
639
|
toolUses: toolUses.length > 0 ? toolUses : undefined,
|
|
365
640
|
});
|
|
366
641
|
}
|
|
@@ -403,7 +678,24 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
403
678
|
: "continue";
|
|
404
679
|
}
|
|
405
680
|
}
|
|
681
|
+
const modelInfo = kiroModelCatalog().find((info) => info.modelId === upstreamModel);
|
|
406
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
|
+
}
|
|
407
699
|
const history = [];
|
|
408
700
|
for (let i = 0; i < turns.length - 1; i++) {
|
|
409
701
|
const turn = turns[i];
|
|
@@ -428,6 +720,9 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
428
720
|
history.push({
|
|
429
721
|
assistantResponseMessage: {
|
|
430
722
|
content: turn.content,
|
|
723
|
+
...(turn.reasoningContent
|
|
724
|
+
? { reasoningContent: turn.reasoningContent }
|
|
725
|
+
: {}),
|
|
431
726
|
...(turn.toolUses && turn.toolUses.length > 0
|
|
432
727
|
? { toolUses: turn.toolUses }
|
|
433
728
|
: {}),
|
|
@@ -467,33 +762,89 @@ function buildKiroRequestBody(request, credential, upstreamModel, agentic, think
|
|
|
467
762
|
if (credential.profileArn) {
|
|
468
763
|
payload.profileArn = credential.profileArn;
|
|
469
764
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if (wantsThinking && isNativeReasoningModel(upstreamModel)) {
|
|
473
|
-
payload.additionalModelRequestFields = { reasoning: { effort } };
|
|
474
|
-
}
|
|
475
|
-
else if (wantsThinking && isAdaptiveThinkingModel(upstreamModel)) {
|
|
476
|
-
const budget = KIRO_THINKING_BUDGET[effort] ?? 16000;
|
|
477
|
-
const directive = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>`;
|
|
478
|
-
const uim = payload.conversationState
|
|
479
|
-
.currentMessage;
|
|
480
|
-
const msg = uim.userInputMessage;
|
|
481
|
-
msg.content = `${directive}\n\n${String(msg.content ?? "")}`;
|
|
482
|
-
payload.additionalModelRequestFields = {
|
|
483
|
-
output_config: { effort },
|
|
484
|
-
thinking: { type: "adaptive", display: "summarized" },
|
|
485
|
-
};
|
|
765
|
+
if (additionalFields) {
|
|
766
|
+
payload.additionalModelRequestFields = additionalFields;
|
|
486
767
|
}
|
|
487
768
|
return payload;
|
|
488
769
|
}
|
|
489
770
|
let cachedKiroModels = null;
|
|
771
|
+
let cachedKiroModelInfo = [];
|
|
772
|
+
let cachedKiroApiGeneration;
|
|
773
|
+
let cachedKiroCredentialId = "";
|
|
490
774
|
let lastKiroModelFetch = 0;
|
|
491
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
|
+
}
|
|
819
|
+
export function kiroModelCatalog() {
|
|
820
|
+
return cachedKiroModelInfo;
|
|
821
|
+
}
|
|
822
|
+
export function resetKiroModelCacheForTesting() {
|
|
823
|
+
cachedKiroModels = null;
|
|
824
|
+
cachedKiroModelInfo = [];
|
|
825
|
+
cachedKiroApiGeneration = undefined;
|
|
826
|
+
cachedKiroCredentialId = "";
|
|
827
|
+
lastKiroModelFetch = 0;
|
|
828
|
+
}
|
|
829
|
+
export async function fetchKiroUsageLimits(auth, onStatus) {
|
|
830
|
+
return withKiroCredential(auth, getKiroUsageLimits, onStatus);
|
|
831
|
+
}
|
|
832
|
+
const KIRO_MODEL_RANK = (id) => {
|
|
833
|
+
const base = resolveKiroModel(id).upstream;
|
|
834
|
+
if (base === "auto")
|
|
835
|
+
return 0;
|
|
836
|
+
if (/^claude-/.test(base))
|
|
837
|
+
return 1;
|
|
838
|
+
return 2;
|
|
839
|
+
};
|
|
492
840
|
export const kiroProvider = {
|
|
493
841
|
id: "kiro",
|
|
494
842
|
displayName: "Kiro AI",
|
|
495
843
|
defaultModel: defaultModels.kiro,
|
|
496
844
|
envVar: "KIRO_API_KEY",
|
|
845
|
+
sortModels(models) {
|
|
846
|
+
return [...models].sort((a, b) => KIRO_MODEL_RANK(a) - KIRO_MODEL_RANK(b) || a.localeCompare(b));
|
|
847
|
+
},
|
|
497
848
|
validateKey(key) {
|
|
498
849
|
const trimmed = key.trim();
|
|
499
850
|
if (!trimmed)
|
|
@@ -507,85 +858,35 @@ export const kiroProvider = {
|
|
|
507
858
|
return trimmed.length >= 8;
|
|
508
859
|
},
|
|
509
860
|
async listModels(auth) {
|
|
510
|
-
const
|
|
511
|
-
|
|
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)
|
|
512
867
|
return cachedKiroModels;
|
|
513
|
-
}
|
|
514
868
|
try {
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const endpoint = `https://q.${region}.amazonaws.com/ListAvailableModels?${params.toString()}`;
|
|
519
|
-
const headers = {
|
|
520
|
-
Accept: "application/json",
|
|
521
|
-
"User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0",
|
|
522
|
-
"X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
|
|
523
|
-
};
|
|
524
|
-
if (credential.authMethod === "api_key" && credential.apiKey) {
|
|
525
|
-
headers["Authorization"] = `Bearer ${credential.apiKey}`;
|
|
526
|
-
headers["TokenType"] = "API_KEY";
|
|
527
|
-
}
|
|
528
|
-
else if (credential.accessToken) {
|
|
529
|
-
headers["Authorization"] = `Bearer ${credential.accessToken}`;
|
|
530
|
-
if (credential.authMethod === "external_idp") {
|
|
531
|
-
headers["TokenType"] = "EXTERNAL_IDP";
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
const response = await fetch(endpoint, {
|
|
535
|
-
method: "GET",
|
|
536
|
-
headers,
|
|
537
|
-
signal: AbortSignal.timeout(15_000),
|
|
869
|
+
const refreshedId = await withKiroCredential(auth, async (current) => {
|
|
870
|
+
await ensureKiroModelCatalog(current);
|
|
871
|
+
return kiroCredentialId(current);
|
|
538
872
|
});
|
|
539
|
-
if (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
.map((m) => m.modelId || m.id || "")
|
|
544
|
-
.filter(Boolean);
|
|
545
|
-
if (baseIds.length > 0) {
|
|
546
|
-
const variants = [];
|
|
547
|
-
for (const id of baseIds) {
|
|
548
|
-
variants.push(id);
|
|
549
|
-
variants.push(`${id}-thinking`);
|
|
550
|
-
variants.push(`${id}-agentic`);
|
|
551
|
-
variants.push(`${id}-thinking-agentic`);
|
|
552
|
-
}
|
|
553
|
-
cachedKiroModels = variants;
|
|
554
|
-
lastKiroModelFetch = now;
|
|
555
|
-
return variants;
|
|
556
|
-
}
|
|
873
|
+
if ((cachedKiroCredentialId === credentialId ||
|
|
874
|
+
cachedKiroCredentialId === refreshedId) &&
|
|
875
|
+
cachedKiroModels) {
|
|
876
|
+
return cachedKiroModels;
|
|
557
877
|
}
|
|
558
878
|
}
|
|
559
879
|
catch { }
|
|
560
|
-
return
|
|
880
|
+
return [...kiroFallbackModels];
|
|
561
881
|
},
|
|
562
882
|
async ping(auth) {
|
|
563
883
|
const credential = resolveKiroCredential(auth);
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const endpoint = `https://q.${region}.amazonaws.com/ListAvailableModels?${params.toString()}`;
|
|
567
|
-
const headers = {
|
|
568
|
-
Accept: "application/json",
|
|
569
|
-
"User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0",
|
|
570
|
-
"X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
|
|
571
|
-
};
|
|
572
|
-
if (credential.authMethod === "api_key" && credential.apiKey) {
|
|
573
|
-
headers["Authorization"] = `Bearer ${credential.apiKey}`;
|
|
574
|
-
headers["TokenType"] = "API_KEY";
|
|
575
|
-
}
|
|
576
|
-
else if (credential.accessToken) {
|
|
577
|
-
headers["Authorization"] = `Bearer ${credential.accessToken}`;
|
|
578
|
-
if (credential.authMethod === "external_idp") {
|
|
579
|
-
headers["TokenType"] = "EXTERNAL_IDP";
|
|
580
|
-
}
|
|
884
|
+
try {
|
|
885
|
+
await discoverKiroModelsDetailed(credential);
|
|
581
886
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
signal: AbortSignal.timeout(15_000),
|
|
586
|
-
});
|
|
587
|
-
if (!response.ok) {
|
|
588
|
-
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.`);
|
|
589
890
|
}
|
|
590
891
|
},
|
|
591
892
|
async complete(request, auth, onStatus) {
|
|
@@ -595,20 +896,27 @@ export const kiroProvider = {
|
|
|
595
896
|
const requestedModel = request.model ?? defaultModels.kiro;
|
|
596
897
|
const { upstream, agentic, thinking } = resolveKiroModel(requestedModel);
|
|
597
898
|
return withKiroCredential(auth, async (credential) => {
|
|
899
|
+
await ensureKiroModelCatalog(credential).catch(() => { });
|
|
598
900
|
const body = buildKiroRequestBody(request, credential, upstream, agentic, thinking);
|
|
599
|
-
const
|
|
901
|
+
const catalogIsFresh = hasFreshKiroCatalog(kiroCredentialId(credential));
|
|
902
|
+
const endpoints = getCandidateEndpoints(credential, catalogIsFresh ? cachedKiroApiGeneration : undefined);
|
|
600
903
|
let lastError;
|
|
601
904
|
for (const endpoint of endpoints) {
|
|
602
905
|
try {
|
|
603
906
|
const headers = {
|
|
604
|
-
"Content-Type":
|
|
907
|
+
"Content-Type": endpoint.awsTarget
|
|
908
|
+
? "application/x-amz-json-1.0"
|
|
909
|
+
: "application/json",
|
|
605
910
|
Accept: "application/vnd.amazon.eventstream",
|
|
606
911
|
"Amz-Sdk-Request": "attempt=1; max=3",
|
|
607
912
|
"Amz-Sdk-Invocation-Id": randomUUID(),
|
|
608
|
-
"
|
|
913
|
+
"User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
|
|
914
|
+
"X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
|
|
915
|
+
"x-amzn-kiro-agent-mode": "vibe",
|
|
916
|
+
"x-amzn-codewhisperer-optout": "true",
|
|
609
917
|
"x-amzn-codewhisperer-machine-id": "kiro-desktop",
|
|
610
918
|
};
|
|
611
|
-
if (endpoint.
|
|
919
|
+
if (endpoint.awsTarget) {
|
|
612
920
|
headers["X-Amz-Target"] =
|
|
613
921
|
"AmazonCodeWhispererStreamingService.GenerateAssistantResponse";
|
|
614
922
|
}
|
|
@@ -626,7 +934,7 @@ export const kiroProvider = {
|
|
|
626
934
|
headers["x-amzn-codewhisperer-profile-arn"] = credential.profileArn;
|
|
627
935
|
}
|
|
628
936
|
}
|
|
629
|
-
const response = await
|
|
937
|
+
const response = await generationFetch(endpoint.url, {
|
|
630
938
|
method: "POST",
|
|
631
939
|
headers,
|
|
632
940
|
body: JSON.stringify(body),
|
|
@@ -635,10 +943,15 @@ export const kiroProvider = {
|
|
|
635
943
|
if (!response.ok) {
|
|
636
944
|
const errorText = await response.text().catch(() => "");
|
|
637
945
|
if (response.status === 401 || response.status === 403) {
|
|
638
|
-
|
|
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;
|
|
639
952
|
}
|
|
640
953
|
if (response.status === 400) {
|
|
641
|
-
throw new ProviderError(`Kiro request invalid (${response.status}): ${errorText}`, response.status);
|
|
954
|
+
throw new ProviderError(`Kiro request invalid (${response.status}): ${errorText}`, response.status, errorText);
|
|
642
955
|
}
|
|
643
956
|
lastError = new ProviderError(`Kiro endpoint error (${response.status}): ${errorText}`, response.status);
|
|
644
957
|
continue;
|
|
@@ -647,30 +960,76 @@ export const kiroProvider = {
|
|
|
647
960
|
throw new ProviderError("Empty response body from Kiro endpoint", 500);
|
|
648
961
|
}
|
|
649
962
|
let fullText = "";
|
|
650
|
-
|
|
963
|
+
const pendingStreamEvents = [];
|
|
964
|
+
const reasoning = createKiroReasoningAccumulator((text) => pendingStreamEvents.push({ kind: "reasoning", text }));
|
|
651
965
|
let insideThinkingTag = false;
|
|
652
966
|
let finishReason = "stop";
|
|
967
|
+
let stopReason = "";
|
|
653
968
|
const accumulatedTools = [];
|
|
654
969
|
let currentToolIndex = -1;
|
|
655
970
|
let promptTokens = 0;
|
|
656
971
|
let completionTokens = 0;
|
|
657
972
|
let cachedTokens = 0;
|
|
658
973
|
let cacheCreationTokens = 0;
|
|
974
|
+
const usageCharges = [];
|
|
975
|
+
let contextUsagePercentage;
|
|
659
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
|
+
: "";
|
|
660
983
|
const eventType = (typeof frame.headers[":event-type"] === "string"
|
|
661
984
|
? frame.headers[":event-type"]
|
|
662
985
|
: undefined) ||
|
|
663
|
-
|
|
986
|
+
headerExceptionType ||
|
|
987
|
+
Object.keys(frame.payload).find((key) => key.endsWith("Event") || key.endsWith("Exception")) ||
|
|
664
988
|
"";
|
|
665
|
-
const
|
|
666
|
-
|
|
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
|
+
}
|
|
1006
|
+
if (typeof eventPayload.usage === "number" &&
|
|
1007
|
+
Number.isFinite(eventPayload.usage) &&
|
|
1008
|
+
eventPayload.usage >= 0 &&
|
|
1009
|
+
typeof eventPayload.unit === "string" &&
|
|
1010
|
+
eventPayload.unit.trim()) {
|
|
1011
|
+
usageCharges.push({
|
|
1012
|
+
amount: eventPayload.usage,
|
|
1013
|
+
unit: typeof eventPayload.unitPlural === "string" &&
|
|
1014
|
+
eventPayload.unitPlural.trim()
|
|
1015
|
+
? eventPayload.unitPlural.trim()
|
|
1016
|
+
: eventPayload.unit.trim(),
|
|
1017
|
+
...(typeof eventPayload.currency === "string"
|
|
1018
|
+
? { currency: eventPayload.currency }
|
|
1019
|
+
: {}),
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
667
1022
|
if (eventType === "assistantResponseEvent" ||
|
|
668
1023
|
eventType.includes("Response")) {
|
|
1024
|
+
if (typeof eventPayload.contextUsagePercentage === "number") {
|
|
1025
|
+
contextUsagePercentage = eventPayload.contextUsagePercentage;
|
|
1026
|
+
}
|
|
669
1027
|
const chunk = typeof eventPayload.content === "string"
|
|
670
1028
|
? eventPayload.content
|
|
671
1029
|
: "";
|
|
672
1030
|
if (chunk) {
|
|
673
1031
|
let visibleChunk = "";
|
|
1032
|
+
let reasoningChunk = "";
|
|
674
1033
|
let i = 0;
|
|
675
1034
|
while (i < chunk.length) {
|
|
676
1035
|
if (!insideThinkingTag) {
|
|
@@ -688,30 +1047,51 @@ export const kiroProvider = {
|
|
|
688
1047
|
else {
|
|
689
1048
|
const tagEnd = chunk.indexOf("</thinking>", i);
|
|
690
1049
|
if (tagEnd !== -1) {
|
|
691
|
-
|
|
1050
|
+
reasoningChunk += chunk.slice(i, tagEnd);
|
|
692
1051
|
insideThinkingTag = false;
|
|
693
1052
|
i = tagEnd + 11;
|
|
694
1053
|
}
|
|
695
1054
|
else {
|
|
696
|
-
|
|
1055
|
+
reasoningChunk += chunk.slice(i);
|
|
697
1056
|
break;
|
|
698
1057
|
}
|
|
699
1058
|
}
|
|
700
1059
|
}
|
|
1060
|
+
reasoning.push(reasoningChunk);
|
|
701
1061
|
if (visibleChunk) {
|
|
702
1062
|
fullText += visibleChunk;
|
|
703
|
-
|
|
1063
|
+
pendingStreamEvents.push({ kind: "token", text: visibleChunk });
|
|
704
1064
|
}
|
|
705
1065
|
}
|
|
706
1066
|
}
|
|
707
1067
|
else if (eventType === "reasoningContentEvent" ||
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
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);
|
|
715
1095
|
}
|
|
716
1096
|
else if (eventType === "codeEvent") {
|
|
717
1097
|
const chunk = typeof eventPayload.content === "string"
|
|
@@ -719,72 +1099,124 @@ export const kiroProvider = {
|
|
|
719
1099
|
: "";
|
|
720
1100
|
if (chunk) {
|
|
721
1101
|
fullText += chunk;
|
|
722
|
-
|
|
1102
|
+
pendingStreamEvents.push({ kind: "token", text: chunk });
|
|
723
1103
|
}
|
|
724
1104
|
}
|
|
725
1105
|
else if (eventType === "toolUseEvent") {
|
|
726
|
-
const
|
|
1106
|
+
const explicitToolId = typeof eventPayload.toolUseId === "string"
|
|
727
1107
|
? eventPayload.toolUseId
|
|
728
|
-
:
|
|
1108
|
+
: typeof eventPayload.tool_use_id === "string"
|
|
1109
|
+
? eventPayload.tool_use_id
|
|
1110
|
+
: undefined;
|
|
729
1111
|
const name = typeof eventPayload.name === "string" ? eventPayload.name : "";
|
|
730
1112
|
const input = eventPayload.input;
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
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
|
+
};
|
|
734
1133
|
accumulatedTools.push(existing);
|
|
735
|
-
currentToolIndex = accumulatedTools.length - 1;
|
|
736
1134
|
}
|
|
737
|
-
|
|
1135
|
+
if (!existing) {
|
|
1136
|
+
if (stopped)
|
|
1137
|
+
currentToolIndex = -1;
|
|
1138
|
+
continue;
|
|
1139
|
+
}
|
|
738
1140
|
if (typeof input === "string") {
|
|
739
1141
|
existing.rawArgs += input;
|
|
740
|
-
chunkBytes = Buffer.byteLength(input, "utf8");
|
|
741
1142
|
}
|
|
742
1143
|
else if (input && typeof input === "object") {
|
|
743
1144
|
existing.rawArgs = JSON.stringify(input);
|
|
744
|
-
chunkBytes = Buffer.byteLength(existing.rawArgs, "utf8");
|
|
745
1145
|
}
|
|
746
|
-
if (name && !existing.name)
|
|
1146
|
+
if (name && !existing.name)
|
|
747
1147
|
existing.name = name;
|
|
748
|
-
|
|
1148
|
+
currentToolIndex = accumulatedTools.indexOf(existing);
|
|
1149
|
+
const argumentsBytes = Buffer.byteLength(existing.rawArgs, "utf8");
|
|
749
1150
|
const delta = {
|
|
750
1151
|
index: currentToolIndex,
|
|
751
1152
|
id: existing.id,
|
|
752
1153
|
name: existing.name,
|
|
753
|
-
argumentsBytes
|
|
1154
|
+
argumentsBytes,
|
|
754
1155
|
};
|
|
755
|
-
|
|
1156
|
+
pendingStreamEvents.push({ kind: "tool", delta });
|
|
756
1157
|
finishReason = "tool_calls";
|
|
1158
|
+
if (stopped)
|
|
1159
|
+
currentToolIndex = -1;
|
|
757
1160
|
}
|
|
758
1161
|
else if (eventType === "messageStopEvent") {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
if (
|
|
763
|
-
|
|
764
|
-
stop === "tool_use" || stop === "tool_calls"
|
|
765
|
-
? "tool_calls"
|
|
766
|
-
: stop === "max_tokens" || stop === "length"
|
|
767
|
-
? "length"
|
|
768
|
-
: "stop";
|
|
1162
|
+
stopReason = mergeKiroStopReason(stopReason, normalizeKiroStopReason(eventPayload.stopReason ?? eventPayload.stop_reason));
|
|
1163
|
+
}
|
|
1164
|
+
else if (eventType === "contextUsageEvent") {
|
|
1165
|
+
if (typeof eventPayload.contextUsagePercentage === "number") {
|
|
1166
|
+
contextUsagePercentage = eventPayload.contextUsagePercentage;
|
|
769
1167
|
}
|
|
770
1168
|
}
|
|
771
1169
|
else if (eventType === "metricsEvent" ||
|
|
772
|
-
eventType === "
|
|
773
|
-
eventType === "
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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);
|
|
779
1214
|
}
|
|
780
|
-
if (
|
|
781
|
-
|
|
1215
|
+
if (cacheWriteTokens !== undefined) {
|
|
1216
|
+
cacheCreationTokens = Math.max(cacheCreationTokens, cacheWriteTokens);
|
|
782
1217
|
}
|
|
783
|
-
if (
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
if (typeof eventPayload.cacheWriteInputTokens === "number") {
|
|
787
|
-
cacheCreationTokens = eventPayload.cacheWriteInputTokens;
|
|
1218
|
+
if (/^metadataevent$/i.test(eventType)) {
|
|
1219
|
+
stopReason = mergeKiroStopReason(stopReason, normalizeKiroStopReason(eventPayload.stopReason ?? eventPayload.stop_reason));
|
|
788
1220
|
}
|
|
789
1221
|
}
|
|
790
1222
|
}
|
|
@@ -803,10 +1235,50 @@ export const kiroProvider = {
|
|
|
803
1235
|
rawArguments: t.rawArgs,
|
|
804
1236
|
};
|
|
805
1237
|
});
|
|
806
|
-
|
|
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) {
|
|
807
1271
|
finishReason = "tool_calls";
|
|
808
1272
|
}
|
|
809
|
-
const
|
|
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"));
|
|
1281
|
+
const tokenUsage = promptTokens > 0 || completionTokens > 0
|
|
810
1282
|
? {
|
|
811
1283
|
promptTokens,
|
|
812
1284
|
completionTokens,
|
|
@@ -818,7 +1290,54 @@ export const kiroProvider = {
|
|
|
818
1290
|
? Math.max(0, promptTokens - cachedTokens)
|
|
819
1291
|
: promptTokens,
|
|
820
1292
|
}
|
|
821
|
-
: undefined
|
|
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;
|
|
1306
|
+
const usage = tokenUsage
|
|
1307
|
+
? {
|
|
1308
|
+
...tokenUsage,
|
|
1309
|
+
...(usageCharges.length > 0 ? { charges: usageCharges } : {}),
|
|
1310
|
+
}
|
|
1311
|
+
: usageCharges.length > 0
|
|
1312
|
+
? {
|
|
1313
|
+
promptTokens: 0,
|
|
1314
|
+
promptTokensKnown: false,
|
|
1315
|
+
completionTokens: 0,
|
|
1316
|
+
totalTokens: 0,
|
|
1317
|
+
exact: false,
|
|
1318
|
+
charges: usageCharges,
|
|
1319
|
+
}
|
|
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
|
+
}
|
|
822
1341
|
return {
|
|
823
1342
|
text: fullText,
|
|
824
1343
|
provider: "kiro",
|
|
@@ -827,13 +1346,23 @@ export const kiroProvider = {
|
|
|
827
1346
|
finishReason,
|
|
828
1347
|
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
829
1348
|
usage,
|
|
830
|
-
|
|
831
|
-
?
|
|
1349
|
+
reasoningArtifacts: reasoningResult.artifacts.length > 0
|
|
1350
|
+
? reasoningResult.artifacts
|
|
832
1351
|
: undefined,
|
|
1352
|
+
reasoningBlock: reasoningResult.block,
|
|
833
1353
|
};
|
|
834
1354
|
}
|
|
835
1355
|
catch (err) {
|
|
836
|
-
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)))) {
|
|
837
1366
|
throw err;
|
|
838
1367
|
}
|
|
839
1368
|
lastError = err instanceof Error ? err : new Error(String(err));
|