{"record":{"id":"37f04c9908c29591","repo":"BigPizzaV3/CodexPlusPlus","slug":"api","errorCode":null,"errorMessage":"请填写 API 的模型名称","messagePattern":"请填写 API 的模型名称","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/conversation-canvas/public/canvas.user.js","lineNumber":634,"sourceCode":"    await new Promise(resolve=>setTimeout(resolve,1000));\n  }\n}\n\n  // OpenAI-compatible Chat Completions. Never persist credentials in tree checkpoints.\nfunction apiEndpoint(raw){\n  let url;try{url=new URL(String(raw).trim());}catch{throw Error('请输入完整的 HTTPS API 地址');}\n  if(url.protocol!=='https:'||url.username||url.password||url.search||url.hash)throw Error('API 地址须使用 HTTPS，且不含账号、密码、查询参数或片段');\n  const path=url.pathname.replace(/\\/+$/,'');\n  url.pathname=path.endsWith('/chat/completions')?path:(path||'/v1')+'/chat/completions';\n  return url.href;\n}\n\nfunction apiConfig(input){\n  const channel=input?.channel==='external'?'external':'native';\n  const value={channel,baseUrl:String(input?.baseUrl||'').trim(),model:String(input?.model||'').trim(),key:String(input?.key||'').trim(),remember:input?.remember===true,speed:input?.speed==='provider'?'provider':'fast',revision:input?.revision||crypto.randomUUID()};\n  if(channel==='external'){\n    value.endpoint=apiEndpoint(value.baseUrl);\n    if(!value.model||value.model.length>200)throw Error('请填写 API 的模型名称');\n    if(!value.key||/[\\r\\n]/.test(value.key))throw Error('请在设置中填写有效 API Key');\n  }\n  return value;\n}\n\nfunction storedApiConfig(config){\n  const {channel,baseUrl,model,remember,speed,revision}=config;\n  return {channel,baseUrl,model,remember,speed,revision,...remember?{key:config.key}:{}};\n}\n\nfunction apiError(error){\n  if(error?.name==='AbortError')return error;\n  if(error?.canvasApiLocal===true)return error;\n  const code=Number(error?.status??error?.responseStatus);\n  const hint={401:'密钥无效或已过期',403:'接口拒绝访问，请检查权限',404:'地址或模型不存在',408:'接口请求超时',413:'本批资料超过接口大小限制',429:'接口限流或额度不足'}[code];\n  // Provider messages can echo request contents and Authorization; never display them.\n  return Object.assign(Error(hint?`API ${code}：${hint}`:code>=400?`API 请求失败（HTTP ${code}），请检查服务状态`:'API 连接失败，请检查地址、网络及服务状态'),{retryable:!code||code===408||code===429||code>=500});\n}","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/tools/conversation-canvas/public/canvas.user.js#L616-L652","documentation":"apiConfig() validates the external-channel API settings before use. When channel is 'external', the model name must be non-empty and at most 200 characters; otherwise this Error is thrown to stop the organize flow early with a clear message instead of sending a doomed request.","triggerScenarios":"Calling apiConfig (via the organize/save settings path) with input.channel==='external' and input.model empty or whitespace-only, or a model string longer than 200 chars.","commonSituations":"User selected external API channel in settings but left the model field blank; pasted a baseUrl+key but forgot model; a script/UI bug trimmed the model away.","solutions":["Open settings and enter a valid model name in the model field","Verify the channel is really 'external' and the model matches what the provider exposes (e.g. gpt-4o, deepseek-chat)","Ensure the model string is ≤200 characters (no accidental giant paste)","If using native channel intentionally, set channel to 'native' so the model check is skipped"],"exampleFix":"// before\napiConfig({channel:'external',baseUrl:'https://api.x.com/v1',model:'',key:'sk-...'})\n// after\napiConfig({channel:'external',baseUrl:'https://api.x.com/v1',model:'gpt-4o',key:'sk-...'})","handlingStrategy":"validation","validationCode":"const model=(input.model||'').trim();\nif(input.channel==='external' && (!model || model.length>200)) throw new Error('请填写 API 的模型名称');","typeGuard":"function hasValidModel(cfg){return typeof cfg?.model==='string' && cfg.model.trim().length>0 && cfg.model.trim().length<=200;}","tryCatchPattern":null,"preventionTips":["Always fill the model field when using an external channel","Trim pasted model names","Keep model names short and canonical from provider docs"],"tags":["validation","configuration","user-input"],"backgroundTag":"missing-required-argument","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}