An enterprise-grade AI agent built for serious development
+
Strict AI coder for enterprises
diff --git a/apps/web-roo-code/src/app/page.tsx b/apps/web-roo-code/src/app/page.tsx
index 4ef415a658..7169b4febd 100644
--- a/apps/web-roo-code/src/app/page.tsx
+++ b/apps/web-roo-code/src/app/page.tsx
@@ -14,6 +14,7 @@ import {
} from "@/components/homepage"
import { EXTERNAL_LINKS } from "@/lib/constants"
import { ArrowRight } from "lucide-react"
+import { StructuredData } from "@/components/structured-data"
// Invalidate cache when a request comes in, at most once every hour.
export const revalidate = 3600
@@ -23,6 +24,7 @@ export default async function Home() {
return (
<>
+
diff --git a/apps/web-roo-code/src/components/structured-data.tsx b/apps/web-roo-code/src/components/structured-data.tsx
new file mode 100644
index 0000000000..0a7ba479e9
--- /dev/null
+++ b/apps/web-roo-code/src/components/structured-data.tsx
@@ -0,0 +1,26 @@
+import { getStructuredData } from "@/lib/structured-data"
+
+/**
+ * StructuredData Component
+ *
+ * Renders JSON-LD structured data in the document head for SEO.
+ *
+ * The structured data includes:
+ * - Organization information (brand, logo, social profiles)
+ * - WebSite metadata (site name for Google Search)
+ * - SoftwareApplication details (VS Code extension)
+ *
+ * @see https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
+ */
+export function StructuredData() {
+ const structuredData = getStructuredData()
+
+ return (
+
+ )
+}
diff --git a/apps/web-roo-code/src/lib/seo.ts b/apps/web-roo-code/src/lib/seo.ts
index 7dfad0550a..9af16e58e8 100644
--- a/apps/web-roo-code/src/lib/seo.ts
+++ b/apps/web-roo-code/src/lib/seo.ts
@@ -3,7 +3,7 @@ const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://roocode.com"
export const SEO = {
url: SITE_URL,
name: "Roo Code",
- title: "Roo Code – Your AI-Powered Dev Team in VS Code and Beyond",
+ title: "Roo Code – The AI dev team that gets things done",
description:
"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
locale: "en_US",
diff --git a/apps/web-roo-code/src/lib/structured-data.ts b/apps/web-roo-code/src/lib/structured-data.ts
new file mode 100644
index 0000000000..271b9a6d31
--- /dev/null
+++ b/apps/web-roo-code/src/lib/structured-data.ts
@@ -0,0 +1,127 @@
+import { SEO } from "./seo"
+import { EXTERNAL_LINKS } from "./constants"
+
+/**
+ * Type definitions for Schema.org structured data
+ */
+interface ImageObject {
+ "@type": "ImageObject"
+ url: string
+ width: number
+ height: number
+}
+
+interface Organization {
+ "@type": "Organization"
+ "@id": string
+ name: string
+ url: string
+ logo: ImageObject
+ alternateName: string[]
+ sameAs: string[]
+}
+
+interface WebSite {
+ "@type": "WebSite"
+ "@id": string
+ url: string
+ name: string
+ alternateName: string[]
+ publisher: { "@id": string }
+}
+
+interface SoftwareApplication {
+ "@type": "SoftwareApplication"
+ "@id": string
+ name: string
+ applicationCategory: string
+ operatingSystem: string
+ url: string
+ downloadUrl: string
+ offers: {
+ "@type": "Offer"
+ price: string
+ priceCurrency: string
+ }
+ isAccessibleForFree: boolean
+ publisher: { "@id": string }
+}
+
+interface StructuredDataGraph {
+ "@context": "https://schema.org"
+ "@graph": [Organization, WebSite, SoftwareApplication]
+}
+
+/**
+ * Generates the complete JSON-LD structured data for SEO
+ *
+ * This includes:
+ * - Organization schema (brand identity, logo, social profiles)
+ * - WebSite schema (site name for Google Search)
+ * - SoftwareApplication schema (VS Code extension metadata)
+ *
+ * @returns Complete structured data object ready for JSON-LD injection
+ */
+export function getStructuredData(): StructuredDataGraph {
+ // Organization ID - used to link all entities
+ const orgId = `${SEO.url}#org`
+
+ const organization: Organization = {
+ "@type": "Organization",
+ "@id": orgId,
+ name: SEO.name,
+ url: SEO.url,
+ logo: {
+ "@type": "ImageObject",
+ url: `${SEO.url}/android-chrome-512x512.png`,
+ width: 512,
+ height: 512,
+ },
+ alternateName: ["RooCode"],
+ sameAs: [
+ EXTERNAL_LINKS.GITHUB,
+ EXTERNAL_LINKS.MARKETPLACE,
+ EXTERNAL_LINKS.X,
+ EXTERNAL_LINKS.LINKEDIN,
+ EXTERNAL_LINKS.REDDIT,
+ EXTERNAL_LINKS.DISCORD,
+ EXTERNAL_LINKS.YOUTUBE,
+ ],
+ }
+
+ const website: WebSite = {
+ "@type": "WebSite",
+ "@id": `${SEO.url}#website`,
+ url: SEO.url,
+ name: SEO.name,
+ alternateName: ["RooCode"],
+ publisher: { "@id": orgId },
+ }
+
+ const softwareApplication: SoftwareApplication = {
+ "@type": "SoftwareApplication",
+ "@id": `${SEO.url}#vscode-extension`,
+ name: "Roo Code (VS Code extension)",
+ applicationCategory: "DeveloperApplication",
+ operatingSystem: "Windows, macOS, Linux",
+ url: SEO.url,
+ downloadUrl: EXTERNAL_LINKS.MARKETPLACE,
+ offers: {
+ "@type": "Offer",
+ price: "0",
+ priceCurrency: "USD",
+ },
+ isAccessibleForFree: true,
+ publisher: { "@id": orgId },
+ }
+
+ return {
+ "@context": "https://schema.org",
+ "@graph": [organization, website, softwareApplication],
+ }
+}
+
+/**
+ * Type export for use in components
+ */
+export type { StructuredDataGraph }
diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts
index 6b80459118..87e62e1045 100644
--- a/packages/types/src/providers/bedrock.ts
+++ b/packages/types/src/providers/bedrock.ts
@@ -457,7 +457,6 @@ export const BEDROCK_REGIONS = [
{ value: "us-gov-west-1", label: "us-gov-west-1" },
].sort((a, b) => a.value.localeCompare(b.value))
-export const BEDROCK_CLAUDE_SONNET_4_MODEL_ID = "anthropic.claude-sonnet-4-20250514-v1:0"
export const BEDROCK_1M_CONTEXT_MODEL_IDS = [
"anthropic.claude-sonnet-4-20250514-v1:0",
"anthropic.claude-sonnet-4-5-20250929-v1:0",
diff --git a/packages/types/src/providers/zai.ts b/packages/types/src/providers/zai.ts
index b3838c1406..de8c6cd4e4 100644
--- a/packages/types/src/providers/zai.ts
+++ b/packages/types/src/providers/zai.ts
@@ -32,6 +32,18 @@ export const internationalZAiModels = {
description:
"GLM-4.5-Air is the lightweight version of GLM-4.5. It balances performance and cost-effectiveness, and can flexibly switch to hybrid thinking models.",
},
+ "glm-4.6": {
+ maxTokens: 98_304,
+ contextWindow: 204_800,
+ supportsImages: false,
+ supportsPromptCache: true,
+ inputPrice: 0.6,
+ outputPrice: 2.2,
+ cacheWritesPrice: 0,
+ cacheReadsPrice: 0.11,
+ description:
+ "GLM-4.6 is Zhipu's newest model with an extended context window of up to 200k tokens, providing enhanced capabilities for processing longer documents and conversations.",
+ },
} as const satisfies Record
export type MainlandZAiModelId = keyof typeof mainlandZAiModels
@@ -101,6 +113,44 @@ export const mainlandZAiModels = {
},
],
},
+ "glm-4.6": {
+ maxTokens: 98_304,
+ contextWindow: 204_800,
+ supportsImages: false,
+ supportsPromptCache: true,
+ inputPrice: 0.29,
+ outputPrice: 1.14,
+ cacheWritesPrice: 0,
+ cacheReadsPrice: 0.057,
+ description:
+ "GLM-4.6 is Zhipu's newest model with an extended context window of up to 200k tokens, providing enhanced capabilities for processing longer documents and conversations.",
+ tiers: [
+ {
+ contextWindow: 32_000,
+ inputPrice: 0.21,
+ outputPrice: 1.0,
+ cacheReadsPrice: 0.043,
+ },
+ {
+ contextWindow: 128_000,
+ inputPrice: 0.29,
+ outputPrice: 1.14,
+ cacheReadsPrice: 0.057,
+ },
+ {
+ contextWindow: 200_000,
+ inputPrice: 0.29,
+ outputPrice: 1.14,
+ cacheReadsPrice: 0.057,
+ },
+ {
+ contextWindow: Infinity,
+ inputPrice: 0.29,
+ outputPrice: 1.14,
+ cacheReadsPrice: 0.057,
+ },
+ ],
+ },
} as const satisfies Record
export const ZAI_DEFAULT_TEMPERATURE = 0
diff --git a/releases/3.28.14-release.png b/releases/3.28.14-release.png
new file mode 100644
index 0000000000..4ef1acc702
Binary files /dev/null and b/releases/3.28.14-release.png differ
diff --git a/src/api/providers/__tests__/bedrock.spec.ts b/src/api/providers/__tests__/bedrock.spec.ts
index 8df495ca9f..55317dac40 100644
--- a/src/api/providers/__tests__/bedrock.spec.ts
+++ b/src/api/providers/__tests__/bedrock.spec.ts
@@ -25,7 +25,7 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => {
import { AwsBedrockHandler } from "../bedrock"
import { ConverseStreamCommand, BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"
-import { BEDROCK_CLAUDE_SONNET_4_MODEL_ID } from "@roo-code/types"
+import { BEDROCK_1M_CONTEXT_MODEL_IDS } from "@roo-code/types"
import type { Anthropic } from "@anthropic-ai/sdk"
@@ -569,7 +569,7 @@ describe("AwsBedrockHandler", () => {
describe("1M context beta feature", () => {
it("should enable 1M context window when awsBedrock1MContext is true for Claude Sonnet 4", () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -584,7 +584,7 @@ describe("AwsBedrockHandler", () => {
it("should use default context window when awsBedrock1MContext is false for Claude Sonnet 4", () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -614,7 +614,7 @@ describe("AwsBedrockHandler", () => {
it("should include anthropic_beta parameter when 1M context is enabled", async () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -644,7 +644,7 @@ describe("AwsBedrockHandler", () => {
it("should not include anthropic_beta parameter when 1M context is disabled", async () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -698,7 +698,7 @@ describe("AwsBedrockHandler", () => {
it("should enable 1M context window with cross-region inference for Claude Sonnet 4", () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -711,12 +711,12 @@ describe("AwsBedrockHandler", () => {
// Should have 1M context window even with cross-region prefix
expect(model.info.contextWindow).toBe(1_000_000)
// Model ID should have cross-region prefix
- expect(model.id).toBe(`us.${BEDROCK_CLAUDE_SONNET_4_MODEL_ID}`)
+ expect(model.id).toBe(`us.${BEDROCK_1M_CONTEXT_MODEL_IDS[0]}`)
})
it("should include anthropic_beta parameter with cross-region inference for Claude Sonnet 4", async () => {
const handler = new AwsBedrockHandler({
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
@@ -746,7 +746,7 @@ describe("AwsBedrockHandler", () => {
// Should not include anthropic_version since thinking is not enabled
expect(commandArg.additionalModelRequestFields.anthropic_version).toBeUndefined()
// Model ID should have cross-region prefix
- expect(commandArg.modelId).toBe(`us.${BEDROCK_CLAUDE_SONNET_4_MODEL_ID}`)
+ expect(commandArg.modelId).toBe(`us.${BEDROCK_1M_CONTEXT_MODEL_IDS[0]}`)
})
})
})
diff --git a/src/api/providers/__tests__/zai.spec.ts b/src/api/providers/__tests__/zai.spec.ts
index 7928a4298d..383394b703 100644
--- a/src/api/providers/__tests__/zai.spec.ts
+++ b/src/api/providers/__tests__/zai.spec.ts
@@ -71,6 +71,19 @@ describe("ZAiHandler", () => {
expect(model.id).toBe(testModelId)
expect(model.info).toEqual(internationalZAiModels[testModelId])
})
+
+ it("should return GLM-4.6 international model with correct configuration", () => {
+ const testModelId: InternationalZAiModelId = "glm-4.6"
+ const handlerWithModel = new ZAiHandler({
+ apiModelId: testModelId,
+ zaiApiKey: "test-zai-api-key",
+ zaiApiLine: "international",
+ })
+ const model = handlerWithModel.getModel()
+ expect(model.id).toBe(testModelId)
+ expect(model.info).toEqual(internationalZAiModels[testModelId])
+ expect(model.info.contextWindow).toBe(204_800)
+ })
})
describe("China Z AI", () => {
@@ -108,6 +121,19 @@ describe("ZAiHandler", () => {
expect(model.id).toBe(testModelId)
expect(model.info).toEqual(mainlandZAiModels[testModelId])
})
+
+ it("should return GLM-4.6 China model with correct configuration", () => {
+ const testModelId: MainlandZAiModelId = "glm-4.6"
+ const handlerWithModel = new ZAiHandler({
+ apiModelId: testModelId,
+ zaiApiKey: "test-zai-api-key",
+ zaiApiLine: "china",
+ })
+ const model = handlerWithModel.getModel()
+ expect(model.id).toBe(testModelId)
+ expect(model.info).toEqual(mainlandZAiModels[testModelId])
+ expect(model.info.contextWindow).toBe(204_800)
+ })
})
describe("Default behavior", () => {
diff --git a/src/api/providers/bedrock.ts b/src/api/providers/bedrock.ts
index 66432196aa..f162210d06 100644
--- a/src/api/providers/bedrock.ts
+++ b/src/api/providers/bedrock.ts
@@ -21,7 +21,6 @@ import {
BEDROCK_MAX_TOKENS,
BEDROCK_DEFAULT_CONTEXT,
AWS_INFERENCE_PROFILE_MAPPING,
- BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
BEDROCK_1M_CONTEXT_MODEL_IDS,
} from "@roo-code/types"
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
index 6dc9a81272..bc2d89dac4 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -2276,6 +2276,22 @@ export class Task extends EventEmitter implements TaskLike {
// Note: updateApiReqMsg() is now called from within drainStreamInBackgroundToFindAllUsage
// to ensure usage data is captured even when the stream is interrupted. The background task
// uses local variables to accumulate usage data before atomically updating the shared state.
+
+ // Complete the reasoning message if it exists
+ // We can't use say() here because the reasoning message may not be the last message
+ // (other messages like text blocks or tool uses may have been added after it during streaming)
+ if (reasoningMessage) {
+ const lastReasoningIndex = findLastIndex(
+ this.clineMessages,
+ (m) => m.type === "say" && m.say === "reasoning",
+ )
+
+ if (lastReasoningIndex !== -1 && this.clineMessages[lastReasoningIndex].partial) {
+ this.clineMessages[lastReasoningIndex].partial = false
+ await this.updateClineMessage(this.clineMessages[lastReasoningIndex])
+ }
+ }
+
await this.persistGpt5Metadata(reasoningMessage)
await this.saveClineMessages()
await this.providerRef.deref()?.postStateToWebview()
diff --git a/src/core/tools/generateImageTool.ts b/src/core/tools/generateImageTool.ts
index 842b5a5efa..46eb745402 100644
--- a/src/core/tools/generateImageTool.ts
+++ b/src/core/tools/generateImageTool.ts
@@ -11,7 +11,7 @@ import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
import { OpenRouterHandler } from "../../api/providers/openrouter"
// Hardcoded list of image generation models for now
-const IMAGE_GENERATION_MODELS = ["google/gemini-2.5-flash-image-preview", "google/gemini-2.5-flash-image-preview:free"]
+const IMAGE_GENERATION_MODELS = ["google/gemini-2.5-flash-image-preview"]
export async function generateImageTool(
cline: Task,
diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx
index 9c33ba6a37..56cf76b815 100644
--- a/webview-ui/src/components/chat/ChatTextArea.tsx
+++ b/webview-ui/src/components/chat/ChatTextArea.tsx
@@ -295,10 +295,10 @@ export const ChatTextArea = forwardRef(
const allModes = useMemo(() => getAllModes(customModes), [customModes])
- // Memoized check for whether the input has content
+ // Memoized check for whether the input has content (text or images)
const hasInputContent = useMemo(() => {
- return inputValue.trim().length > 0
- }, [inputValue])
+ return inputValue.trim().length > 0 || selectedImages.length > 0
+ }, [inputValue, selectedImages])
const queryItems = useMemo(() => {
return [
@@ -1277,18 +1277,20 @@ export const ChatTextArea = forwardRef(
diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx
index 8fce5fb312..9dea72a71e 100644
--- a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx
+++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx
@@ -1116,4 +1116,86 @@ describe("ChatTextArea", () => {
// expect(isDisabled).toBe(true)
})
})
+
+ describe("send button visibility", () => {
+ it("should show send button when there are images but no text", () => {
+ const { container } = render(
+ ,
+ )
+
+ // Find the send button by looking for the button with SendHorizontal icon
+ const buttons = container.querySelectorAll("button")
+ const sendButton = Array.from(buttons).find(
+ (button) => button.querySelector(".lucide-send-horizontal") !== null,
+ )
+
+ expect(sendButton).toBeInTheDocument()
+
+ // Check that the button is visible (has opacity-100 class when content exists)
+ expect(sendButton).toHaveClass("opacity-100")
+ expect(sendButton).toHaveClass("cursor-pointer")
+ expect(sendButton).not.toHaveClass("opacity-60")
+ expect(sendButton).not.toHaveClass("cursor-not-allowed")
+ })
+
+ it("should hide send button when there is no text and no images", () => {
+ const { container } = render()
+
+ // Find the send button by looking for the button with SendHorizontal icon
+ const buttons = container.querySelectorAll("button")
+ const sendButton = Array.from(buttons).find(
+ (button) => button.querySelector(".lucide-send-horizontal") !== null,
+ )
+
+ expect(sendButton).toBeInTheDocument()
+
+ // Check that the button is hidden (has opacity-60 class when no content)
+ expect(sendButton).toHaveClass("opacity-60")
+ expect(sendButton).toHaveClass("cursor-not-allowed")
+ expect(sendButton).not.toHaveClass("opacity-100")
+ expect(sendButton).not.toHaveClass("cursor-pointer")
+ })
+
+ it("should show send button when there is text but no images", () => {
+ const { container } = render()
+
+ // Find the send button by looking for the button with SendHorizontal icon
+ const buttons = container.querySelectorAll("button")
+ const sendButton = Array.from(buttons).find(
+ (button) => button.querySelector(".lucide-send-horizontal") !== null,
+ )
+
+ expect(sendButton).toBeInTheDocument()
+
+ // Check that the button is visible
+ expect(sendButton).toHaveClass("opacity-100")
+ expect(sendButton).toHaveClass("pointer-events-auto")
+ })
+
+ it("should show send button when there is both text and images", () => {
+ const { container } = render(
+ ,
+ )
+
+ // Find the send button by looking for the button with SendHorizontal icon
+ const buttons = container.querySelectorAll("button")
+ const sendButton = Array.from(buttons).find(
+ (button) => button.querySelector(".lucide-send-horizontal") !== null,
+ )
+
+ expect(sendButton).toBeInTheDocument()
+
+ // Check that the button is visible
+ expect(sendButton).toHaveClass("opacity-100")
+ expect(sendButton).toHaveClass("pointer-events-auto")
+ })
+ })
})
diff --git a/webview-ui/src/components/settings/ImageGenerationSettings.tsx b/webview-ui/src/components/settings/ImageGenerationSettings.tsx
index c31f31e316..53ae18d1a7 100644
--- a/webview-ui/src/components/settings/ImageGenerationSettings.tsx
+++ b/webview-ui/src/components/settings/ImageGenerationSettings.tsx
@@ -14,7 +14,6 @@ interface ImageGenerationSettingsProps {
// Hardcoded list of image generation models
const IMAGE_GENERATION_MODELS = [
{ value: "google/gemini-2.5-flash-image-preview", label: "Gemini 2.5 Flash Image Preview" },
- { value: "google/gemini-2.5-flash-image-preview:free", label: "Gemini 2.5 Flash Image Preview (Free)" },
// Add more models as they become available
]
diff --git a/webview-ui/src/components/settings/__tests__/ImageGenerationSettings.spec.tsx b/webview-ui/src/components/settings/__tests__/ImageGenerationSettings.spec.tsx
index cadd8f83e0..3ecadb73e3 100644
--- a/webview-ui/src/components/settings/__tests__/ImageGenerationSettings.spec.tsx
+++ b/webview-ui/src/components/settings/__tests__/ImageGenerationSettings.spec.tsx
@@ -41,7 +41,7 @@ describe("ImageGenerationSettings", () => {
,
)
diff --git a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts
index 9b4bff0e42..7a96381065 100644
--- a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts
+++ b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts
@@ -5,7 +5,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { renderHook } from "@testing-library/react"
import type { Mock } from "vitest"
-import { ProviderSettings, ModelInfo, BEDROCK_CLAUDE_SONNET_4_MODEL_ID } from "@roo-code/types"
+import { ProviderSettings, ModelInfo, BEDROCK_1M_CONTEXT_MODEL_IDS } from "@roo-code/types"
import { useSelectedModel } from "../useSelectedModel"
import { useRouterModels } from "../useRouterModels"
@@ -473,28 +473,28 @@ describe("useSelectedModel", () => {
it("should enable 1M context window for Bedrock Claude Sonnet 4 when awsBedrock1MContext is true", () => {
const apiConfiguration: ProviderSettings = {
apiProvider: "bedrock",
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsBedrock1MContext: true,
}
const wrapper = createWrapper()
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
- expect(result.current.id).toBe(BEDROCK_CLAUDE_SONNET_4_MODEL_ID)
+ expect(result.current.id).toBe(BEDROCK_1M_CONTEXT_MODEL_IDS[0])
expect(result.current.info?.contextWindow).toBe(1_000_000)
})
it("should use default context window for Bedrock Claude Sonnet 4 when awsBedrock1MContext is false", () => {
const apiConfiguration: ProviderSettings = {
apiProvider: "bedrock",
- apiModelId: BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
+ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],
awsBedrock1MContext: false,
}
const wrapper = createWrapper()
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper })
- expect(result.current.id).toBe(BEDROCK_CLAUDE_SONNET_4_MODEL_ID)
+ expect(result.current.id).toBe(BEDROCK_1M_CONTEXT_MODEL_IDS[0])
expect(result.current.info?.contextWindow).toBe(200_000)
})
diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts
index f4610c6e61..94bf8a4e7c 100644
--- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts
+++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts
@@ -403,11 +403,11 @@ function getSelectedModel({
// Apply 1M context beta tier pricing for Claude Sonnet 4
if (
provider === "anthropic" &&
- id === "claude-sonnet-4-20250514" &&
+ (id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5") &&
apiConfiguration.anthropicBeta1MContext &&
baseInfo
) {
- // Type assertion since we know claude-sonnet-4-20250514 has tiers
+ // Type assertion since we know claude-sonnet-4-20250514 and claude-sonnet-4-5 have tiers
const modelWithTiers = baseInfo as typeof baseInfo & {
tiers?: Array<{
contextWindow: number