fix(frontend): 按端点能力约束会话压缩映射

This commit is contained in:
MMEXA
2026-07-14 02:05:10 +08:00
parent f10d631a9c
commit 93e2f95c47
5 changed files with 262 additions and 10 deletions
@@ -52,8 +52,21 @@ vi.mock('@/components/common/MultiSelect.vue', async () => {
return {
default: defineComponent({
name: 'MultiSelectStub',
setup() {
return () => h('div')
props: {
modelValue: { type: Array, default: () => [] },
options: { type: Array, default: () => [] },
},
emits: ['update:modelValue'],
setup(props, { emit }) {
return () => h('div', (props.options as Array<{ value: string, label: string }>).map(option => h(
'button',
{
type: 'button',
'data-endpoint-id': option.value,
onClick: () => emit('update:modelValue', [option.value]),
},
option.label,
)))
},
}),
}
@@ -108,6 +121,136 @@ afterEach(() => {
})
describe('ModelMappingDialog', () => {
it('offers session compaction only for an explicitly selected Responses endpoint', async () => {
const chatEndpoint = {
id: 'endpoint-chat',
api_format: 'openai:chat',
base_url: 'https://api.example.com/v1',
is_active: true,
} as ProviderEndpoint
const responsesEndpoint = {
id: 'endpoint-responses',
api_format: 'openai:responses',
base_url: 'https://api.example.com/v1',
is_active: true,
} as ProviderEndpoint
const model = {
id: 'model-sol',
provider_model_name: 'gpt-5.6-sol',
global_model_display_name: 'GPT-5.6 Sol',
provider_model_mappings: [],
} as Model
const open = ref(false)
const root = document.createElement('div')
document.body.appendChild(root)
const app = createApp(defineComponent({
setup() {
return () => h(ModelMappingDialog, {
open: open.value,
providerId: 'provider-1',
endpoints: [chatEndpoint, responsesEndpoint],
models: [model],
preselectedModelId: model.id,
'onUpdate:open': (value: boolean) => { open.value = value },
})
},
}))
app.mount(root)
mountedApps.push({ app, root })
open.value = true
await nextTick()
await nextTick()
expect(root.textContent).toContain('所有请求')
expect(root.textContent).not.toContain('仅会话压缩')
root.querySelector<HTMLButtonElement>('[data-endpoint-id="endpoint-chat"]')?.click()
await nextTick()
expect(root.textContent).not.toContain('仅会话压缩')
root.querySelector<HTMLButtonElement>('[data-endpoint-id="endpoint-responses"]')?.click()
await nextTick()
expect(root.textContent).toContain('仅会话压缩')
})
it('returns to all requests when a compact mapping switches away from Responses', async () => {
const responsesEndpoint = {
id: 'endpoint-responses',
api_format: 'openai:responses',
base_url: 'https://api.example.com/v1',
is_active: true,
} as ProviderEndpoint
const chatEndpoint = {
id: 'endpoint-chat',
api_format: 'openai:chat',
base_url: 'https://api.example.com/v1',
is_active: true,
} as ProviderEndpoint
const model = {
id: 'model-sol',
provider_model_name: 'gpt-5.6-sol',
global_model_display_name: 'GPT-5.6 Sol',
provider_model_mappings: [{
name: 'gpt-5.6-luna',
priority: 1,
endpoint_ids: [responsesEndpoint.id],
operations: ['compact'],
}],
} as Model
const editingGroup: AliasGroup = {
model,
apiFormatsKey: '',
apiFormats: [],
endpointIdsKey: responsesEndpoint.id,
endpointIds: [responsesEndpoint.id],
operationsKey: 'compact',
operations: ['compact'],
aliases: model.provider_model_mappings ?? [],
}
const open = ref(false)
const root = document.createElement('div')
document.body.appendChild(root)
const app = createApp(defineComponent({
setup() {
return () => h(ModelMappingDialog, {
open: open.value,
providerId: 'provider-1',
endpoints: [responsesEndpoint, chatEndpoint],
models: [model],
editingGroup,
'onUpdate:open': (value: boolean) => { open.value = value },
})
},
}))
app.mount(root)
mountedApps.push({ app, root })
open.value = true
await nextTick()
await nextTick()
expect(root.textContent).toContain('仅会话压缩')
root.querySelector<HTMLButtonElement>('[data-endpoint-id="endpoint-chat"]')?.click()
await nextTick()
expect(root.textContent).not.toContain('仅会话压缩')
expect(root.querySelector<HTMLButtonElement>('[role="radio"][aria-checked="true"]')?.textContent)
.toContain('所有请求')
const saveButton = [...root.querySelectorAll('button')]
.find(button => button.textContent?.includes('保存映射'))
saveButton?.click()
await vi.waitFor(() => expect(updateModel).toHaveBeenCalledTimes(1))
expect(updateModel).toHaveBeenCalledWith('provider-1', 'model-sol', {
provider_model_mappings: [{
name: 'gpt-5.6-luna',
priority: 1,
endpoint_ids: [chatEndpoint.id],
}],
})
})
it('normalizes and replaces an edited compact operation scope', async () => {
const endpoint = {
id: 'endpoint-responses',