import { describe, expect, it } from 'vitest'; import { buildArgs, DEFAULT_API_KEY_ENV, toToolSummaries, type CodexProviderSpec } from './codexRuntime'; /** 这组断言锁的是「喂给 codex.exe 的 -c 参数」——provider 能不能生效全在这里 */ const API_KEY = 'sk-unit-secret-abcdef123456'; const custom: CodexProviderSpec = { id: 'zsjz', name: '知数 · 第三方', baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1', model: 'qwen3-max', apiKey: API_KEY, httpHeaders: { 'X-DashScope-WorkSpace': 'ws-1' }, extra: { request_max_retries: 3, temperature: 0.5, query_params: { version: 'v2' } }, }; describe('buildArgs', () => { it('没有 provider 时只起 app-server,且不传 --strict-config', () => { expect(buildArgs(null)).toEqual(['app-server', '--listen', 'stdio://']); expect(buildArgs(null)).not.toContain('--strict-config'); }); it('自定义 provider 走 responses + 免登录 + env_key', () => { const args = buildArgs(custom); expect(args).toContain('-c'); expect(args.join(' ')).toContain('model_provider="zsjz"'); expect(args.join(' ')).toContain('model="qwen3-max"'); expect(args.join(' ')).toContain('model_providers.zsjz.wire_api="responses"'); expect(args.join(' ')).toContain('model_providers.zsjz.requires_openai_auth=false'); expect(args.join(' ')).toContain(`model_providers.zsjz.env_key="${DEFAULT_API_KEY_ENV}"`); expect(args.join(' ')).toContain('model_providers.zsjz.base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"'); }); it('API Key 绝不出现在命令行参数里', () => { expect(JSON.stringify(buildArgs(custom))).not.toContain(API_KEY); }); it('没有 apiKey 时不写 env_key(本地无鉴权服务)', () => { const args = buildArgs({ ...custom, apiKey: null }); expect(args.join(' ')).not.toContain('env_key'); }); it('http_headers 与 query_params 输出成 TOML inline table', () => { const joined = buildArgs(custom).join(' '); // 只含 A-Za-z0-9_- 的键按 TOML bare key 规则输出,无需加引号 expect(joined).toContain('model_providers.zsjz.http_headers={X-DashScope-WorkSpace="ws-1"}'); expect(joined).toContain('model_providers.zsjz.query_params={version="v2"}'); }); it('config 白名单外的键被丢弃', () => { const joined = buildArgs(custom).join(' '); expect(joined).toContain('request_max_retries=3'); expect(joined).not.toContain('temperature'); }); it('provider 一律用自定义 id,绝不落在 Codex 保留的内置 id 上', () => { const joined = buildArgs(custom).join(' '); expect(joined).toContain('model_provider="zsjz"'); // 覆盖 model_providers.ollama 之类会让 app-server 启动即退出 expect(joined).not.toMatch(/model_providers\.(ollama|lmstudio|openai)\b/u); }); it('重试次数 / 空闲超时 / websocket 开关都会写进 -c', () => { const joined = buildArgs({ ...custom, extra: { request_max_retries: 0, stream_max_retries: 0, stream_idle_timeout_ms: 300_000, supports_websockets: false, }, }).join(' '); expect(joined).toContain('model_providers.zsjz.stream_max_retries=0'); expect(joined).toContain('model_providers.zsjz.request_max_retries=0'); expect(joined).toContain('model_providers.zsjz.stream_idle_timeout_ms=300000'); expect(joined).toContain('model_providers.zsjz.supports_websockets=false'); }); it('值里的引号与反斜杠被 TOML 安全转义', () => { const joined = buildArgs({ ...custom, name: '带"引号"和\\反斜杠', baseUrl: 'https://x/v1', }).join(' '); expect(joined).toContain('model_providers.zsjz.name="带\\"引号\\"和\\\\反斜杠"'); }); it('嵌套 map 输出成 TOML inline table,而不是 JSON', () => { const joined = buildArgs({ ...custom, extra: { query_params: { version: 'v2', flag: 'on' } }, }).join(' '); expect(joined).toContain('model_providers.zsjz.query_params={version="v2",flag="on"}'); expect(joined).not.toContain('{"version"'); }); it('不符合 bare key 规则的键加引号', () => { const joined = buildArgs({ ...custom, httpHeaders: { 'X Token': 'a' } }).join(' '); expect(joined).toContain('model_providers.zsjz.http_headers={"X Token"="a"}'); }); }); /** mcpServerStatus/list 的 tools 详情结构不由我们决定,这里锁住退化行为 */ describe('toToolSummaries', () => { it('详情里带 name / description 时优先取详情', () => { expect(toToolSummaries({ query_case: { name: 'query_case_v2', description: '按条件查案件' } })).toEqual([ { name: 'query_case_v2', description: '按条件查案件' }, ]); }); it('详情形态不认识时退化成用 key 当工具名,描述留空', () => { expect(toToolSummaries({ list_tables: { inputSchema: {} }, ping: null })).toEqual([ { name: 'list_tables', description: '' }, { name: 'ping', description: '' }, ]); }); it('tools 缺失时返回空列表', () => { expect(toToolSummaries(undefined)).toEqual([]); expect(toToolSummaries(null)).toEqual([]); }); });