import assert from 'node:assert/strict' import { createServer } from 'node:http' import { mkdtemp, readFile } from 'node:fs/promises' import { resolve } from 'node:path' import { once } from 'node:events' import { normalizeModelAddress, endpointCandidates, endpointUrl, modelEndpoint } from '../src/shared/model-endpoint' import { cheapestModelPrice, lookupModelMetadata, type ModelCatalog } from '../src/shared/model-metadata' import { discoverModelConnection, modelFetch } from '../src/main/model-connection' import { Gateway } from '../src/main/gateway' import { buildAnthropicRequest, buildGeminiRequest } from '../src/main/gateway/native-protocols' import { prepareOmpModel, supportsOmpModel } from '../src/main/omp-model' import { OmpKernel, detectOmpPath } from '../src/main/omp' import type { ModelApi, ResolvedModel } from '../src/shared/models' const directory = await mkdtemp(resolve('.tmp/custom-model-regression-')) const checks: string[] = [] function check(label: string, run: () => void): void { run(); checks.push(label) } const catalog = JSON.parse(await readFile('resources/model-metadata/models.dev.json', 'utf8')) as ModelCatalog const source = JSON.parse(await readFile('resources/model-metadata/manifest.json', 'utf8')) check('domain-only, local origin and full routes normalize', () => { assert.equal(normalizeModelAddress('api.example.com'), 'https://api.example.com') assert.equal(normalizeModelAddress('127.0.0.1:9000'), 'http://127.0.0.1:9000') assert.throws(() => normalizeModelAddress('https://user:password@example.com')) assert.throws(() => normalizeModelAddress('https://example.com?key=secret')) assert(endpointCandidates('https://example.com/proxy', 'anthropic').some(endpoint => endpointUrl(endpoint, 'generate') === 'https://example.com/proxy/v1/messages')) }) check('metadata uses the canonical provider and cheapest context tier', () => { const value = lookupModelMetadata(catalog, 'gpt-5.4', 'openai', source)! assert.equal(value.providerId, 'openai'); assert.equal(value.contextWindowTokens, 272000) assert.equal(value.maxInputTokens, 144000); assert(value.supportsImages); assert(value.supportsReasoning) assert.equal(value.price?.input, 2.5); assert.equal(value.price?.output, 15) assert.equal(lookupModelMetadata(catalog, 'openai/gpt-5.4', 'auto', source)?.modelId, 'gpt-5.4') assert.equal(lookupModelMetadata(catalog, 'gpt-5.4-not-a-real-alias', 'auto', source), null) assert.equal(cheapestModelPrice({ id: 'bad', cost: { input: -1, output: 1 } }), undefined) }) check('tier thresholds constrain defaults without changing provider', () => { const price = cheapestModelPrice({ id: 'test', limit: { context: 100000 }, cost: { input: 4, output: 8, tiers: [{ input: 1, output: 2, tier: { type: 'context', size: 32000 } }, { input: 5, output: 10, tier: { type: 'context', size: 64000 } }] } })! assert.equal(price.minContext, 32000); assert.equal(price.maxContext, 64000) }) let api: ModelApi = 'anthropic-messages', anonymous = false const requests: Array<{ api: ModelApi; path: string; body: any }> = [] const rejectedAuth: unknown[] = [] const anthropic = (model: string): string => [ { type: 'message_start', message: { id: 'msg_test', type: 'message', role: 'assistant', content: [], model, stop_reason: null, stop_sequence: null, usage: { input_tokens: 10, output_tokens: 0 } } }, { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } }, { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: '协议正常' } }, { type: 'content_block_stop', index: 0 }, { type: 'message_delta', delta: { stop_reason: 'end_turn', stop_sequence: null }, usage: { output_tokens: 2 } }, { type: 'message_stop' } ].map(value => `event: ${value.type}\ndata: ${JSON.stringify(value)}\n\n`).join('') const gemini = (): string => 'data: ' + JSON.stringify({ candidates: [{ index: 0, content: { role: 'model', parts: [{ text: '协议正常' }] }, finishReason: 'STOP' }], usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 2, totalTokenCount: 12 } }) + '\n\n' const server = createServer(async (req, res) => { const url = new URL(req.url!, 'http://local') if (url.pathname === '/redirect') { res.writeHead(302, { location: 'http://127.0.0.1:1/trap' }); res.end(); return } if (req.method === 'GET') { const valid = api === 'anthropic-messages' ? url.pathname === '/v1/models' && req.headers['x-api-key'] === 'controlled-test-key' : api === 'google-generative-ai' ? url.pathname === '/v1beta/models' && req.headers['x-goog-api-key'] === 'controlled-test-key' : url.pathname === '/v1/models' && req.headers.authorization === 'Bearer controlled-test-key' res.writeHead(valid ? 200 : 404, { 'content-type': 'application/json' }) res.end(JSON.stringify(api === 'google-generative-ai' ? { models: [{ name: 'models/gemini-2.5-flash', displayName: 'Gemini test', supportedGenerationMethods: ['generateContent'] }, { name: 'models/embed', supportedGenerationMethods: ['embedContent'] }] } : { data: [{ id: 'claude-3-5-haiku-latest' }, { id: 'claude-3-5-haiku-latest' }] })); return } let raw = ''; for await (const chunk of req) raw += chunk const authorized = anonymous ? !req.headers['x-api-key'] && !req.headers['x-goog-api-key'] && !req.headers.authorization : api === 'anthropic-messages' ? req.headers['x-api-key'] === 'controlled-test-key' && !req.headers.authorization : req.headers['x-goog-api-key'] === 'controlled-test-key' if (!authorized) { rejectedAuth.push({ api, anonymous, path: req.url, headers: Object.keys(req.headers).filter(name => /api-key|authorization/.test(name)), googleSentinel: req.headers['x-goog-api-key'] === 'N/A' }); res.writeHead(401, { 'content-type': 'application/json' }); res.end(JSON.stringify({ error: { message: 'Incorrect native authentication' } })); return } const body = JSON.parse(raw || '{}'); requests.push({ api, path: req.url!, body }) res.writeHead(200, { 'content-type': 'text/event-stream' }) res.end(api === 'anthropic-messages' ? anthropic(body.model) : gemini()) }) server.listen(0, '127.0.0.1'); await once(server, 'listening') const address = server.address(); assert(address && typeof address === 'object') const root = `http://127.0.0.1:${address.port}` try { await assert.rejects(() => modelFetch(root + '/redirect', {}), /不同域名/); checks.push('credentials cannot follow a cross-origin redirect') for (const currentApi of ['anthropic-messages', 'google-generative-ai'] as const) { api = currentApi const discovery = await discoverModelConnection(root, 'auto', 'controlled-test-key', true) assert.equal(discovery.endpoint.api, api); assert.equal(discovery.models.length, 1) checks.push(api + ' model discovery negotiates path and auth, filters and deduplicates') const config = { api, baseUrl: discovery.endpoint.baseUrl, model: api === 'anthropic-messages' ? 'claude-3-5-haiku-latest' : 'gemini-2.5-flash', apiKey: 'controlled-test-key', temperature: 0, maxToolRounds: 2, maxOutputTokens: 128 } const events = [] for await (const event of new Gateway(config).stream({ messages: [{ role: 'user', content: 'hello' }] })) events.push(event) assert.equal(events.filter(event => event.type === 'text').map(event => event.text).join(''), '协议正常') assert(events.some(event => event.type === 'usage' && event.usage.totalTokens === 12)) checks.push(api + ' fallback gateway streams native text and usage') const body = api === 'anthropic-messages' ? buildAnthropicRequest(config, { messages: [{ role: 'user', content: [{ type: 'image_url', image_url: { url: 'data:image/png;base64,AAAA' } }] }] }) : buildGeminiRequest(config, { messages: [{ role: 'user', content: [{ type: 'image_url', image_url: { url: 'data:image/png;base64,AAAA' } }] }] }) assert(JSON.stringify(body).includes('AAAA')); checks.push(api + ' image input preserves base64 data') const executable = detectOmpPath(); assert(executable, 'Real OMP required for native protocol acceptance') for (const authMode of ['api-key', 'none'] as const) { anonymous = authMode === 'none' const resolved: ResolvedModel = { profile: { id: config.model, providerId: 'custom', name: config.model, model: config.model, baseUrl: root, protocol: api === 'anthropic-messages' ? 'anthropic' : 'gemini', authMode, hasApiKey: !anonymous, keyStorage: 'none', supportsReasoning: true, supportsImages: true }, config: { ...config, authMode, apiKey: anonymous ? '' : config.apiKey } } if (!supportsOmpModel(resolved)) { assert.equal(api, 'google-generative-ai'); assert.equal(authMode, 'none') await assert.rejects(() => prepareOmpModel(resolved), /原生 HTTP/) checks.push('keyless Gemini explicitly routes to the native HTTP gateway rather than sending OMP sentinel credentials') continue } process.env.YCODE_OMP_HOME = directory const managed = await prepareOmpModel(resolved), frames: string[] = [], errors: string[] = [] assert(!(await readFile(resolve(directory, '.omp/profiles', managed.profile, 'agent/models.yml'), 'utf8')).includes(config.apiKey), 'native profile must never store the API key') const kernel = new OmpKernel(executable, directory, managed.profile, undefined, managed.model, managed.env) kernel.on('error', error => errors.push(String(error))) kernel.on('stderr', value => { if (/error/i.test(String(value))) errors.push(String(value).slice(0, 300)) }) const start = requests.length try { await kernel.start() const auto = await kernel.send({ type: 'set_thinking_level', level: 'auto' }) assert.equal(auto.success, true, 'OMP must accept automatic thinking intensity') await kernel.setThinkingLevel('minimal') const end = new Promise((resolve, reject) => { const timer = setTimeout(() => reject(Error('Native protocol turn timeout: ' + JSON.stringify({ api, paths: requests.slice(start).map(r => r.path), frames, errors }))), 18000) kernel.on('event', frame => { frames.push(frame.type); if (frame.type === 'agent_end') { clearTimeout(timer); resolve() } }) }) await kernel.prompt('Reply briefly.'); await end assert(requests.length > start, JSON.stringify({ api, authMode, frames, errors, rejectedAuth })) const request = requests[start] console.log(JSON.stringify({ api, nativePath: request.path, thinking: request.body.thinking ?? request.body.generationConfig?.thinkingConfig, expectedRoot: discovery.endpoint.baseUrl, frameTypes: [...new Set(frames)], errors })) const nativeUrl = new URL(request.path, root) assert.equal(nativeUrl.pathname, api === 'anthropic-messages' ? '/v1/messages' : '/v1beta/models/gemini-2.5-flash:streamGenerateContent') if (api === 'google-generative-ai') assert.equal(nativeUrl.searchParams.get('alt'), 'sse') checks.push(api + ' real OMP native adapter completes using the negotiated route and ' + authMode + ' authentication') } finally { await kernel.dispose() } } anonymous = false } console.log('CUSTOM_MODEL_REGRESSION_PASS ' + JSON.stringify({ directory, checks })) } finally { server.closeAllConnections(); await new Promise(resolve => server.close(() => resolve())) }