新增 AGC 模型 Agent 模式与 Claude Agent SDK sidecar
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 57s
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 57s
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
后台模型目录增加 codex/cc 执行模式绑定,旧目录缺省兼容 Codex AGC 客户端按模型绑定路由 Codex app-server 或 Claude Agent SDK sidecar 随包携带 Node runtime、Claude Agent SDK 与匹配平台 Claude runtime 补充模型配置、客户端选择、运行时适配、MCP 取消和定向测试 同步 AGC 模型配置规范、里程碑计划与共享决策记录
This commit is contained in:
@@ -1075,11 +1075,14 @@ export interface AdminRechargeRefundActionResponse {
|
||||
export interface AdminWalletRestrictionResponse {
|
||||
wallet: AdminProfileWalletPayload;
|
||||
}
|
||||
export type AdminAgcAgentMode = 'codex' | 'cc';
|
||||
|
||||
export interface AdminAgcModel {
|
||||
id: string;
|
||||
alias: string;
|
||||
modelId: string;
|
||||
enabled: boolean;
|
||||
agentMode: AdminAgcAgentMode;
|
||||
}
|
||||
|
||||
export interface AdminAgcModelCatalog {
|
||||
|
||||
@@ -23,14 +23,23 @@ vi.mock('../components/useAdminWriteConfirm', () => ({
|
||||
confirmDialog: null,
|
||||
}),
|
||||
}));
|
||||
afterEach(cleanup);
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test('edits alias and upstream model without changing the stable identifier or revision', async () => {
|
||||
const catalog = {
|
||||
revision: 3,
|
||||
defaultModelId: 'quality',
|
||||
models: [
|
||||
{ id: 'quality', alias: '高质量', modelId: 'gpt-6-astra', enabled: true },
|
||||
{
|
||||
id: 'quality',
|
||||
alias: '高质量',
|
||||
modelId: 'gpt-6-astra',
|
||||
enabled: true,
|
||||
agentMode: 'codex' as const,
|
||||
},
|
||||
],
|
||||
};
|
||||
vi.mocked(getAgcModelCatalog).mockResolvedValue(catalog);
|
||||
@@ -54,3 +63,44 @@ test('edits alias and upstream model without changing the stable identifier or r
|
||||
expect(screen.getAllByText('已保存').length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
test('new models default to Codex and save the selected Agent mode', async () => {
|
||||
const catalog = {
|
||||
revision: 3,
|
||||
defaultModelId: 'quality',
|
||||
models: [
|
||||
{
|
||||
id: 'quality',
|
||||
alias: '高质量',
|
||||
modelId: 'gpt-6-astra',
|
||||
enabled: true,
|
||||
agentMode: 'codex' as const,
|
||||
},
|
||||
],
|
||||
};
|
||||
vi.mocked(getAgcModelCatalog).mockResolvedValue(catalog);
|
||||
vi.mocked(saveAgcModelCatalog).mockImplementation(async (_, input) => ({
|
||||
...input,
|
||||
revision: 4,
|
||||
}));
|
||||
render(<AdminAgcModelsPage token="test" onUnauthorized={vi.fn()} />);
|
||||
await screen.findByDisplayValue('gpt-6-astra');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '添加模型' }));
|
||||
const agentMode = screen.getByLabelText('模型 2 Agent 模式');
|
||||
expect((agentMode as HTMLSelectElement).value).toBe('codex');
|
||||
fireEvent.change(agentMode, { target: { value: 'cc' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '保存' }));
|
||||
|
||||
await waitFor(() => {
|
||||
const calls = vi.mocked(saveAgcModelCatalog).mock.calls;
|
||||
const payload = calls[calls.length - 1]?.[1];
|
||||
expect(payload?.models).toHaveLength(2);
|
||||
expect(payload?.models[1]).toMatchObject({
|
||||
alias: '',
|
||||
modelId: '',
|
||||
enabled: true,
|
||||
agentMode: 'cc',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,6 +116,7 @@ export function AdminAgcModelsPage({
|
||||
columns={[
|
||||
{ key: 'alias', label: '别名' },
|
||||
{ key: 'modelId', label: '实际模型名' },
|
||||
{ key: 'agentMode', label: 'Agent 模式' },
|
||||
{ key: 'enabled', label: '启用' },
|
||||
{ key: 'default', label: '默认' },
|
||||
{ key: 'actions', label: '操作' },
|
||||
@@ -155,6 +156,7 @@ export function AdminAgcModelsPage({
|
||||
alias: '',
|
||||
modelId: '',
|
||||
enabled: true,
|
||||
agentMode: 'codex',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -211,6 +213,21 @@ export function AdminAgcModelsPage({
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
aria-label={`模型 ${index + 1} Agent 模式`}
|
||||
value={model.agentMode}
|
||||
disabled={busy}
|
||||
onChange={(e) =>
|
||||
update(model.id, {
|
||||
agentMode: e.target.value as AdminAgcModel['agentMode'],
|
||||
})
|
||||
}
|
||||
>
|
||||
<option value="codex">Codex</option>
|
||||
<option value="cc">Claude Code</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
aria-label={`模型 ${index + 1} 启用`}
|
||||
|
||||
Reference in New Issue
Block a user