fix(web): edit a declared provider's name and protocol
The Models editor card curated its pi-ai fields by what every route has, so `displayName` and `api` — the two a hand-declared route names for itself — were asked for at creation and then reachable only through settings.yaml. The editor now renders both for a route the directory reports as declared, from the same namespace schema the create card reads. A catalog route gets neither: it defaults its name from its catalog entry, and its models each carry their own protocol, so a route-level one could only override all of them. Clearing the name unsets it and the route falls back to its id, which is what the field's placeholder shows; storing the empty string would be refused by the adapter. A declared profile naming no protocol selects nothing rather than reading as if it had picked the first choice. The Provider ID stays fixed: it is the settings dict key, it is referenced from `agent-default-model` and every logged request header, and it is the stem of a credential reference the page can never read back to move. Fixes #2204
This commit is contained in:
@@ -28,6 +28,7 @@ const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/models-settings', import
|
||||
const EMPTY_EXPECTED = join(SNAPSHOT_DIR, 'empty.expected.md')
|
||||
const CONFIGURED_EXPECTED = join(SNAPSHOT_DIR, 'configured.expected.md')
|
||||
const DECLARED_EXPECTED = join(SNAPSHOT_DIR, 'declared.expected.md')
|
||||
const DECLARED_EDIT_EXPECTED = join(SNAPSHOT_DIR, 'declared-edit.expected.md')
|
||||
const NATIVE_DELETE_EXPECTED = join(SNAPSHOT_DIR, 'native-delete.expected.md')
|
||||
const DELETE_EXPECTED = join(SNAPSHOT_DIR, 'delete.expected.md')
|
||||
const MODE = webSnapshotMode()
|
||||
@@ -209,6 +210,37 @@ describe('web e2e: Models settings page configures a dormant provider', () => {
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('reopens the name and protocol a declared route was created with', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-models-declared-identity'))
|
||||
const dialog = page.getByRole('dialog', { name: '设置' })
|
||||
await dialog.getByRole('button', { name: '编辑 Acme Gateway (acme-gateway)' }).click()
|
||||
await dialog.getByText('自定义设置').click()
|
||||
// The create card asked this route for a name and a protocol because
|
||||
// nothing can default them; the editor reaches the same two fields rather
|
||||
// than sending the user to settings.yaml for what only this route names.
|
||||
const protocol = dialog.getByLabel('API 协议')
|
||||
await protocol.waitFor({ timeout: 10_000 })
|
||||
expect(await protocol.inputValue()).toBe('openai-completions')
|
||||
const name = dialog.getByLabel('显示名称', { exact: true })
|
||||
expect(await name.inputValue()).toBe('Acme Gateway')
|
||||
const snapshot = await captureStableAria(page, '[role="dialog"]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(DECLARED_EDIT_EXPECTED, snapshot, MODE)
|
||||
|
||||
await protocol.selectOption('anthropic-messages')
|
||||
await name.fill('Acme 网关')
|
||||
await dialog.getByRole('button', { name: '保存', exact: true }).click()
|
||||
await expect.poll(async () => dialog.getByLabel('API 协议').count(), { timeout: 10_000 }).toBe(0)
|
||||
// The adapter re-resolved the route under the new protocol and re-registered
|
||||
// it under the new name: an unserviceable profile would have been refused
|
||||
// at the write instead, and a rename that did not re-register would leave
|
||||
// the old label on the row.
|
||||
await dialog.getByText('Acme 网关', { exact: true }).first().waitFor({ timeout: 10_000 })
|
||||
const document = await readFile(join(scaffold.harnessHome, 'settings.yaml'), 'utf8')
|
||||
expect(document).toContain('api: anthropic-messages')
|
||||
expect(document).toContain('displayName: Acme 网关')
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('confirms an identified provider deletion before removing its profile and key', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-models-delete'))
|
||||
const settingsDialog = page.getByRole('dialog', { name: '设置' })
|
||||
@@ -243,8 +275,8 @@ describe('web e2e: Models settings page configures a dormant provider', () => {
|
||||
|
||||
it.skipIf(MODE === 'record')('keeps the fixture inventory closed', async () => {
|
||||
await assertFixtureInventory(SNAPSHOT_DIR, [
|
||||
'configured.expected.md', 'declared.expected.md', 'delete.expected.md',
|
||||
'empty.expected.md', 'native-delete.expected.md',
|
||||
'configured.expected.md', 'declared-edit.expected.md', 'declared.expected.md',
|
||||
'delete.expected.md', 'empty.expected.md', 'native-delete.expected.md',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user