diff --git a/chat-client/package.json b/chat-client/package.json index aa079f4fd6..aff0948d16 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -24,10 +24,10 @@ "package": "webpack" }, "dependencies": { - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.6" + "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/chat-client/src/client/mynahUi.test.ts b/chat-client/src/client/mynahUi.test.ts index 8524ab7713..3a13772926 100644 --- a/chat-client/src/client/mynahUi.test.ts +++ b/chat-client/src/client/mynahUi.test.ts @@ -571,7 +571,7 @@ describe('MynahUI', () => { // Simulate the response from the server const models = [ { id: 'CLAUDE_3_7_SONNET_20250219_V1_0', name: 'Claude Sonnet 3.7' }, - { id: 'CLAUDE_SONNET_4_20250514_V1_0', name: 'Claude Sonnet 4' }, + { id: 'CLAUDE_SONNET_4_20250514_V1_0', name: 'Claude Sonnet 4', description: 'Test description' }, ] const result: ListAvailableModelsResult = { @@ -589,8 +589,12 @@ describe('MynahUI', () => { { id: 'model-selection', options: [ - { value: 'CLAUDE_3_7_SONNET_20250219_V1_0', label: 'Claude Sonnet 3.7' }, - { value: 'CLAUDE_SONNET_4_20250514_V1_0', label: 'Claude Sonnet 4' }, + { value: 'CLAUDE_3_7_SONNET_20250219_V1_0', label: 'Claude Sonnet 3.7', description: '' }, + { + value: 'CLAUDE_SONNET_4_20250514_V1_0', + label: 'Claude Sonnet 4', + description: 'Test description', + }, ], type: 'select', value: 'CLAUDE_3_7_SONNET_20250219_V1_0', diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index e2ce161f6f..0bcdf9bacd 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1737,7 +1737,11 @@ ${params.message}`, ? { ...option, type: 'select', - options: params.models.map(model => ({ value: model.id, label: model.name })), + options: params.models.map(model => ({ + value: model.id, + label: model.name, + description: model.description ?? '', + })), value: params.selectedModelId, } : option diff --git a/chat-client/src/client/texts/modelSelection.ts b/chat-client/src/client/texts/modelSelection.ts index a1d0247875..6cfd25b7fe 100644 --- a/chat-client/src/client/texts/modelSelection.ts +++ b/chat-client/src/client/texts/modelSelection.ts @@ -5,21 +5,24 @@ import { ChatItem, ChatItemFormItem, ChatItemType } from '@aws/mynah-ui' */ export enum BedrockModel { CLAUDE_SONNET_4_20250514_V1_0 = 'CLAUDE_SONNET_4_20250514_V1_0', - CLAUDE_3_7_SONNET_20250219_V1_0 = 'CLAUDE_3_7_SONNET_20250219_V1_0', } type ModelDetails = { label: string + description: string } const modelRecord: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, - [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, + [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { + label: 'Claude Sonnet 4', + description: 'Hybrid reasoning and coding for regular use', + }, } -const modelOptions = Object.entries(modelRecord).map(([value, { label }]) => ({ +const modelOptions = Object.entries(modelRecord).map(([value, { label, description }]) => ({ value, label, + description, })) export const modelSelection: ChatItemFormItem = { diff --git a/client/vscode/package.json b/client/vscode/package.json index a943422cfa..baeeb80cfe 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -351,7 +351,7 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", diff --git a/package-lock.json b/package-lock.json index ebbfc8606b..638493ff16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -254,10 +254,10 @@ "version": "0.1.38", "license": "Apache-2.0", "dependencies": { - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.6" + "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -279,7 +279,7 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", @@ -4019,12 +4019,11 @@ "link": true }, "node_modules/@aws/chat-client-ui-types": { - "version": "0.1.56", - "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.56.tgz", - "integrity": "sha512-5FAFyzo0KzqnVBbZuhN4drCmLnREbb4IpAzb/OS8omNLf1/yUsP89DBCNoW6WxqFuWSASwaPEffmQOuMT3bWIg==", - "license": "Apache-2.0", + "version": "0.1.63", + "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.63.tgz", + "integrity": "sha512-LTiDodg/9jXJSoTmbPa056zRtKjz4Z4szAb7loZa7J7uOMpJ8ah/MxdpOKltW9PgcZ3F7u7585U5LuNPuoY+2A==", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.50" + "@aws/language-server-runtimes-types": "^0.1.57" } }, "node_modules/@aws/hello-world-lsp": { @@ -4068,10 +4067,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.56", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.56.tgz", - "integrity": "sha512-Md/L750JShCHUsCQUJva51Ofkn/GDBEX8PpZnWUIVqkpddDR00SLQS2smNf4UHtKNJ2fefsfks/Kqfuatjkjvg==", - "license": "Apache-2.0", + "version": "0.1.57", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.57.tgz", + "integrity": "sha512-Poy8BW4njSBt6jf3ATnc3YRZQTFnNvFcYs/wcCAvPj314XRdDCS731y3EESVVdXfXlTIqLZrnHsvQgtbNm59Tw==", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5" @@ -4204,11 +4202,10 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.6", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.6.tgz", - "integrity": "sha512-RIFKIasIgO00dYmRM+JS7dij1hzrNZchhf0+CyUNDUpw2Hcc86/8lP90F1F5rJIOtqtnguiPQ7XwmXxf+Tw5jQ==", + "version": "4.36.8", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.8.tgz", + "integrity": "sha512-1IDUjzX42ASOuf6DD+uv/MYlIB50U0wZxX3Rqpc0aR4KFHpoX5mUIwGvqS/uHj42aySFN2QL+T6vUEvD0l6v1A==", "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -28689,7 +28686,7 @@ "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 6219fc5798..bd6432040d 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -35,7 +35,7 @@ "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 4ab9587d1c..367870e3e7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -3043,8 +3043,8 @@ ${' '.repeat(8)}} isCachedModelsValidStub.returns(true) const cachedData = { models: [ - { id: 'model1', name: 'Model 1' }, - { id: 'model2', name: 'Model 2' }, + { id: 'model1', name: 'Model 1', description: 'Test description 1' }, + { id: 'model2', name: 'Model 2', description: 'Test description 2' }, ], defaultModelId: 'model1', timestamp: Date.now(), @@ -3128,8 +3128,16 @@ ${' '.repeat(8)}} const mockApiResponse = { models: { - 'claude-3-sonnet': { modelId: 'claude-3-sonnet' }, - 'claude-4-sonnet': { modelId: 'claude-4-sonnet' }, + 'claude-3-sonnet': { + modelId: 'claude-3-sonnet', + modelName: 'Claude 3 Sonnet', + description: 'Advanced AI model', + }, + 'claude-4-sonnet': { + modelId: 'claude-4-sonnet', + modelName: 'Claude 4 Sonnet', + description: 'Latest AI model', + }, }, defaultModel: { modelId: 'claude-3-sonnet' }, } @@ -3147,8 +3155,8 @@ ${' '.repeat(8)}} assert.strictEqual(result.tabId, mockTabId) assert.strictEqual(result.models.length, 2) assert.deepStrictEqual(result.models, [ - { id: 'claude-3-sonnet', name: 'claude-3-sonnet' }, - { id: 'claude-4-sonnet', name: 'claude-4-sonnet' }, + { id: 'claude-3-sonnet', name: 'Claude 3 Sonnet', description: 'Advanced AI model' }, + { id: 'claude-4-sonnet', name: 'Claude 4 Sonnet', description: 'Latest AI model' }, ]) // Verify cache was updated @@ -3163,7 +3171,7 @@ ${' '.repeat(8)}} // Verify fallback to FALLBACK_MODEL_OPTIONS assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) // FALLBACK_MODEL_OPTIONS length + assert.strictEqual(result.models.length, 1) // FALLBACK_MODEL_OPTIONS length // Verify cache was not updated due to error sinon.assert.notCalled(setCachedModelsStub) @@ -3230,7 +3238,7 @@ ${' '.repeat(8)}} it('should fall back to default model when session has no modelId and no defaultModelId in cache', async () => { getCachedModelsStub.returns({ - models: [{ id: 'model1', name: 'Model 1' }], + models: [{ id: 'model1', name: 'Model 1', description: 'Test model' }], defaultModelId: undefined, // No default model timestamp: Date.now(), }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 374e0a9060..005101b715 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -726,9 +726,10 @@ export class AgenticChatController implements ChatHandlers { // Wait for the response to be completed before proceeding this.#log('Model Response: ', JSON.stringify(responseResult, null, 2)) - models = Object.values(responseResult.models).map(({ modelId, modelName }) => ({ + models = Object.values(responseResult.models).map(({ modelId, modelName, description }) => ({ id: modelId, name: modelName ?? modelId, + description: description ?? '', })) defaultModelId = responseResult.defaultModel?.modelId @@ -765,7 +766,7 @@ export class AgenticChatController implements ChatHandlers { const { models, defaultModelId, errorFromAPI } = await this.#fetchModelsWithCache() // Get the first fallback model option as default - const defaultModelOption = FALLBACK_MODEL_OPTIONS[1] + const defaultModelOption = FALLBACK_MODEL_OPTIONS[0] const DEFAULT_MODEL_ID = defaultModelId || defaultModelOption?.id const sessionResult = this.#chatSessionManagementService.getSession(params.tabId) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts index f037470bec..211cf52dfe 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts @@ -5,27 +5,26 @@ describe('modelSelection', () => { describe('modelOptions', () => { it('should contain the correct model options', () => { assert.ok(Array.isArray(FALLBACK_MODEL_OPTIONS), 'modelOptions should be an array') - assert.strictEqual(FALLBACK_MODEL_OPTIONS.length, 2, 'modelOptions should have 2 items') + assert.strictEqual(FALLBACK_MODEL_OPTIONS.length, 1, 'modelOptions should have 1 item') // Check that the array contains the expected models const modelIds = FALLBACK_MODEL_OPTIONS.map(model => model.id) assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'Should include claude-sonnet-4') - assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), 'Should include claude-3.7-sonnet') // Check that each model has the required properties FALLBACK_MODEL_OPTIONS.forEach(model => { assert.ok('id' in model, 'Model should have id property') assert.ok('name' in model, 'Model should have name property') + assert.ok('description' in model, 'Model should have description property') assert.strictEqual(typeof model.id, 'string', 'Model id should be a string') assert.strictEqual(typeof model.name, 'string', 'Model name should be a string') + assert.strictEqual(typeof model.description, 'string', 'Model description should be a string') }) // Check specific model names const claudeSonnet4 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_SONNET_4_20250514_V1_0') - const claudeSonnet37 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_3_7_SONNET_20250219_V1_0') assert.strictEqual(claudeSonnet4?.name, 'Claude Sonnet 4', 'claude-sonnet-4 should have correct name') - assert.strictEqual(claudeSonnet37?.name, 'Claude 3.7 Sonnet', 'claude-3.7-sonnet should have correct name') }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts index 46c5446c8c..9e9927b10c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts @@ -5,26 +5,28 @@ import { ListAvailableModelsResult } from '@aws/language-server-runtimes/protoco */ export enum BedrockModel { CLAUDE_SONNET_4_20250514_V1_0 = 'CLAUDE_SONNET_4_20250514_V1_0', - CLAUDE_3_7_SONNET_20250219_V1_0 = 'CLAUDE_3_7_SONNET_20250219_V1_0', } type ModelDetails = { label: string + description: string } export const FALLBACK_MODEL_RECORD: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, - [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, + [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { + label: 'Claude Sonnet 4', + description: 'Hybrid reasoning and coding for regular use', + }, } export const BEDROCK_MODEL_TO_MODEL_ID: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: 'claude-3.7-sonnet', [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: 'claude-sonnet-4', } export const FALLBACK_MODEL_OPTIONS: ListAvailableModelsResult['models'] = Object.entries(FALLBACK_MODEL_RECORD).map( - ([value, { label }]) => ({ + ([value, { label, description }]) => ({ id: value, name: label, + description: description, }) )