[codex] add vendor code entry presets follow-up (#363)

* address coding plan review comments

* add more vendor code entry presets
This commit is contained in:
Cita
2026-04-01 13:57:24 +08:00
committed by GitHub
parent 3ebe851002
commit aac1307470
8 changed files with 543 additions and 28 deletions
@@ -471,6 +471,66 @@ describe('sites proxy settings', () => {
});
});
it('canonicalizes create payload url and platform before persistence and conflict checks', async () => {
const created = await app.inject({
method: 'POST',
url: '/api/sites',
payload: {
name: 'Aliyun Generic OpenAI',
url: ' coding.dashscope.aliyuncs.com/v1/ ',
platform: ' OPENAI ',
},
});
expect(created.statusCode).toBe(200);
expect(created.json()).toMatchObject({
name: 'Aliyun Generic OpenAI',
url: 'https://coding.dashscope.aliyuncs.com/v1',
platform: 'openai',
});
const duplicate = await app.inject({
method: 'POST',
url: '/api/sites',
payload: {
name: 'Aliyun Generic OpenAI Duplicate',
url: 'https://coding.dashscope.aliyuncs.com/v1',
platform: 'openai',
},
});
expect(duplicate.statusCode).toBe(409);
expect((duplicate.json() as { error?: string }).error).toContain('already exists');
});
it('canonicalizes update payload url and platform before saving', async () => {
const created = await app.inject({
method: 'POST',
url: '/api/sites',
payload: {
name: 'Update Canonicalization',
url: 'https://update-canonicalization.example.com',
platform: 'new-api',
},
});
expect(created.statusCode).toBe(200);
const response = await app.inject({
method: 'PUT',
url: `/api/sites/${(created.json() as { id: number }).id}`,
payload: {
url: ' coding.dashscope.aliyuncs.com/v1/ ',
platform: ' OPENAI ',
},
});
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
url: 'https://coding.dashscope.aliyuncs.com/v1',
platform: 'openai',
});
});
it('detects Zhipu Coding Plan OpenAI endpoint with initialization preset metadata', async () => {
const response = await app.inject({
method: 'POST',
@@ -486,4 +546,50 @@ describe('sites proxy settings', () => {
initializationPresetId: 'zhipu-coding-plan-openai',
});
});
it('detects additional vendor-specific code endpoints with initialization preset metadata', async () => {
const cases = [
{ url: 'https://api.deepseek.com/v1', platform: 'openai', initializationPresetId: 'deepseek-openai' },
{ url: 'https://api.deepseek.com/anthropic', platform: 'claude', initializationPresetId: 'deepseek-claude' },
{ url: 'https://api.moonshot.cn/v1', platform: 'openai', initializationPresetId: 'moonshot-openai' },
{ url: 'https://api.moonshot.cn/anthropic', platform: 'claude', initializationPresetId: 'moonshot-claude' },
{ url: 'https://api.minimaxi.com/v1', platform: 'openai', initializationPresetId: 'minimax-openai' },
{ url: 'https://api.minimaxi.com/anthropic', platform: 'claude', initializationPresetId: 'minimax-claude' },
{ url: 'https://api-inference.modelscope.cn/v1', platform: 'openai', initializationPresetId: 'modelscope-openai' },
{ url: 'https://api-inference.modelscope.cn', platform: 'claude', initializationPresetId: 'modelscope-claude' },
{ url: 'https://ark.cn-beijing.volces.com/api/coding/v3', platform: 'openai', initializationPresetId: 'doubao-coding-openai' },
];
for (const testCase of cases) {
const response = await app.inject({
method: 'POST',
url: '/api/sites/detect',
payload: { url: testCase.url },
});
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
platform: testCase.platform,
initializationPresetId: testCase.initializationPresetId,
});
}
});
it('creates Doubao Coding Plan sites without explicit platform by using preset-backed detection', async () => {
const response = await app.inject({
method: 'POST',
url: '/api/sites',
payload: {
name: 'Doubao Coding Plan',
url: 'https://ark.cn-beijing.volces.com/api/coding/v3',
},
});
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({
name: 'Doubao Coding Plan',
platform: 'openai',
initializationPresetId: 'doubao-coding-openai',
});
});
});
+19 -12
View File
@@ -90,9 +90,15 @@ type ErrorLike = {
cause?: unknown;
};
function normalizeOptionalPlatform(value: string | undefined): string | null {
function normalizeCanonicalSiteUrl(value: string): string {
const trimmed = value.trim();
const withScheme = trimmed.includes('://') ? trimmed : `https://${trimmed}`;
return normalizeSiteUrl(withScheme);
}
function normalizeSitePlatform(value: string | undefined): string | null {
if (value === undefined) return null;
const normalized = value.trim();
const normalized = value.trim().toLowerCase();
return normalized || null;
}
@@ -347,15 +353,15 @@ export async function sitesRoutes(app: FastifyInstance) {
const existingSites = await db.select().from(schema.sites).all();
const maxSortOrder = existingSites.reduce((max, site) => Math.max(max, site.sortOrder || 0), -1);
const normalizedUrl = normalizeSiteUrl(url);
let detectedPlatform = normalizeOptionalPlatform(platform);
const canonicalUrl = normalizeCanonicalSiteUrl(url);
const canonicalPlatform = normalizeSitePlatform(platform);
let detectedPlatform = canonicalPlatform;
let responseInitializationPresetId: string | null = explicitInitializationPreset?.id || null;
if (!detectedPlatform) {
if (explicitInitializationPreset) {
detectedPlatform = explicitInitializationPreset.platform;
} else {
const detected = await detectSite(url);
const detected = await detectSite(canonicalUrl);
detectedPlatform = detected?.platform ?? null;
responseInitializationPresetId = detected?.initializationPresetId || null;
}
@@ -366,16 +372,16 @@ export async function sitesRoutes(app: FastifyInstance) {
if (!detectedPlatform) {
return { error: 'Could not detect platform. Please specify manually.' };
}
const conflictingSite = findExistingSiteBinding(existingSites, detectedPlatform, normalizedUrl);
const conflictingSite = findExistingSiteBinding(existingSites, detectedPlatform, canonicalUrl);
if (conflictingSite) {
return sendSiteBindingConflict(reply, detectedPlatform, normalizedUrl);
return sendSiteBindingConflict(reply, detectedPlatform, canonicalUrl);
}
let inserted;
try {
inserted = await db.insert(schema.sites).values({
name,
url: normalizedUrl,
url: canonicalUrl,
platform: detectedPlatform,
proxyUrl: normalizedProxyUrl.proxyUrl,
useSystemProxy: normalizedUseSystemProxy ?? false,
@@ -388,7 +394,7 @@ export async function sitesRoutes(app: FastifyInstance) {
}).run();
} catch (error) {
if (isSitesPlatformUrlConflict(error)) {
return sendSiteBindingConflict(reply, detectedPlatform, normalizedUrl);
return sendSiteBindingConflict(reply, detectedPlatform, canonicalUrl);
}
throw error;
}
@@ -459,9 +465,10 @@ export async function sitesRoutes(app: FastifyInstance) {
return reply.code(400).send({ error: normalizedCustomHeaders.error || 'Invalid customHeaders.' });
}
const nextUrl = body.url !== undefined ? normalizeSiteUrl(body.url) : existingSite.url;
const canonicalPlatform = normalizeSitePlatform(body.platform);
const nextUrl = body.url !== undefined ? normalizeCanonicalSiteUrl(body.url) : existingSite.url;
const nextPlatform = body.platform !== undefined
? normalizeOptionalPlatform(body.platform)
? canonicalPlatform
: existingSite.platform;
if (body.platform !== undefined && !nextPlatform) {
return reply.code(400).send({ error: 'Invalid platform. Expected non-empty string.' });