feat(web): configure custom DeepSeek models
This commit is contained in:
@@ -76,9 +76,8 @@ describe('web e2e: message IconActions and clocks on settled history', () => {
|
||||
|
||||
it.skipIf(MODE === 'record')('matches the conversation aria golden with IconActions and clocks', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-message-actions-aria'))
|
||||
await page.getByRole('button', {
|
||||
name: 'Select model, current deepseek-v4-flash',
|
||||
}).waitFor({ timeout: 10_000 })
|
||||
await page.getByRole('button', { name: 'Select model', exact: true })
|
||||
.waitFor({ timeout: 10_000 })
|
||||
// Keep a footer focused so opacity-hidden actions stay in the a11y tree
|
||||
// as an active/focused control during the capture.
|
||||
await page.getByRole('button', { name: 'Copy' }).first().focus()
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('web e2e: Models settings page configures a dormant provider', () => {
|
||||
await dialog.getByText('填入各提供方的 API 密钥即可使用其模型。').waitFor({ timeout: 10_000 })
|
||||
// The dormant pi-ai adapter contributes its whole installed catalog; no
|
||||
// provider is configured yet, so the page is one add button.
|
||||
const add = dialog.getByRole('button', { name: '+ 添加提供方' })
|
||||
const add = dialog.getByRole('button', { name: '添加提供方' })
|
||||
await add.waitFor({ timeout: 10_000 })
|
||||
// The button enables once the dormant catalog lands in the join.
|
||||
await expect.poll(async () => add.isEnabled(), { timeout: 10_000 }).toBe(true)
|
||||
|
||||
@@ -16,6 +16,7 @@ import { saveFailureShot } from './support.ts'
|
||||
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/onboarding-deepseek-config', import.meta.url))
|
||||
const MISSING_EXPECTED = join(SNAPSHOT_DIR, 'missing.expected.md')
|
||||
const MODELS_EXPECTED = join(SNAPSHOT_DIR, 'models.expected.md')
|
||||
const MODE = webSnapshotMode()
|
||||
|
||||
describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup', () => {
|
||||
@@ -85,7 +86,48 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('configures arbitrary DeepSeek models and prompts after the selected model is removed', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-onboarding-deepseek-models'))
|
||||
const settings = page.getByRole('dialog', { name: '设置' })
|
||||
await settings.getByText('自定义设置').click()
|
||||
await settings.getByRole('button', { name: '删除模型' }).first().click()
|
||||
await settings.getByRole('button', { name: '添加模型' }).click()
|
||||
const customModelId = settings.getByLabel('模型 ID 2')
|
||||
await customModelId.fill('private-preview')
|
||||
await settings.getByLabel('显示名称 2').fill('Private Preview')
|
||||
await settings.getByLabel('上下文窗口 2').fill('131072')
|
||||
|
||||
const modelEditor = await captureStableAria(page, '[role="dialog"]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(MODELS_EXPECTED, modelEditor, MODE)
|
||||
await settings.getByRole('button', { name: '保存', exact: true }).click()
|
||||
await customModelId.waitFor({ state: 'detached', timeout: 15_000 })
|
||||
|
||||
const document = await readFile(join(scaffold.harnessHome, 'settings.yaml'), 'utf8')
|
||||
expect(document).toContain('id: deepseek-v4-pro')
|
||||
expect(document).toContain('id: private-preview')
|
||||
expect(document).toContain('name: Private Preview')
|
||||
expect(document).toContain('contextWindow: 131072')
|
||||
expect(document).not.toContain('id: deepseek-v4-flash')
|
||||
|
||||
await page.keyboard.press('Escape')
|
||||
await page.getByRole('button', { name: '创建工作区', exact: true }).click()
|
||||
await page.getByRole('menuitem', { name: '新建工作区', exact: true }).click()
|
||||
const workspaceDialog = page.getByRole('dialog', { name: '新建工作区' })
|
||||
await workspaceDialog.getByLabel('新工作区名称').fill('model-fallback-e2e')
|
||||
await workspaceDialog.getByRole('button', { name: '创建工作区', exact: true }).click()
|
||||
await workspaceDialog.waitFor({ state: 'detached', timeout: 10_000 })
|
||||
|
||||
const modelTrigger = page.getByRole('button', { name: '选择模型', exact: true })
|
||||
await modelTrigger.waitFor({ timeout: 10_000 })
|
||||
await modelTrigger.click()
|
||||
await page.getByRole('menuitem', { name: /模型/ }).click()
|
||||
expect(await page.getByText('deepseek-v4-flash', { exact: true }).count()).toBe(0)
|
||||
await page.getByRole('menuitemradio', { name: 'Private Preview' }).waitFor({ timeout: 10_000 })
|
||||
expect(tripwire.warnings).toEqual([])
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('keeps the fixture inventory closed', async () => {
|
||||
await assertFixtureInventory(SNAPSHOT_DIR, ['missing.expected.md'])
|
||||
await assertFixtureInventory(SNAPSHOT_DIR, ['missing.expected.md', 'models.expected.md'])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -152,12 +152,11 @@ describe('web e2e: seeded history renders through cold resume', () => {
|
||||
|
||||
it.skipIf(MODE === 'record')('matches the historical conversation aria golden', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-seeded-aria'))
|
||||
await page.getByRole('button', {
|
||||
// This scenario deliberately leaves the LLM seam open to prove zero
|
||||
// model calls. History still restores the selected id, but no catalog
|
||||
// adapter exists to provide its presentation name.
|
||||
name: 'Select model, current deepseek-v4-flash',
|
||||
}).waitFor({ timeout: 10_000 })
|
||||
// This scenario deliberately leaves the LLM seam open to prove zero
|
||||
// model calls. History still restores the routed id, but without an
|
||||
// advertised catalog row the selector prompts for a listed replacement.
|
||||
await page.getByRole('button', { name: 'Select model', exact: true })
|
||||
.waitFor({ timeout: 10_000 })
|
||||
const snapshot = (await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd))
|
||||
.split(SEED_ID).join('{{seededId}}')
|
||||
await compareOrRefreshGolden(UI_EXPECTED, snapshot, MODE)
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
- img
|
||||
- 'button "Access mode, current: Danger Full Access"': Danger Full Access
|
||||
- button "Plan mode on, press to turn off": Plan
|
||||
- button "Select model, current deepseek-v4-flash":
|
||||
- text: deepseek-v4-flash
|
||||
- button "Select model":
|
||||
- text: Select model
|
||||
- img
|
||||
- button "Send message" [disabled]
|
||||
- text: Details
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
- button "Commands":
|
||||
- img
|
||||
- 'button "Access mode, current: Danger Full Access"': Danger Full Access
|
||||
- button "Select model, current deepseek-v4-flash":
|
||||
- text: deepseek-v4-flash
|
||||
- button "Select model":
|
||||
- text: Select model
|
||||
- img
|
||||
- button "Send message" [disabled]
|
||||
- text: 1 turns · 2 steps Tool call {{duration}} Cache hit 98% Input 15.8K tok · Output 135 tok
|
||||
|
||||
@@ -17,4 +17,6 @@
|
||||
- text: minimax-cn 已启用
|
||||
- button "编辑"
|
||||
- button "删除"
|
||||
- button "+ 添加提供方"
|
||||
- button "添加提供方":
|
||||
- img
|
||||
- text: 添加提供方
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
- dialog "设置":
|
||||
- navigation:
|
||||
- text: 设置
|
||||
- button "通用设置":
|
||||
- img
|
||||
- text: 通用设置
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "关闭":
|
||||
- img
|
||||
- text: 关闭
|
||||
- heading "模型" [level=2]
|
||||
- paragraph: 填入各提供方的 API 密钥即可使用其模型。
|
||||
- list:
|
||||
- listitem:
|
||||
- text: DeepSeek 已启用
|
||||
- button "编辑"
|
||||
- text: DeepSeek deepseek-official API 密钥
|
||||
- textbox "API 密钥":
|
||||
- /placeholder: 已配置——输入新值可替换
|
||||
- group:
|
||||
- text: 自定义设置 API 地址
|
||||
- textbox "API 地址":
|
||||
- /placeholder: https://api.deepseek.com
|
||||
- text: 推理强度
|
||||
- combobox "推理强度":
|
||||
- option "默认" [selected]
|
||||
- option "off"
|
||||
- option "high"
|
||||
- option "max"
|
||||
- region "模型目录":
|
||||
- text: 模型目录 已自定义模型目录
|
||||
- button "恢复默认模型"
|
||||
- textbox "模型 ID 1": deepseek-v4-pro
|
||||
- textbox "显示名称 1":
|
||||
- /placeholder: 留空时使用模型 ID
|
||||
- text: DeepSeek-V4-Pro
|
||||
- spinbutton "上下文窗口 1": "1000000"
|
||||
- button "删除模型":
|
||||
- img
|
||||
- text: 删除模型
|
||||
- textbox "模型 ID 2": private-preview
|
||||
- textbox "显示名称 2":
|
||||
- /placeholder: 留空时使用模型 ID
|
||||
- text: Private Preview
|
||||
- spinbutton "上下文窗口 2": "131072"
|
||||
- button "删除模型":
|
||||
- img
|
||||
- text: 删除模型
|
||||
- button "添加模型":
|
||||
- img
|
||||
- text: 添加模型
|
||||
- button "取消"
|
||||
- button "保存"
|
||||
- button "添加提供方":
|
||||
- img
|
||||
- text: 添加提供方
|
||||
@@ -45,8 +45,8 @@
|
||||
- button "Commands":
|
||||
- img
|
||||
- 'button "Access mode, current: Workspace Write"': Workspace Write
|
||||
- button "Select model, current deepseek-v4-flash":
|
||||
- text: deepseek-v4-flash
|
||||
- button "Select model":
|
||||
- text: Select model
|
||||
- img
|
||||
- button "Send message" [disabled]
|
||||
- text: 1 turns · 2 steps Tool call {{duration}} Cache hit 98% Input 15.8K tok · Output 135 tok
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
- button "Commands":
|
||||
- img
|
||||
- 'button "Access mode, current: Danger Full Access"': Danger Full Access
|
||||
- button "Select model, current deepseek-v4-flash":
|
||||
- text: deepseek-v4-flash
|
||||
- button "Select model":
|
||||
- text: Select model
|
||||
- img
|
||||
- button "Send message" [disabled]
|
||||
- text: 1 turns · 2 steps Tool call {{duration}} Cache hit 98% Input 15.8K tok · Output 135 tok
|
||||
|
||||
Reference in New Issue
Block a user