@vibeapi/cli 0.0.77 → 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
|
|
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
|
|
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.
|
|
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,
|
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeapi/cli",
|
|
3
|
-
"version": "0.0.
|
|
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",
|