Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions chat-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 7 additions & 3 deletions chat-client/src/client/mynahUi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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',
Expand Down
6 changes: 5 additions & 1 deletion chat-client/src/client/mynahUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 7 additions & 4 deletions chat-client/src/client/texts/modelSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, ModelDetails> = {
[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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this change on the backend?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most probably it wont change but this is valid until for initial listAvailableModel API call so it should be fine.

},
}

const modelOptions = Object.entries(modelRecord).map(([value, { label }]) => ({
const modelOptions = Object.entries(modelRecord).map(([value, { label, description }]) => ({
value,
label,
description,
}))

export const modelSelection: ChatItemFormItem = {
Expand Down
2 changes: 1 addition & 1 deletion client/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
31 changes: 14 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/aws-lsp-codewhisperer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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' },
}
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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(),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Will be deleted or merged.
*/

import * as crypto from 'crypto'

Check warning on line 6 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test

Do not import Node.js builtin module "crypto"

Check warning on line 6 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test (Windows)

Do not import Node.js builtin module "crypto"
import * as path from 'path'

Check warning on line 7 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test

Do not import Node.js builtin module "path"

Check warning on line 7 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test (Windows)

Do not import Node.js builtin module "path"
import * as os from 'os'

Check warning on line 8 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test

Do not import Node.js builtin module "os"

Check warning on line 8 in server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

View workflow job for this annotation

GitHub Actions / Test (Windows)

Do not import Node.js builtin module "os"
import {
ChatTriggerType,
Origin,
Expand Down Expand Up @@ -726,9 +726,10 @@

// 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

Expand Down Expand Up @@ -765,7 +766,7 @@
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -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, ModelDetails> = {
[BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' },
[BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callout for future: probably worth adding a comment: since we are also removing 3.7, we have to be careful not to remove sonnet 4 because if for some reason call to the backend fails, there will be no fallback left to show in the UI

[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, string> = {
[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,
})
)
Loading