From ed4bc730805501b34d248ff0ab300d72b346fcd8 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 28 Apr 2026 11:23:31 +0200 Subject: [PATCH 01/97] fix(ai): normalize Bedrock model names for profiles --- packages/ai/src/providers/amazon-bedrock.ts | 33 ++++++++++----------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/ai/src/providers/amazon-bedrock.ts b/packages/ai/src/providers/amazon-bedrock.ts index ae0593c6..f23dd5d0 100644 --- a/packages/ai/src/providers/amazon-bedrock.ts +++ b/packages/ai/src/providers/amazon-bedrock.ts @@ -481,17 +481,17 @@ function handleContentBlockStop( * Checks both model ID and model name to support application inference profiles * whose ARNs don't contain the model name. */ +function getModelMatchCandidates(modelId: string, modelName?: string): string[] { + const values = modelName ? [modelId, modelName] : [modelId]; + return values.flatMap((value) => { + const lower = value.toLowerCase(); + return [lower, lower.replace(/[\s_.:]+/g, "-")]; + }); +} + function supportsAdaptiveThinking(modelId: string, modelName?: string): boolean { - const candidates = modelName ? [modelId, modelName] : [modelId]; - return candidates.some( - (s) => - s.includes("opus-4-6") || - s.includes("opus-4.6") || - s.includes("opus-4-7") || - s.includes("opus-4.7") || - s.includes("sonnet-4-6") || - s.includes("sonnet-4.6"), - ); + const candidates = getModelMatchCandidates(modelId, modelName); + return candidates.some((s) => s.includes("opus-4-6") || s.includes("opus-4-7") || s.includes("sonnet-4-6")); } function mapThinkingLevelToEffort( @@ -499,7 +499,7 @@ function mapThinkingLevelToEffort( modelId: string, modelName?: string, ): "low" | "medium" | "high" | "xhigh" | "max" { - const candidates = modelName ? [modelId, modelName] : [modelId]; + const candidates = getModelMatchCandidates(modelId, modelName); switch (level) { case "minimal": case "low": @@ -509,10 +509,10 @@ function mapThinkingLevelToEffort( case "high": return "high"; case "xhigh": - if (candidates.some((s) => s.includes("opus-4-6") || s.includes("opus-4.6"))) { + if (candidates.some((s) => s.includes("opus-4-6"))) { return "max"; } - if (candidates.some((s) => s.includes("opus-4-7") || s.includes("opus-4.7"))) { + if (candidates.some((s) => s.includes("opus-4-7"))) { return "xhigh"; } return "high"; @@ -565,10 +565,7 @@ function isAnthropicClaudeModel(model: Model<"bedrock-converse-stream">): boolea * Amazon Nova models have automatic caching and don't need explicit cache points. */ function supportsPromptCaching(model: Model<"bedrock-converse-stream">): boolean { - const candidates = [model.id.toLowerCase()]; - if (model.name) { - candidates.push(model.name.toLowerCase()); - } + const candidates = getModelMatchCandidates(model.id, model.name); const hasClaudeRef = candidates.some((s) => s.includes("claude")); if (!hasClaudeRef) { @@ -578,7 +575,7 @@ function supportsPromptCaching(model: Model<"bedrock-converse-stream">): boolean return false; } // Claude 4.x models (opus-4, sonnet-4, haiku-4) - if (candidates.some((s) => s.includes("-4-") || s.includes("-4."))) return true; + if (candidates.some((s) => s.includes("-4-"))) return true; // Claude 3.7 Sonnet if (candidates.some((s) => s.includes("claude-3-7-sonnet"))) return true; // Claude 3.5 Haiku From 57787b6557b9129189e0fe03bf47f9779938ed63 Mon Sep 17 00:00:00 2001 From: Justin Barnett Date: Tue, 28 Apr 2026 05:46:42 -0400 Subject: [PATCH 02/97] fix(coding-agent): escape exported session metadata (#3883) --- .../src/core/export-html/template.js | 30 +++++++++---------- .../coding-agent/test/export-html-xss.test.ts | 28 +++++++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/packages/coding-agent/src/core/export-html/template.js b/packages/coding-agent/src/core/export-html/template.js index 27dff747..844f1eb3 100644 --- a/packages/coding-agent/src/core/export-html/template.js +++ b/packages/coding-agent/src/core/export-html/template.js @@ -634,13 +634,13 @@ if (toolCall) { return labelHtml + `${escapeHtml(formatToolCall(toolCall.name, toolCall.arguments))}`; } - return labelHtml + `[${msg.toolName || 'tool'}]`; + return labelHtml + `[${escapeHtml(msg.toolName || 'tool')}]`; } if (msg.role === 'bashExecution') { const cmd = truncate(normalize(msg.command || '')); return labelHtml + `[bash]: ${escapeHtml(cmd)}`; } - return labelHtml + `[${msg.role}]`; + return labelHtml + `[${escapeHtml(msg.role)}]`; } case 'compaction': return labelHtml + `[compaction: ${Math.round(entry.tokensBefore/1000)}k tokens]`; @@ -653,11 +653,11 @@ return labelHtml + `[${escapeHtml(entry.customType)}]: ${escapeHtml(truncate(normalize(content)))}`; } case 'model_change': - return labelHtml + `[model: ${entry.modelId}]`; + return labelHtml + `[model: ${escapeHtml(entry.modelId)}]`; case 'thinking_level_change': - return labelHtml + `[thinking: ${entry.thinkingLevel}]`; + return labelHtml + `[thinking: ${escapeHtml(entry.thinkingLevel)}]`; default: - return labelHtml + `[${entry.type}]`; + return labelHtml + `[${escapeHtml(entry.type)}]`; } } @@ -1122,7 +1122,7 @@ * Render the copy-link button HTML for a message. */ function renderCopyLinkButton(entryId) { - return `