fix(kiro): normalize dashboard thinking intensity models

Strip the generic dashboard model(level) suffix before resolving Kiro
synthetic -thinking/-agentic variants so the upstream request no longer
carries an invalid parenthesized model id. Map explicit levels to native
Kiro effort fields only for supported Claude/GPT model families, and stop
advertising native levels for unsupported legacy Kiro models. Applies to
both OpenAI→Kiro and direct Claude→Kiro routes.
This commit is contained in:
ankit1324
2026-07-23 16:26:22 +07:00
committed by decolua
parent e45bd73d6e
commit 007d372724
7 changed files with 103 additions and 11 deletions

View File

@@ -15,7 +15,7 @@
* fiction. The suffix is stripped before the request leaves this process.
*/
import { extractThinking } from "../translator/concerns/thinkingUnified.js";
import { extractThinking, parseSuffix } from "../translator/concerns/thinkingUnified.js";
import { effortToBudget } from "../translator/concerns/thinking.js";
export const KIRO_AGENTIC_SUFFIX = "-agentic";
@@ -40,6 +40,39 @@ export function resolveDefaultProfileArn(authMethod) {
export const KIRO_THINKING_BUDGET_DEFAULT = 16000;
/**
* Resolve a Kiro model after consuming the generic model(level) suffix.
* The suffix is a 9router request override, not part of Kiro's upstream model id.
*/
export function resolveKiroModelIntent(model) {
const { cleanModel, override } = parseSuffix(model);
return {
model: cleanModel,
...resolveKiroModel(cleanModel),
thinkingOverride: override,
};
}
/** Apply a parsed model(level) override without mutating the caller's body. */
export function applyKiroThinkingOverride(body, override) {
if (!override) return body;
const next = { ...body };
if (override.mode === "budget") {
delete next.output_config;
delete next.reasoning_effort;
delete next.reasoning;
next.thinking = { type: "enabled", budget_tokens: override.budget };
return next;
}
next.output_config = {
...(body.output_config || {}),
effort: override.mode === "level" ? override.level : override.mode,
};
return next;
}
export const KIRO_AGENTIC_SYSTEM_PROMPT = `
# CRITICAL: CHUNKED WRITE PROTOCOL (MANDATORY)

View File

@@ -2,6 +2,7 @@
// Reuses capabilities.js (thinkingFormat/canDisable) so this file only maps format→levels (DRY).
import { getCapabilitiesForModel } from "./capabilities.js";
import { matchPattern } from "./pricing.js";
import { resolveKiroEffortPath } from "../config/kiroConstants.js";
// Shared level sets (deduped) — verified against provider docs + wire in thinkingUnified.applyFormat.
const L = {
@@ -39,6 +40,7 @@ const PATTERN_THINKING = [
// Returns valid thinking levels for a model, or null when the model has no reasoning.
export function getThinkingLevels(provider, model) {
if (provider === "kiro" && resolveKiroEffortPath(model) === null) return null;
const caps = getCapabilitiesForModel(provider, model);
if (!caps.reasoning) return null;
const hit = PATTERN_THINKING.find((p) => matchPattern(p.pattern, model));

View File

@@ -27,7 +27,8 @@ import { FORMATS } from "../formats.js";
import { applyKiroSessionReplay } from "../../utils/kiroSessionReplay.js";
import { resolveContinuationId, resolveSessionIdentity } from "../../utils/sessionManager.js";
import {
resolveKiroModel,
resolveKiroModelIntent,
applyKiroThinkingOverride,
resolveKiroThinkingBudget,
buildThinkingSystemPrefix,
KIRO_AGENTIC_SYSTEM_PROMPT,
@@ -389,10 +390,12 @@ export function claudeToKiroRequest(model, body, stream, credentials) {
const temperature = body.temperature;
const topP = body.top_p;
const { upstream: upstreamModel, agentic } = resolveKiroModel(model);
const thinkingBudget = resolveKiroThinkingBudget(body, credentials?.rawHeaders, model);
const additionalModelRequestFields = buildKiroAdditionalModelRequestFieldsForModel(body, upstreamModel);
const usesNativeGptEffort = usesKiroNativeGptEffort(body, upstreamModel);
const modelIntent = resolveKiroModelIntent(model);
const { upstream: upstreamModel, agentic } = modelIntent;
const thinkingBody = applyKiroThinkingOverride(body, modelIntent.thinkingOverride);
const thinkingBudget = resolveKiroThinkingBudget(thinkingBody, credentials?.rawHeaders, modelIntent.model);
const additionalModelRequestFields = buildKiroAdditionalModelRequestFieldsForModel(thinkingBody, upstreamModel);
const usesNativeGptEffort = usesKiroNativeGptEffort(thinkingBody, upstreamModel);
// Guard 1: no client tools → flatten all tool interactions to text.
if (!clientProvidedTools) {

View File

@@ -8,7 +8,8 @@ import { v4 as uuidv4 } from "uuid";
import { applyKiroSessionReplay } from "../../utils/kiroSessionReplay.js";
import { resolveContinuationId, resolveSessionIdentity } from "../../utils/sessionManager.js";
import {
resolveKiroModel,
resolveKiroModelIntent,
applyKiroThinkingOverride,
resolveKiroThinkingBudget,
buildThinkingSystemPrefix,
KIRO_AGENTIC_SYSTEM_PROMPT,
@@ -524,10 +525,12 @@ export function openaiToKiroRequest(model, body, stream, credentials) {
const temperature = body.temperature;
const topP = body.top_p;
const { upstream: upstreamModel, agentic } = resolveKiroModel(model);
const thinkingBudget = resolveKiroThinkingBudget(body, credentials?.rawHeaders, model);
const additionalModelRequestFields = buildKiroAdditionalModelRequestFieldsForModel(body, upstreamModel);
const usesNativeGptEffort = usesKiroNativeGptEffort(body, upstreamModel);
const modelIntent = resolveKiroModelIntent(model);
const { upstream: upstreamModel, agentic } = modelIntent;
const thinkingBody = applyKiroThinkingOverride(body, modelIntent.thinkingOverride);
const thinkingBudget = resolveKiroThinkingBudget(thinkingBody, credentials?.rawHeaders, modelIntent.model);
const additionalModelRequestFields = buildKiroAdditionalModelRequestFieldsForModel(thinkingBody, upstreamModel);
const usesNativeGptEffort = usesKiroNativeGptEffort(thinkingBody, upstreamModel);
const { history, currentMessage } = convertMessages(messages, tools, upstreamModel);