@vibeapi/cli 0.0.76 → 0.0.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,11 +72,14 @@ export interface GatewayClientModel {
72
72
  description?: string;
73
73
  contextWindow?: number;
74
74
  autoCompactTokens?: number;
75
+ /** Taken off by the gateway: not listed, and keeps the built-in entry of the same id out too. */
76
+ hidden?: boolean;
75
77
  }
76
78
  /**
77
79
  * 拉取网关下发给编码客户端的模型清单(公开接口,无需鉴权):每个工具的模型、名称、说明、
78
80
  * 上下文窗口与压缩阈值,站长改了即时生效。老网关没有这个接口,任何失败都返回 null,
79
- * 调用方回退到 models.json 里的内置清单。隐藏的模型直接丢弃。
81
+ * 调用方回退到 models.json 里的内置清单。隐藏的模型只留 id 和 `hidden` 标记:不列出,
82
+ * 也挡住内置清单里的同名条目。
80
83
  */
81
84
  export declare function fetchClientModelConfig(options?: {
82
85
  timeoutMs?: number;
@@ -1 +1 @@
1
- import{logger as e}from"../utils/logger.js";import{configManager as t}from"./config.js";import{i18n as r}from"./i18n.js";import{rememberPublishedAddresses as o}from"./gateway-addresses.js";const n=e=>new Promise(t=>setTimeout(t,e));async function a(e,o,n){const a=`${t.getBaseUrl()}/v1/models`,s=new AbortController,l=setTimeout(()=>s.abort(),o);try{const t=await n(a,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:s.signal});if(401===t.status)return{valid:!1,error:"invalid_api_key",message:"API Key is invalid or expired"};if(t.ok){try{const e=await t.json();if(e&&"list"===e.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${t.status}: ${t.statusText}`}}catch(e){return e instanceof Error&&"AbortError"===e.name?{valid:!1,error:"network_error",message:"Request timeout"}:function(e){const t=e?.cause?.code;return"string"==typeof t&&i.has(t)}(e)?{valid:!1,error:"network_error",message:r.t("messages.certificate_intercepted",{url:a})}:{valid:!1,error:"network_error",message:e instanceof Error?e.message:"Network connection failed"}}finally{clearTimeout(l)}}const i=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(r,o={}){const{timeoutMs:n=3e4,fetchFn:a=fetch}=o,i=`${t.getBaseUrl()}/v1/models`,s=new AbortController,l=setTimeout(()=>s.abort(),n);try{const e=await a(i,{method:"GET",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},signal:s.signal});if(!e.ok)return{ok:!1,models:[],error:`HTTP ${e.status}`};const t=await e.json();return{ok:!0,models:(Array.isArray(t?.data)?t.data:[]).map(e=>"string"==typeof e?e:e?.id).filter(e=>"string"==typeof e&&e.trim().length>0).map(e=>e.trim())}}catch(t){return e.logError("fetchModels",t),{ok:!1,models:[],error:t instanceof Error?t.message:"network error"}}finally{clearTimeout(l)}}function s(e){return e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.name).map(e=>({name:e.name.trim(),..."string"==typeof e.labelOverride?{labelOverride:e.labelOverride}:{},..."boolean"==typeof e.supports1m?{supports1m:e.supports1m}:{}})).filter(e=>e.name.length>0)}export async function fetchGatewayStatus(r={}){const{timeoutMs:n=15e3,fetchFn:a=fetch}=r,i=`${t.getBaseUrl()}/api/status`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await a(i,{method:"GET",signal:l.signal});if(!e.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${e.status}`};const r=await e.json();o(r?.data,t.getBaseUrl());let n=r?.data?.claude_desktop_group_models;if("string"==typeof n)try{n=JSON.parse(n)}catch{n=void 0}const c={};if(n&&"object"==typeof n&&!Array.isArray(n))for(const[e,t]of Object.entries(n))Array.isArray(t)&&(c[e]=s(t));return{ok:!0,claudeDesktopGroupModels:c}}catch(t){return e.logError("fetchGatewayStatus",t),{ok:!1,claudeDesktopGroupModels:{},error:t instanceof Error?t.message:"network error"}}finally{clearTimeout(c)}}export async function fetchKeyGroupInfo(r,o={}){const{timeoutMs:n=1e4,fetchFn:a=fetch}=o,i=`${t.getBaseUrl()}/api/platform/vibecode/key`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await a(i,{method:"GET",headers:{Authorization:`Bearer ${r}`},signal:l.signal});if(!e.ok)return null;const t=await e.json(),o=t?.data;if(!o||"string"!=typeof o.group||!Array.isArray(o.claude_desktop_models))return null;const n=Array.isArray(o.groups)?o.groups.filter(e=>"string"==typeof e&&!!e):[];return{group:o.group,groups:n.length>0?n:[o.group],claudeDesktopModels:s(o.claude_desktop_models)}}catch(t){return e.logError("fetchKeyGroupInfo",t),null}finally{clearTimeout(c)}}function l(e){return"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0}export async function fetchClientModelConfig(r={}){const{timeoutMs:o=1e4,fetchFn:n=fetch}=r,a=`${t.getBaseUrl()}/api/platform/vibecode/config`,i=new AbortController,s=setTimeout(()=>i.abort(),o);try{const e=await n(a,{method:"GET",signal:i.signal});if(!e.ok)return null;const t=await e.json(),r=t?.data?.models;if(!r||"object"!=typeof r||Array.isArray(r))return null;const o={};for(const[e,t]of Object.entries(r))Array.isArray(t)&&(o[e]=t.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.id).filter(e=>!0!==e.hidden&&e.id.trim().length>0).map(e=>{const t={id:e.id.trim()};"string"==typeof e.name&&e.name.trim()&&(t.name=e.name.trim()),"string"==typeof e.description&&e.description.trim()&&(t.description=e.description.trim());const r=l(e.context_window);r&&(t.contextWindow=r);const o=l(e.auto_compact_tokens);return o&&(t.autoCompactTokens=o),t}));return o}catch(t){return e.logError("fetchClientModelConfig",t),null}finally{clearTimeout(s)}}export async function validateApiKey(t,r={}){const{timeoutMs:o=3e4,retries:i=2,backoffMs:s=500,fetchFn:l=fetch,sleepFn:c=n}=r;let u={valid:!1,error:"network_error",message:"Network connection failed"};for(let r=0;r<=i;r++){const n=await a(t,o,l);if(n.valid||"invalid_api_key"===n.error)return n.valid||e.logError("validateApiKey",new Error(n.message||"invalid_api_key")),n;u=n,r<i&&await c(s*Math.pow(2,r))}return e.logError("validateApiKey",new Error(u.message||"network_error")),u}
1
+ import{logger as e}from"../utils/logger.js";import{configManager as t}from"./config.js";import{i18n as r}from"./i18n.js";import{rememberPublishedAddresses as o}from"./gateway-addresses.js";const n=e=>new Promise(t=>setTimeout(t,e));async function a(e,o,n){const a=`${t.getBaseUrl()}/v1/models`,s=new AbortController,l=setTimeout(()=>s.abort(),o);try{const t=await n(a,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:s.signal});if(401===t.status)return{valid:!1,error:"invalid_api_key",message:"API Key is invalid or expired"};if(t.ok){try{const e=await t.json();if(e&&"list"===e.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${t.status}: ${t.statusText}`}}catch(e){return e instanceof Error&&"AbortError"===e.name?{valid:!1,error:"network_error",message:"Request timeout"}:function(e){const t=e?.cause?.code;return"string"==typeof t&&i.has(t)}(e)?{valid:!1,error:"network_error",message:r.t("messages.certificate_intercepted",{url:a})}:{valid:!1,error:"network_error",message:e instanceof Error?e.message:"Network connection failed"}}finally{clearTimeout(l)}}const i=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(r,o={}){const{timeoutMs:n=3e4,fetchFn:a=fetch}=o,i=`${t.getBaseUrl()}/v1/models`,s=new AbortController,l=setTimeout(()=>s.abort(),n);try{const e=await a(i,{method:"GET",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},signal:s.signal});if(!e.ok)return{ok:!1,models:[],error:`HTTP ${e.status}`};const t=await e.json();return{ok:!0,models:(Array.isArray(t?.data)?t.data:[]).map(e=>"string"==typeof e?e:e?.id).filter(e=>"string"==typeof e&&e.trim().length>0).map(e=>e.trim())}}catch(t){return e.logError("fetchModels",t),{ok:!1,models:[],error:t instanceof Error?t.message:"network error"}}finally{clearTimeout(l)}}function s(e){return e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.name).map(e=>({name:e.name.trim(),..."string"==typeof e.labelOverride?{labelOverride:e.labelOverride}:{},..."boolean"==typeof e.supports1m?{supports1m:e.supports1m}:{}})).filter(e=>e.name.length>0)}export async function fetchGatewayStatus(r={}){const{timeoutMs:n=15e3,fetchFn:a=fetch}=r,i=`${t.getBaseUrl()}/api/status`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await a(i,{method:"GET",signal:l.signal});if(!e.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${e.status}`};const r=await e.json();o(r?.data,t.getBaseUrl());let n=r?.data?.claude_desktop_group_models;if("string"==typeof n)try{n=JSON.parse(n)}catch{n=void 0}const c={};if(n&&"object"==typeof n&&!Array.isArray(n))for(const[e,t]of Object.entries(n))Array.isArray(t)&&(c[e]=s(t));return{ok:!0,claudeDesktopGroupModels:c}}catch(t){return e.logError("fetchGatewayStatus",t),{ok:!1,claudeDesktopGroupModels:{},error:t instanceof Error?t.message:"network error"}}finally{clearTimeout(c)}}export async function fetchKeyGroupInfo(r,o={}){const{timeoutMs:n=1e4,fetchFn:a=fetch}=o,i=`${t.getBaseUrl()}/api/platform/vibecode/key`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await a(i,{method:"GET",headers:{Authorization:`Bearer ${r}`},signal:l.signal});if(!e.ok)return null;const t=await e.json(),o=t?.data;if(!o||"string"!=typeof o.group||!Array.isArray(o.claude_desktop_models))return null;const n=Array.isArray(o.groups)?o.groups.filter(e=>"string"==typeof e&&!!e):[];return{group:o.group,groups:n.length>0?n:[o.group],claudeDesktopModels:s(o.claude_desktop_models)}}catch(t){return e.logError("fetchKeyGroupInfo",t),null}finally{clearTimeout(c)}}function l(e){return"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):void 0}export async function fetchClientModelConfig(r={}){const{timeoutMs:o=1e4,fetchFn:n=fetch}=r,a=`${t.getBaseUrl()}/api/platform/vibecode/config`,i=new AbortController,s=setTimeout(()=>i.abort(),o);try{const e=await n(a,{method:"GET",signal:i.signal});if(!e.ok)return null;const t=await e.json(),r=t?.data?.models;if(!r||"object"!=typeof r||Array.isArray(r))return null;const o={};for(const[e,t]of Object.entries(r))Array.isArray(t)&&(o[e]=t.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.id).filter(e=>e.id.trim().length>0).map(e=>{const t={id:e.id.trim()};if(!0===e.hidden)return{...t,hidden:!0};"string"==typeof e.name&&e.name.trim()&&(t.name=e.name.trim()),"string"==typeof e.description&&e.description.trim()&&(t.description=e.description.trim());const r=l(e.context_window);r&&(t.contextWindow=r);const o=l(e.auto_compact_tokens);return o&&(t.autoCompactTokens=o),t}));return o}catch(t){return e.logError("fetchClientModelConfig",t),null}finally{clearTimeout(s)}}export async function validateApiKey(t,r={}){const{timeoutMs:o=3e4,retries:i=2,backoffMs:s=500,fetchFn:l=fetch,sleepFn:c=n}=r;let u={valid:!1,error:"network_error",message:"Network connection failed"};for(let r=0;r<=i;r++){const n=await a(t,o,l);if(n.valid||"invalid_api_key"===n.error)return n.valid||e.logError("validateApiKey",new Error(n.message||"invalid_api_key")),n;u=n,r<i&&await c(s*Math.pow(2,r))}return e.logError("validateApiKey",new Error(u.message||"network_error")),u}
@@ -10,10 +10,12 @@ export type GatewayModelTool = 'codex' | 'claude-code';
10
10
  export declare function autoCompactTokens(window: number, explicit?: number): number;
11
11
  /**
12
12
  * The models to add for `tool`. When the gateway publishes its client config
13
- * (`/api/platform/vibecode/config`) its lists win — fields it leaves out keep the
14
- * built-in values, and Claude models only come from it when `models.json` lists
13
+ * (`/api/platform/vibecode/config`) its lists come first — fields it leaves out keep
14
+ * the built-in values, and Claude models only come from it when `models.json` lists
15
15
  * them too (so a model removed there, like Haiku for Codex, stays out); Codex also
16
- * gets the `gemini` list. Otherwise the built-in list from `models.json` → `gatewayModels`.
16
+ * gets the `gemini` list. Built-in entries the lists lack are added (see
17
+ * `withBuiltInExtras`); a `hidden` row on the gateway keeps one out. Without the
18
+ * config, the built-in list from `models.json` → `gatewayModels`.
17
19
  */
18
20
  export declare function gatewayModelSpecs(tool: GatewayModelTool, clientModels?: Record<string, GatewayClientModel[]>): GatewayModelSpec[];
19
21
  /**
@@ -1 +1 @@
1
- import{getGatewayModelRules as t}from"./model-registry.js";export function autoCompactTokens(e,o){return o&&o>0?Math.min(o,e):Math.floor(e*t().autoCompactRatio)}export function gatewayModelSpecs(e,o){const i=t().models,n=i.filter(t=>function(t,e){return"codex"===t?!1!==e.codex:!e.id.startsWith("claude-")&&!1!==e.claudeCode}(e,t));if(!o)return n;const r=new Map(("claude-code"===e?i:n).map(t=>[t.id,t])),s=(o.gemini??[]).filter(t=>!1!==i.find(e=>e.id===t.id)?.codex),d="codex"===e?[...o.codex??[],...s,...(o.claude??[]).filter(t=>t.id.startsWith("claude-")&&r.has(t.id))]:function(t,e){return[...(t.codex??[]).filter(t=>"gpt"===modelFamily(t.id)),...t.gemini??[],...t.grok??[],...(t.claude??[]).filter(t=>!t.id.startsWith("claude-"))].filter(t=>e.get(t.id)?.claudeCode??!0)}(o,r);if(0===d.length)return n;const c=new Set,l=[];for(const t of d)c.has(t.id)||(c.add(t.id),l.push({...r.get(t.id),...t}));return l}const e={gpt:"GPT",gemini:"Gemini",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function modelBlurb(t,e={}){const o=[];for(const i of(t??"").split("|")){const t=i.trim();t&&(/\d\s*万?\s*输出|output\D*\d|\d\D*output/i.test(t)||(/[\d百千]\s*万?\s*上下文|context\D*\d|\d\D*context/i.test(t)?e.millionContext&&!o.includes("百万上下文")&&o.unshift("百万上下文"):o.push(t)))}return e.millionContext&&!o.includes("百万上下文")&&o.unshift("百万上下文"),o.length>0?o.join(" | "):void 0}export function prettyModelName(t){const o=t.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),i=[];for(const t of o){const o=i[i.length-1];if(/^\d+$/.test(t)&&o&&/^\d+$/.test(o)&&t.length<=2&&!/^\d{8}$/.test(t)){i[i.length-1]=`${o}.${t}`;continue}const n=t.toLowerCase();i.push(e[n]??(/^[a-z]\d/i.test(t)?t.toUpperCase():t[0].toUpperCase()+t.slice(1)))}return i.join(" ")}export function vendorNames(t){return[...new Set(t.map(t=>prettyModelName(t).split(" ")[0]))]}export function modelFamily(t){const e=t.toLowerCase();return e.startsWith("claude-")?"claude":e.startsWith("gemini")?"gemini":e.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(e)?"gpt":"other"}
1
+ import{getGatewayModelRules as t}from"./model-registry.js";export function autoCompactTokens(e,i){return i&&i>0?Math.min(i,e):Math.floor(e*t().autoCompactRatio)}export function gatewayModelSpecs(e,i){const o=t().models,n=o.filter(t=>function(t,e){return"codex"===t?!1!==e.codex:!e.id.startsWith("claude-")&&!1!==e.claudeCode}(e,t));if(!i)return n;const d=new Set(Object.values(i).flat().filter(t=>t.hidden).map(t=>t.id)),r=Object.fromEntries(Object.entries(i).map(([t,e])=>[t,e.filter(t=>!t.hidden)])),s=new Map(("claude-code"===e?o:n).map(t=>[t.id,t])),l=(r.gemini??[]).filter(t=>!1!==o.find(e=>e.id===t.id)?.codex),a="codex"===e?[...r.codex??[],...l,...(r.claude??[]).filter(t=>t.id.startsWith("claude-")&&s.has(t.id))]:function(t,e){return[...(t.codex??[]).filter(t=>"gpt"===modelFamily(t.id)),...t.gemini??[],...t.grok??[],...(t.claude??[]).filter(t=>!t.id.startsWith("claude-"))].filter(t=>e.get(t.id)?.claudeCode??!0)}(r,s);if(0===a.length)return n.filter(t=>!d.has(t.id));const c=new Set,u=[];for(const t of a)c.has(t.id)||(c.add(t.id),u.push({...s.get(t.id),...t}));return function(t,e,i){const o=[...t];return e.forEach((t,n)=>{if(i.has(t.id)||o.some(e=>e.id===t.id))return;const d=modelFamily(t.id),r=new Set(e.slice(n+1).filter(t=>modelFamily(t.id)===d).map(t=>t.id));let s=o.findIndex(t=>r.has(t.id));if(s<0){s=o.length;for(let t=o.length-1;t>=0;t--)if(modelFamily(o[t].id)===d){s=t+1;break}}o.splice(s,0,t)}),o}(u,n,d)}const e={gpt:"GPT",gemini:"Gemini",glm:"GLM",deepseek:"DeepSeek",minimax:"MiniMax",qwen:"Qwen"};export function modelBlurb(t,e={}){const i=[];for(const o of(t??"").split("|")){const t=o.trim();t&&(/\d\s*万?\s*输出|output\D*\d|\d\D*output/i.test(t)||(/[\d百千]\s*万?\s*上下文|context\D*\d|\d\D*context/i.test(t)?e.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"):i.push(t)))}return e.millionContext&&!i.includes("百万上下文")&&i.unshift("百万上下文"),i.length>0?i.join(" | "):void 0}export function prettyModelName(t){const i=t.replace(/^([a-z]+)(\d)/i,"$1 $2").split(/[-_\s]+/).filter(Boolean),o=[];for(const t of i){const i=o[o.length-1];if(/^\d+$/.test(t)&&i&&/^\d+$/.test(i)&&t.length<=2&&!/^\d{8}$/.test(t)){o[o.length-1]=`${i}.${t}`;continue}const n=t.toLowerCase();o.push(e[n]??(/^[a-z]\d/i.test(t)?t.toUpperCase():t[0].toUpperCase()+t.slice(1)))}return o.join(" ")}export function vendorNames(t){return[...new Set(t.map(t=>prettyModelName(t).split(" ")[0]))]}export function modelFamily(t){const e=t.toLowerCase();return e.startsWith("claude-")?"claude":e.startsWith("gemini")?"gemini":e.startsWith("grok")?"grok":/^(gpt|o\d|codex)/.test(e)?"gpt":"other"}
package/dist/models.json CHANGED
@@ -190,6 +190,12 @@
190
190
  "codex": false,
191
191
  "claudeCode": false
192
192
  },
193
+ {
194
+ "id": "gemini-4-argon",
195
+ "name": "Gemini 4 Argon",
196
+ "description": "105 万上下文 | 旗舰推理 | 编码与 Agent",
197
+ "contextWindow": 1048576
198
+ },
193
199
  {
194
200
  "id": "gemini-3.8-flash",
195
201
  "name": "Gemini 3.8 Flash",
package/models.json CHANGED
@@ -190,6 +190,12 @@
190
190
  "codex": false,
191
191
  "claudeCode": false
192
192
  },
193
+ {
194
+ "id": "gemini-4-argon",
195
+ "name": "Gemini 4 Argon",
196
+ "description": "105 万上下文 | 旗舰推理 | 编码与 Agent",
197
+ "contextWindow": 1048576
198
+ },
193
199
  {
194
200
  "id": "gemini-3.8-flash",
195
201
  "name": "Gemini 3.8 Flash",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",