@adversity/coding-tool-x 3.1.1 → 3.1.3
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.
- package/CHANGELOG.md +41 -0
- package/dist/web/assets/Analytics-BIqc8Rin.css +1 -0
- package/dist/web/assets/Analytics-D2V09DHH.js +39 -0
- package/dist/web/assets/{ConfigTemplates-ZrK_s7ma.js → ConfigTemplates-Bf_11LhH.js} +1 -1
- package/dist/web/assets/Home-BRnW4FTS.js +1 -0
- package/dist/web/assets/Home-CyCIx4BA.css +1 -0
- package/dist/web/assets/{PluginManager-BD7QUZbU.js → PluginManager-B9J32GhW.js} +1 -1
- package/dist/web/assets/{ProjectList-DRb1DuHV.js → ProjectList-5a19MWJk.js} +1 -1
- package/dist/web/assets/SessionList-CXUr6S7w.css +1 -0
- package/dist/web/assets/SessionList-Cxg5bAdT.js +1 -0
- package/dist/web/assets/{SkillManager-C1xG5B4Q.js → SkillManager-CVBr0CLi.js} +1 -1
- package/dist/web/assets/{Terminal-DksBo_lM.js → Terminal-D2Xe_Q0H.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Burx7XOo.js → WorkspaceManager-C7dwV94C.js} +1 -1
- package/dist/web/assets/icons-BxcwoY5F.js +1 -0
- package/dist/web/assets/index-BS9RA6SN.js +2 -0
- package/dist/web/assets/index-DUNAVDGb.css +1 -0
- package/dist/web/assets/naive-ui-BIXcURHZ.js +1 -0
- package/dist/web/assets/{vendors-CO3Upi1d.js → vendors-i5CBGnlm.js} +1 -1
- package/dist/web/assets/{vue-vendor-DqyWIXEb.js → vue-vendor-PKd8utv_.js} +1 -1
- package/dist/web/index.html +6 -6
- package/package.json +1 -1
- package/src/config/default.js +7 -27
- package/src/config/loader.js +6 -3
- package/src/config/model-metadata.js +167 -0
- package/src/config/model-metadata.json +125 -0
- package/src/config/model-pricing.js +23 -93
- package/src/server/api/channels.js +16 -39
- package/src/server/api/codex-channels.js +15 -43
- package/src/server/api/commands.js +0 -77
- package/src/server/api/config.js +4 -1
- package/src/server/api/gemini-channels.js +16 -40
- package/src/server/api/opencode-channels.js +108 -56
- package/src/server/api/opencode-proxy.js +42 -33
- package/src/server/api/opencode-sessions.js +4 -69
- package/src/server/api/sessions.js +11 -68
- package/src/server/api/settings.js +138 -0
- package/src/server/api/skills.js +0 -44
- package/src/server/api/statistics.js +115 -1
- package/src/server/codex-proxy-server.js +32 -59
- package/src/server/gemini-proxy-server.js +21 -18
- package/src/server/index.js +13 -7
- package/src/server/opencode-proxy-server.js +1232 -197
- package/src/server/proxy-server.js +8 -8
- package/src/server/services/codex-sessions.js +105 -6
- package/src/server/services/commands-service.js +0 -29
- package/src/server/services/config-templates-service.js +38 -28
- package/src/server/services/env-checker.js +97 -9
- package/src/server/services/env-manager.js +29 -1
- package/src/server/services/opencode-channels.js +3 -1
- package/src/server/services/opencode-sessions.js +486 -218
- package/src/server/services/opencode-settings-manager.js +172 -36
- package/src/server/services/plugins-service.js +37 -28
- package/src/server/services/pty-manager.js +22 -18
- package/src/server/services/response-decoder.js +21 -0
- package/src/server/services/skill-service.js +1 -49
- package/src/server/services/speed-test.js +40 -3
- package/src/server/services/statistics-service.js +238 -1
- package/src/server/utils/pricing.js +51 -60
- package/src/server/websocket-server.js +24 -5
- package/dist/web/assets/Home-B8YfhZ3c.js +0 -1
- package/dist/web/assets/Home-Di2qsylF.css +0 -1
- package/dist/web/assets/SessionList-BGJWyneI.css +0 -1
- package/dist/web/assets/SessionList-lZ0LKzfT.js +0 -1
- package/dist/web/assets/icons-kcfLIMBB.js +0 -1
- package/dist/web/assets/index-Ufv5rCa5.css +0 -1
- package/dist/web/assets/index-lAkrRC3h.js +0 -2
- package/dist/web/assets/naive-ui-CSrLusZZ.js +0 -1
- package/src/server/api/convert.js +0 -260
- package/src/server/services/session-converter.js +0 -577
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as t,c as e,a as n}from"./markdown-C9MYpaSi.js";import{S as r}from"./vue-vendor-
|
|
1
|
+
import{g as t,c as e,a as n}from"./markdown-C9MYpaSi.js";import{S as r}from"./vue-vendor-PKd8utv_.js";var o={exports:{}};
|
|
2
2
|
/**!
|
|
3
3
|
* Sortable 1.14.0
|
|
4
4
|
* @author RubaXa <trash@rubaxa.org>
|
|
@@ -42,4 +42,4 @@ let lc;const cc=e=>lc=e,ac=Symbol();function uc(e){return e&&"object"==typeof e&
|
|
|
42
42
|
* vue-router v4.6.4
|
|
43
43
|
* (c) 2025 Eduardo San Martin Morote
|
|
44
44
|
* @license MIT
|
|
45
|
-
*/(e,t);n=Pa(o.reverse(),"beforeRouteLeave",e,t);for(const s of o)s.leaveGuards.forEach(o=>{n.push(Na(o,e,t))});const c=y.bind(null,e,t);return n.push(c),M(n).then(()=>{n=[];for(const o of s.list())n.push(Na(o,e,t));return n.push(c),M(n)}).then(()=>{n=Pa(r,"beforeRouteUpdate",e,t);for(const o of r)o.updateGuards.forEach(o=>{n.push(Na(o,e,t))});return n.push(c),M(n)}).then(()=>{n=[];for(const o of l)if(o.beforeEnter)if(Ic(o.beforeEnter))for(const r of o.beforeEnter)n.push(Na(r,e,t));else n.push(Na(o.beforeEnter,e,t));return n.push(c),M(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Pa(l,"beforeRouteEnter",e,t,b),n.push(c),M(n))).then(()=>{n=[];for(const o of i.list())n.push(Na(o,e,t));return n.push(c),M(n)}).catch(e=>Ea(e,_a.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function S(e,t,n){l.list().forEach(o=>b(()=>o(e,t,n)))}function C(e,t,n,o,s){const i=g(e,t);if(i)return i;const l=t===la,a=kc?history.state:{};n&&(o||l?r.replace(e.fullPath,Rc({scroll:l&&a&&a.scroll},s)):r.push(e.fullPath,s)),c.value=e,N(e,t,n,l),R()}let w;function x(){w||(w=r.listen((e,t,n)=>{if(!L.listening)return;const o=d(e),s=v(o,L.currentRoute.value);if(s)return void _(Rc(s,{replace:!0,force:!0}),o).catch(Pc);a=o;const i=c.value;var l,u;kc&&(l=ga(i.fullPath,n.delta),u=da(),ma.set(l,u)),E(o,i).catch(e=>Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_CANCELLED)?e:Ea(e,_a.NAVIGATION_GUARD_REDIRECT)?(_(Rc(h(e.to),{force:!0}),o).then(e=>{Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===ca.pop&&r.go(-1,!1)}).catch(Pc),Promise.reject()):(n.delta&&r.go(-n.delta,!1),O(e,o,i))).then(e=>{(e=e||C(o,i,!1))&&(n.delta&&!Ea(e,_a.NAVIGATION_CANCELLED)?r.go(-n.delta,!1):n.type===ca.pop&&Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),S(o,i,e)}).catch(Pc)}))}let A,T=Ra(),k=Ra();function O(e,t,n){R(e);const o=k.list();return o.length&&o.forEach(o=>o(e,t,n)),Promise.reject(e)}function R(e){return A||(A=!e,x(),T.list().forEach(([t,n])=>e?n(e):t()),T.reset()),e}function N(t,n,o,r){const{scrollBehavior:s}=e;if(!kc||!s)return Promise.resolve();const i=!o&&function(e){const t=ma.get(e);return ma.delete(e),t}(ga(t.fullPath,0))||(r||!o)&&history.state&&history.state.scroll||null;return un().then(()=>s(t,n,i)).then(e=>e&&ha(e)).catch(e=>O(e,t,n))}const P=e=>r.go(e);let I;const D=new Set,L={currentRoute:c,listening:!0,addRoute:function(e,n){let o,r;return va(e)?(o=t.getRecordMatcher(e),r=n):r=e,t.addRoute(r,o)},removeRoute:function(e){const n=t.getRecordMatcher(e);n&&t.removeRoute(n)},clearRoutes:t.clearRoutes,hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map(e=>e.record)},resolve:d,options:e,push:m,replace:function(e){return m(Rc(h(e),{replace:!0}))},go:P,back:()=>P(-1),forward:()=>P(1),beforeEach:s.add,beforeResolve:i.add,afterEach:l.add,onError:k.add,isReady:function(){return A&&c.value!==la?Promise.resolve():new Promise((e,t)=>{T.add([e,t])})},install(e){e.component("RouterLink",ru),e.component("RouterView",cu),e.config.globalProperties.$router=L,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>Lt(c)}),kc&&!I&&c.value===la&&(I=!0,m(r.location).catch(e=>{}));const t={};for(const o in la)Object.defineProperty(t,o,{get:()=>c.value[o],enumerable:!0});e.provide(Ta,L),e.provide(ka,_t(t)),e.provide(Oa,c);const n=e.unmount;D.add(e),e.unmount=function(){D.delete(e),D.size<1&&(a=la,w&&w(),w=null,c.value=la,I=!1,A=!1),n()}}};function M(e){return e.reduce((e,t)=>e.then(()=>b(t)),Promise.resolve())}return L}function uu(){return Tn(Ta)}function fu(e){return Tn(ka)}const pu=e(ic);export{er as $,Pt as A,Nn as B,_s as C,Ni as D,wl as E,ms as F,qi as G,Ms as H,vs as I,Tt as J,Ho as K,K as L,tc as M,Lt as N,xt as O,At as P,Ut as Q,B as R,pu as S,Kn as T,au as U,Ma as V,js as W,Ds as X,Cn as Y,Kl as Z,Z as _,Is as a,ks as a0,Ac as a1,tr as a2,Xo as a3,Tc as a4,fu as a5,uu as a6,zl as a7,Yo as a8,ko as a9,dc as aa,Vs as b,Ts as c,ao as d,yt as e,fi as f,Ys as g,jo as h,$o as i,Vo as j,vt as k,Tn as l,Ro as m,No as n,Ss as o,Fs as p,An as q,Nt as r,wn as s,pi as t,Ht as u,un as v,In as w,nr as x,Hs as y,Os as z};
|
|
45
|
+
*/(e,t);n=Pa(o.reverse(),"beforeRouteLeave",e,t);for(const s of o)s.leaveGuards.forEach(o=>{n.push(Na(o,e,t))});const c=y.bind(null,e,t);return n.push(c),M(n).then(()=>{n=[];for(const o of s.list())n.push(Na(o,e,t));return n.push(c),M(n)}).then(()=>{n=Pa(r,"beforeRouteUpdate",e,t);for(const o of r)o.updateGuards.forEach(o=>{n.push(Na(o,e,t))});return n.push(c),M(n)}).then(()=>{n=[];for(const o of l)if(o.beforeEnter)if(Ic(o.beforeEnter))for(const r of o.beforeEnter)n.push(Na(r,e,t));else n.push(Na(o.beforeEnter,e,t));return n.push(c),M(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Pa(l,"beforeRouteEnter",e,t,b),n.push(c),M(n))).then(()=>{n=[];for(const o of i.list())n.push(Na(o,e,t));return n.push(c),M(n)}).catch(e=>Ea(e,_a.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function S(e,t,n){l.list().forEach(o=>b(()=>o(e,t,n)))}function C(e,t,n,o,s){const i=g(e,t);if(i)return i;const l=t===la,a=kc?history.state:{};n&&(o||l?r.replace(e.fullPath,Rc({scroll:l&&a&&a.scroll},s)):r.push(e.fullPath,s)),c.value=e,N(e,t,n,l),R()}let w;function x(){w||(w=r.listen((e,t,n)=>{if(!L.listening)return;const o=d(e),s=v(o,L.currentRoute.value);if(s)return void _(Rc(s,{replace:!0,force:!0}),o).catch(Pc);a=o;const i=c.value;var l,u;kc&&(l=ga(i.fullPath,n.delta),u=da(),ma.set(l,u)),E(o,i).catch(e=>Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_CANCELLED)?e:Ea(e,_a.NAVIGATION_GUARD_REDIRECT)?(_(Rc(h(e.to),{force:!0}),o).then(e=>{Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===ca.pop&&r.go(-1,!1)}).catch(Pc),Promise.reject()):(n.delta&&r.go(-n.delta,!1),O(e,o,i))).then(e=>{(e=e||C(o,i,!1))&&(n.delta&&!Ea(e,_a.NAVIGATION_CANCELLED)?r.go(-n.delta,!1):n.type===ca.pop&&Ea(e,_a.NAVIGATION_ABORTED|_a.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),S(o,i,e)}).catch(Pc)}))}let A,T=Ra(),k=Ra();function O(e,t,n){R(e);const o=k.list();return o.length&&o.forEach(o=>o(e,t,n)),Promise.reject(e)}function R(e){return A||(A=!e,x(),T.list().forEach(([t,n])=>e?n(e):t()),T.reset()),e}function N(t,n,o,r){const{scrollBehavior:s}=e;if(!kc||!s)return Promise.resolve();const i=!o&&function(e){const t=ma.get(e);return ma.delete(e),t}(ga(t.fullPath,0))||(r||!o)&&history.state&&history.state.scroll||null;return un().then(()=>s(t,n,i)).then(e=>e&&ha(e)).catch(e=>O(e,t,n))}const P=e=>r.go(e);let I;const D=new Set,L={currentRoute:c,listening:!0,addRoute:function(e,n){let o,r;return va(e)?(o=t.getRecordMatcher(e),r=n):r=e,t.addRoute(r,o)},removeRoute:function(e){const n=t.getRecordMatcher(e);n&&t.removeRoute(n)},clearRoutes:t.clearRoutes,hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map(e=>e.record)},resolve:d,options:e,push:m,replace:function(e){return m(Rc(h(e),{replace:!0}))},go:P,back:()=>P(-1),forward:()=>P(1),beforeEach:s.add,beforeResolve:i.add,afterEach:l.add,onError:k.add,isReady:function(){return A&&c.value!==la?Promise.resolve():new Promise((e,t)=>{T.add([e,t])})},install(e){e.component("RouterLink",ru),e.component("RouterView",cu),e.config.globalProperties.$router=L,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>Lt(c)}),kc&&!I&&c.value===la&&(I=!0,m(r.location).catch(e=>{}));const t={};for(const o in la)Object.defineProperty(t,o,{get:()=>c.value[o],enumerable:!0});e.provide(Ta,L),e.provide(ka,_t(t)),e.provide(Oa,c);const n=e.unmount;D.add(e),e.unmount=function(){D.delete(e),D.size<1&&(a=la,w&&w(),w=null,c.value=la,I=!1,A=!1),n()}}};function M(e){return e.reduce((e,t)=>e.then(()=>b(t)),Promise.resolve())}return L}function uu(){return Tn(Ta)}function fu(e){return Tn(ka)}const pu=e(ic);export{er as $,Pt as A,Nn as B,_s as C,Ni as D,wl as E,ms as F,qi as G,Ms as H,vs as I,Tt as J,Ho as K,K as L,tc as M,Lt as N,xt as O,At as P,Ut as Q,B as R,pu as S,Kn as T,au as U,Ma as V,js as W,Ds as X,Cn as Y,Kl as Z,Z as _,Is as a,ks as a0,Ac as a1,tr as a2,Xo as a3,Tc as a4,fu as a5,uu as a6,zl as a7,Yo as a8,ko as a9,dc as aa,Rt as ab,Vs as b,Ts as c,ao as d,yt as e,fi as f,Ys as g,jo as h,$o as i,Vo as j,vt as k,Tn as l,Ro as m,No as n,Ss as o,Fs as p,An as q,Nt as r,wn as s,pi as t,Ht as u,un as v,In as w,nr as x,Hs as y,Os as z};
|
package/dist/web/index.html
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
<link rel="icon" href="/favicon.ico">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>CC-TOOL - ClaudeCode增强工作助手</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-BS9RA6SN.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/markdown-C9MYpaSi.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/vue-vendor-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/vendors-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/naive-ui-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/icons-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/vue-vendor-PKd8utv_.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/vendors-i5CBGnlm.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/naive-ui-BIXcURHZ.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/icons-BxcwoY5F.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/markdown-BfC0goYb.css">
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DUNAVDGb.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="app"></div>
|
package/package.json
CHANGED
package/src/config/default.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// 默认配置
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
|
+
const modelMetadataConfig = require('./model-metadata.json');
|
|
4
5
|
|
|
5
6
|
const DEFAULT_CONFIG = {
|
|
6
7
|
projectsDir: path.join(os.homedir(), '.claude', 'projects'),
|
|
@@ -17,36 +18,15 @@ const DEFAULT_CONFIG = {
|
|
|
17
18
|
},
|
|
18
19
|
maxLogs: 100,
|
|
19
20
|
statsInterval: 30,
|
|
20
|
-
defaultModels: {
|
|
21
|
-
claude: [
|
|
22
|
-
'claude-opus-4-6',
|
|
23
|
-
'claude-sonnet-4-6',
|
|
24
|
-
'claude-opus-4-5-20251101',
|
|
25
|
-
'claude-sonnet-4-5-20250929',
|
|
26
|
-
'claude-haiku-4-5-20251001'
|
|
27
|
-
],
|
|
28
|
-
codex: [
|
|
29
|
-
'gpt-5.2-codex',
|
|
30
|
-
'gpt-5.1-codex-max',
|
|
31
|
-
'gpt-5.1-codex',
|
|
32
|
-
'gpt-5.1-codex-mini',
|
|
33
|
-
'gpt-5-codex',
|
|
34
|
-
'gpt-5.2',
|
|
35
|
-
'gpt-5.1',
|
|
36
|
-
'gpt-5'
|
|
37
|
-
],
|
|
38
|
-
gemini: [
|
|
39
|
-
'gemini-3-pro-preview',
|
|
40
|
-
'gemini-3-flash-preview',
|
|
41
|
-
'gemini-2.5-pro',
|
|
42
|
-
'gemini-2.5-flash',
|
|
43
|
-
'gemini-2.5-flash-lite'
|
|
44
|
-
]
|
|
45
|
-
},
|
|
46
21
|
modelDiscovery: {
|
|
47
|
-
// 是否优先使用 /v1/models 获取可用模型;默认关闭,直接走默认模型探测
|
|
48
22
|
useV1ModelsEndpoint: false
|
|
49
23
|
},
|
|
24
|
+
defaultModels: modelMetadataConfig.defaultModels || { claude: [], codex: [], gemini: [] },
|
|
25
|
+
defaultSpeedTestModels: modelMetadataConfig.defaultSpeedTestModels || {
|
|
26
|
+
claude: 'claude-haiku-4-5',
|
|
27
|
+
codex: 'gpt-5.2',
|
|
28
|
+
gemini: 'gemini-2.5-pro'
|
|
29
|
+
},
|
|
50
30
|
pricing: {
|
|
51
31
|
claude: {
|
|
52
32
|
mode: 'auto',
|
package/src/config/loader.js
CHANGED
|
@@ -49,9 +49,9 @@ function mergeDefaultModels(defaultModels, overrides = {}) {
|
|
|
49
49
|
return merged;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
52
|
+
function mergeDefaultSpeedTestModels(defaultModels, overrides = {}) {
|
|
53
53
|
return {
|
|
54
|
-
...
|
|
54
|
+
...defaultModels,
|
|
55
55
|
...(overrides || {})
|
|
56
56
|
};
|
|
57
57
|
}
|
|
@@ -99,7 +99,10 @@ function loadConfig() {
|
|
|
99
99
|
config.ports = { ...DEFAULT_CONFIG.ports, ...userConfig.ports };
|
|
100
100
|
config.pricing = mergePricing(DEFAULT_CONFIG.pricing, userConfig.pricing);
|
|
101
101
|
config.defaultModels = mergeDefaultModels(DEFAULT_CONFIG.defaultModels, userConfig.defaultModels);
|
|
102
|
-
config.
|
|
102
|
+
config.defaultSpeedTestModels = mergeDefaultSpeedTestModels(
|
|
103
|
+
DEFAULT_CONFIG.defaultSpeedTestModels,
|
|
104
|
+
userConfig.defaultSpeedTestModels
|
|
105
|
+
);
|
|
103
106
|
|
|
104
107
|
// 确保有 currentProject,使用 defaultProject 作为 currentProject
|
|
105
108
|
if (!config.currentProject && config.defaultProject) {
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model metadata runtime helpers.
|
|
3
|
+
* Data source: ./model-metadata.json
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const metadataConfig = require('./model-metadata.json');
|
|
9
|
+
const METADATA_FILE_PATH = path.join(__dirname, 'model-metadata.json');
|
|
10
|
+
|
|
11
|
+
const MODEL_METADATA = metadataConfig.models || {};
|
|
12
|
+
const MODEL_ALIASES = metadataConfig.aliases || {};
|
|
13
|
+
const DEFAULT_MODELS = metadataConfig.defaultModels || { claude: [], codex: [], gemini: [] };
|
|
14
|
+
const DEFAULT_SPEED_TEST_MODELS = metadataConfig.defaultSpeedTestModels || {
|
|
15
|
+
claude: 'claude-haiku-4-5',
|
|
16
|
+
codex: 'gpt-5.2',
|
|
17
|
+
gemini: 'gemini-2.5-pro'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function normalizeNonEmptyString(value) {
|
|
21
|
+
if (typeof value !== 'string') return null;
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
return trimmed || null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function loadMetadataConfigFromFile() {
|
|
27
|
+
try {
|
|
28
|
+
const raw = fs.readFileSync(METADATA_FILE_PATH, 'utf8');
|
|
29
|
+
const parsed = JSON.parse(raw);
|
|
30
|
+
if (parsed && typeof parsed === 'object') {
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.warn(`[model-metadata] Failed to read metadata file, fallback to in-memory config: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
return metadataConfig;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve model metadata (limit + pricing) for a given model ID.
|
|
41
|
+
* Supports: exact match -> alias match -> prefix match -> generic Claude fallback
|
|
42
|
+
*
|
|
43
|
+
* @param {string} modelId
|
|
44
|
+
* @returns {{ limit: {context, output}, pricing: {input, output, cacheCreation?, cacheRead?} } | null}
|
|
45
|
+
*/
|
|
46
|
+
function resolveModelMetadata(modelId) {
|
|
47
|
+
if (!modelId) return null;
|
|
48
|
+
const id = String(modelId).toLowerCase().trim();
|
|
49
|
+
|
|
50
|
+
// Exact match
|
|
51
|
+
for (const [key, meta] of Object.entries(MODEL_METADATA)) {
|
|
52
|
+
if (id === key.toLowerCase()) return meta;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Alias match -> canonical
|
|
56
|
+
for (const [alias, canonical] of Object.entries(MODEL_ALIASES)) {
|
|
57
|
+
if (id === alias.toLowerCase()) {
|
|
58
|
+
const meta = MODEL_METADATA[canonical];
|
|
59
|
+
if (meta) return meta;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Prefix match
|
|
64
|
+
for (const [key, meta] of Object.entries(MODEL_METADATA)) {
|
|
65
|
+
if (id.startsWith(key.toLowerCase())) return meta;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Generic fallback for unknown Claude models
|
|
69
|
+
if (id.startsWith('claude-')) {
|
|
70
|
+
return {
|
|
71
|
+
limit: { context: 200000, output: 32000 },
|
|
72
|
+
pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveModelLimit(modelId) {
|
|
80
|
+
const meta = resolveModelMetadata(modelId);
|
|
81
|
+
return meta ? meta.limit : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveModelPricing(modelId) {
|
|
85
|
+
const meta = resolveModelMetadata(modelId);
|
|
86
|
+
return meta ? meta.pricing : null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getAllModelIds() {
|
|
90
|
+
return Object.keys(MODEL_METADATA);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getDefaultModels() {
|
|
94
|
+
return {
|
|
95
|
+
claude: [...(DEFAULT_MODELS.claude || [])],
|
|
96
|
+
codex: [...(DEFAULT_MODELS.codex || [])],
|
|
97
|
+
gemini: [...(DEFAULT_MODELS.gemini || [])]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getDefaultModelsByToolType(toolType) {
|
|
102
|
+
const key = String(toolType || '').trim().toLowerCase();
|
|
103
|
+
if (key === 'openai_compatible') return [...(DEFAULT_MODELS.codex || [])];
|
|
104
|
+
if (key === 'claude' || key === 'codex' || key === 'gemini') {
|
|
105
|
+
return [...(DEFAULT_MODELS[key] || [])];
|
|
106
|
+
}
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getDefaultSpeedTestModels() {
|
|
111
|
+
const fileConfig = loadMetadataConfigFromFile();
|
|
112
|
+
const raw = fileConfig.defaultSpeedTestModels || DEFAULT_SPEED_TEST_MODELS;
|
|
113
|
+
return {
|
|
114
|
+
claude: normalizeNonEmptyString(raw.claude) || DEFAULT_SPEED_TEST_MODELS.claude,
|
|
115
|
+
codex: normalizeNonEmptyString(raw.codex) || DEFAULT_SPEED_TEST_MODELS.codex,
|
|
116
|
+
gemini: normalizeNonEmptyString(raw.gemini) || DEFAULT_SPEED_TEST_MODELS.gemini
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function getDefaultSpeedTestModelByToolType(toolType) {
|
|
121
|
+
const key = String(toolType || '').trim().toLowerCase();
|
|
122
|
+
const defaults = getDefaultSpeedTestModels();
|
|
123
|
+
if (key === 'openai_compatible') return defaults.codex;
|
|
124
|
+
if (key === 'claude' || key === 'codex' || key === 'gemini') {
|
|
125
|
+
return defaults[key];
|
|
126
|
+
}
|
|
127
|
+
return defaults.codex;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function saveDefaultSpeedTestModels(nextDefaults) {
|
|
131
|
+
const current = loadMetadataConfigFromFile();
|
|
132
|
+
const merged = {
|
|
133
|
+
...getDefaultSpeedTestModels(),
|
|
134
|
+
...(nextDefaults || {})
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const normalized = {
|
|
138
|
+
claude: normalizeNonEmptyString(merged.claude) || DEFAULT_SPEED_TEST_MODELS.claude,
|
|
139
|
+
codex: normalizeNonEmptyString(merged.codex) || DEFAULT_SPEED_TEST_MODELS.codex,
|
|
140
|
+
gemini: normalizeNonEmptyString(merged.gemini) || DEFAULT_SPEED_TEST_MODELS.gemini
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const nextConfig = {
|
|
144
|
+
...current,
|
|
145
|
+
defaultSpeedTestModels: normalized
|
|
146
|
+
};
|
|
147
|
+
fs.writeFileSync(METADATA_FILE_PATH, `${JSON.stringify(nextConfig, null, 2)}\n`, 'utf8');
|
|
148
|
+
metadataConfig.defaultSpeedTestModels = normalized;
|
|
149
|
+
return normalized;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = {
|
|
153
|
+
MODEL_METADATA,
|
|
154
|
+
MODEL_ALIASES,
|
|
155
|
+
DEFAULT_MODELS,
|
|
156
|
+
DEFAULT_SPEED_TEST_MODELS,
|
|
157
|
+
resolveModelMetadata,
|
|
158
|
+
resolveModelLimit,
|
|
159
|
+
resolveModelPricing,
|
|
160
|
+
getAllModelIds,
|
|
161
|
+
getDefaultModels,
|
|
162
|
+
getDefaultModelsByToolType,
|
|
163
|
+
getDefaultSpeedTestModels,
|
|
164
|
+
getDefaultSpeedTestModelByToolType,
|
|
165
|
+
saveDefaultSpeedTestModels,
|
|
166
|
+
METADATA_LAST_UPDATED: metadataConfig.lastUpdated || '2026-02-27'
|
|
167
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lastUpdated": "2026-02-27",
|
|
3
|
+
"defaultModels": {
|
|
4
|
+
"claude": [
|
|
5
|
+
"claude-opus-4-6",
|
|
6
|
+
"claude-sonnet-4-6",
|
|
7
|
+
"claude-opus-4-5-20251101",
|
|
8
|
+
"claude-sonnet-4-5-20250929",
|
|
9
|
+
"claude-haiku-4-5-20251001"
|
|
10
|
+
],
|
|
11
|
+
"codex": [
|
|
12
|
+
"gpt-5.3-codex",
|
|
13
|
+
"gpt-5.2-codex",
|
|
14
|
+
"gpt-5.1-codex-max",
|
|
15
|
+
"gpt-5.1-codex",
|
|
16
|
+
"gpt-5.1-codex-mini",
|
|
17
|
+
"gpt-5-codex",
|
|
18
|
+
"gpt-5.2",
|
|
19
|
+
"gpt-5.1",
|
|
20
|
+
"gpt-5"
|
|
21
|
+
],
|
|
22
|
+
"gemini": [
|
|
23
|
+
"gemini-3.1-pro",
|
|
24
|
+
"gemini-3-pro-preview",
|
|
25
|
+
"gemini-3-flash-preview",
|
|
26
|
+
"gemini-2.5-pro",
|
|
27
|
+
"gemini-2.5-flash",
|
|
28
|
+
"gemini-2.5-flash-lite"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"defaultSpeedTestModels": {
|
|
32
|
+
"claude": "claude-haiku-4-5",
|
|
33
|
+
"codex": "gpt-5.2",
|
|
34
|
+
"gemini": "gemini-2.5-pro"
|
|
35
|
+
},
|
|
36
|
+
"aliases": {
|
|
37
|
+
"claude-opus-4-6": "claude-opus-4-6",
|
|
38
|
+
"claude-sonnet-4-6": "claude-sonnet-4-6",
|
|
39
|
+
"claude-opus-4-5": "claude-opus-4-5-20251101",
|
|
40
|
+
"claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
|
|
41
|
+
"claude-haiku-4-5": "claude-haiku-4-5-20251001"
|
|
42
|
+
},
|
|
43
|
+
"models": {
|
|
44
|
+
"claude-opus-4-6": {
|
|
45
|
+
"limit": { "context": 200000, "output": 32000 },
|
|
46
|
+
"pricing": { "input": 15, "output": 75, "cacheCreation": 18.75, "cacheRead": 1.5 }
|
|
47
|
+
},
|
|
48
|
+
"claude-sonnet-4-6": {
|
|
49
|
+
"limit": { "context": 200000, "output": 64000 },
|
|
50
|
+
"pricing": { "input": 3, "output": 15, "cacheCreation": 3.75, "cacheRead": 0.3 }
|
|
51
|
+
},
|
|
52
|
+
"claude-opus-4-5-20251101": {
|
|
53
|
+
"limit": { "context": 200000, "output": 32000 },
|
|
54
|
+
"pricing": { "input": 5, "output": 25, "cacheCreation": 6.25, "cacheRead": 0.5 }
|
|
55
|
+
},
|
|
56
|
+
"claude-sonnet-4-5-20250929": {
|
|
57
|
+
"limit": { "context": 200000, "output": 64000 },
|
|
58
|
+
"pricing": { "input": 3, "output": 15, "cacheCreation": 3.75, "cacheRead": 0.3 }
|
|
59
|
+
},
|
|
60
|
+
"claude-haiku-4-5-20251001": {
|
|
61
|
+
"limit": { "context": 200000, "output": 8096 },
|
|
62
|
+
"pricing": { "input": 1, "output": 5, "cacheCreation": 1.25, "cacheRead": 0.1 }
|
|
63
|
+
},
|
|
64
|
+
"gpt-5": {
|
|
65
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
66
|
+
"pricing": { "input": 2, "output": 8 }
|
|
67
|
+
},
|
|
68
|
+
"gpt-5.1": {
|
|
69
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
70
|
+
"pricing": { "input": 2, "output": 8 }
|
|
71
|
+
},
|
|
72
|
+
"gpt-5.2": {
|
|
73
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
74
|
+
"pricing": { "input": 2, "output": 8 }
|
|
75
|
+
},
|
|
76
|
+
"gpt-5-codex": {
|
|
77
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
78
|
+
"pricing": { "input": 2, "output": 8 }
|
|
79
|
+
},
|
|
80
|
+
"gpt-5.1-codex": {
|
|
81
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
82
|
+
"pricing": { "input": 2, "output": 8 }
|
|
83
|
+
},
|
|
84
|
+
"gpt-5.1-codex-mini": {
|
|
85
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
86
|
+
"pricing": { "input": 1.5, "output": 6 }
|
|
87
|
+
},
|
|
88
|
+
"gpt-5.1-codex-max": {
|
|
89
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
90
|
+
"pricing": { "input": 3, "output": 12 }
|
|
91
|
+
},
|
|
92
|
+
"gpt-5.2-codex": {
|
|
93
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
94
|
+
"pricing": { "input": 2, "output": 8 }
|
|
95
|
+
},
|
|
96
|
+
"gpt-5.3-codex": {
|
|
97
|
+
"limit": { "context": 1000000, "output": 32768 },
|
|
98
|
+
"pricing": { "input": 2, "output": 8 }
|
|
99
|
+
},
|
|
100
|
+
"gemini-3.1-pro": {
|
|
101
|
+
"limit": { "context": 2097152, "output": 65536 },
|
|
102
|
+
"pricing": { "input": 2.5, "output": 15 }
|
|
103
|
+
},
|
|
104
|
+
"gemini-3-pro-preview": {
|
|
105
|
+
"limit": { "context": 2097152, "output": 65536 },
|
|
106
|
+
"pricing": { "input": 2.5, "output": 15 }
|
|
107
|
+
},
|
|
108
|
+
"gemini-3-flash-preview": {
|
|
109
|
+
"limit": { "context": 1048576, "output": 65536 },
|
|
110
|
+
"pricing": { "input": 0.3, "output": 1.2 }
|
|
111
|
+
},
|
|
112
|
+
"gemini-2.5-pro": {
|
|
113
|
+
"limit": { "context": 1048576, "output": 65536 },
|
|
114
|
+
"pricing": { "input": 1.25, "output": 10 }
|
|
115
|
+
},
|
|
116
|
+
"gemini-2.5-flash": {
|
|
117
|
+
"limit": { "context": 1048576, "output": 65536 },
|
|
118
|
+
"pricing": { "input": 0.15, "output": 0.6 }
|
|
119
|
+
},
|
|
120
|
+
"gemini-2.5-flash-lite": {
|
|
121
|
+
"limit": { "context": 1048576, "output": 65536 },
|
|
122
|
+
"pricing": { "input": 0.1, "output": 0.4 }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,105 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Claude Model Pricing - Backward Compatibility Re-export
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* All prices in USD per million tokens
|
|
4
|
+
* This file re-exports Claude-specific pricing and aliases from the centralized
|
|
5
|
+
* model-metadata.js config. Use model-metadata.js directly for new code.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
|
-
const
|
|
11
|
-
// Claude 4.5 (current generation)
|
|
12
|
-
'claude-opus-4-5-20250929': {
|
|
13
|
-
input: 5,
|
|
14
|
-
output: 25,
|
|
15
|
-
cacheCreation: 6.25,
|
|
16
|
-
cacheRead: 0.50
|
|
17
|
-
},
|
|
18
|
-
'claude-sonnet-4-5-20250929': {
|
|
19
|
-
input: 3,
|
|
20
|
-
output: 15,
|
|
21
|
-
cacheCreation: 3.75,
|
|
22
|
-
cacheRead: 0.30
|
|
23
|
-
},
|
|
24
|
-
'claude-haiku-4-5-20250929': {
|
|
25
|
-
input: 1,
|
|
26
|
-
output: 5,
|
|
27
|
-
cacheCreation: 1.25,
|
|
28
|
-
cacheRead: 0.10
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
// Claude 4 (previous generation)
|
|
32
|
-
'claude-opus-4-20250514': {
|
|
33
|
-
input: 5,
|
|
34
|
-
output: 25,
|
|
35
|
-
cacheCreation: 6.25,
|
|
36
|
-
cacheRead: 0.50
|
|
37
|
-
},
|
|
38
|
-
'claude-sonnet-4-20250514': {
|
|
39
|
-
input: 3,
|
|
40
|
-
output: 15,
|
|
41
|
-
cacheCreation: 3.75,
|
|
42
|
-
cacheRead: 0.30
|
|
43
|
-
},
|
|
8
|
+
const { MODEL_METADATA, MODEL_ALIASES, METADATA_LAST_UPDATED } = require('./model-metadata');
|
|
44
9
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
cacheCreation: 1.25,
|
|
56
|
-
cacheRead: 0.10
|
|
57
|
-
},
|
|
58
|
-
'claude-sonnet-3-5-20241022': {
|
|
59
|
-
input: 3,
|
|
60
|
-
output: 15,
|
|
61
|
-
cacheCreation: 3.75,
|
|
62
|
-
cacheRead: 0.30
|
|
63
|
-
},
|
|
64
|
-
'claude-sonnet-3-5-20240620': {
|
|
65
|
-
input: 3,
|
|
66
|
-
output: 15,
|
|
67
|
-
cacheCreation: 3.75,
|
|
68
|
-
cacheRead: 0.30
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
// Claude 3 (legacy)
|
|
72
|
-
'claude-opus-3-20240229': {
|
|
73
|
-
input: 15,
|
|
74
|
-
output: 75,
|
|
75
|
-
cacheCreation: 18.75,
|
|
76
|
-
cacheRead: 1.50
|
|
77
|
-
},
|
|
78
|
-
'claude-3-opus-20240229': {
|
|
79
|
-
input: 15,
|
|
80
|
-
output: 75,
|
|
81
|
-
cacheCreation: 18.75,
|
|
82
|
-
cacheRead: 1.50
|
|
10
|
+
// Build CLAUDE_MODEL_PRICING from centralized metadata (Claude models only)
|
|
11
|
+
const CLAUDE_MODEL_PRICING = {};
|
|
12
|
+
for (const [id, meta] of Object.entries(MODEL_METADATA)) {
|
|
13
|
+
if (id.startsWith('claude-') && meta.pricing) {
|
|
14
|
+
CLAUDE_MODEL_PRICING[id] = {
|
|
15
|
+
input: meta.pricing.input,
|
|
16
|
+
output: meta.pricing.output,
|
|
17
|
+
cacheCreation: meta.pricing.cacheCreation,
|
|
18
|
+
cacheRead: meta.pricing.cacheRead
|
|
19
|
+
};
|
|
83
20
|
}
|
|
84
|
-
}
|
|
21
|
+
}
|
|
85
22
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
'claude-haiku-4-5': 'claude-haiku-4-5-20250929',
|
|
94
|
-
'claude-opus-4': 'claude-opus-4-20250514',
|
|
95
|
-
'claude-sonnet-4': 'claude-sonnet-4-20250514',
|
|
96
|
-
'claude-haiku-3-5': 'claude-haiku-3-5-20241022',
|
|
97
|
-
'claude-sonnet-3-5': 'claude-sonnet-3-5-20241022',
|
|
98
|
-
'claude-opus-3': 'claude-opus-3-20240229'
|
|
99
|
-
};
|
|
23
|
+
// Build CLAUDE_MODEL_ALIASES from centralized aliases (Claude models only)
|
|
24
|
+
const CLAUDE_MODEL_ALIASES = {};
|
|
25
|
+
for (const [alias, canonical] of Object.entries(MODEL_ALIASES)) {
|
|
26
|
+
if (alias.startsWith('claude-')) {
|
|
27
|
+
CLAUDE_MODEL_ALIASES[alias] = canonical;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
100
30
|
|
|
101
31
|
module.exports = {
|
|
102
32
|
CLAUDE_MODEL_PRICING,
|
|
103
33
|
CLAUDE_MODEL_ALIASES,
|
|
104
|
-
PRICING_LAST_UPDATED:
|
|
34
|
+
PRICING_LAST_UPDATED: METADATA_LAST_UPDATED
|
|
105
35
|
};
|
|
@@ -18,14 +18,15 @@ const {
|
|
|
18
18
|
sanitizeBatchConcurrency,
|
|
19
19
|
runWithConcurrencyLimit
|
|
20
20
|
} = require('../services/speed-test');
|
|
21
|
-
const {
|
|
22
|
-
probeModelAvailability,
|
|
23
|
-
fetchModelsFromProvider
|
|
24
|
-
} = require('../services/model-detector');
|
|
21
|
+
const { getDefaultSpeedTestModelByToolType } = require('../../config/model-metadata');
|
|
25
22
|
const { broadcastLog, broadcastProxyState, broadcastSchedulerState } = require('../websocket-server');
|
|
26
23
|
const { clearRedirectCache } = require('../proxy-server');
|
|
27
24
|
const CLAUDE_GATEWAY_SOURCE_TYPE = 'claude';
|
|
28
25
|
|
|
26
|
+
function getDefaultClaudeModel() {
|
|
27
|
+
return getDefaultSpeedTestModelByToolType('claude');
|
|
28
|
+
}
|
|
29
|
+
|
|
29
30
|
// GET /api/channels - Get all channels with health status
|
|
30
31
|
router.get('/', (req, res) => {
|
|
31
32
|
try {
|
|
@@ -271,41 +272,17 @@ router.get('/:id/models', async (req, res) => {
|
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
const gatewaySourceType = CLAUDE_GATEWAY_SOURCE_TYPE;
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
error: null,
|
|
286
|
-
errorHint: null
|
|
287
|
-
};
|
|
288
|
-
} else {
|
|
289
|
-
const usingConfiguredProbe = !!listResult.disabledByConfig;
|
|
290
|
-
const probe = await probeModelAvailability(channel, gatewaySourceType, {
|
|
291
|
-
stopOnFirstAvailable: false
|
|
292
|
-
});
|
|
293
|
-
const probedModels = Array.isArray(probe.availableModels) ? probe.availableModels : [];
|
|
294
|
-
|
|
295
|
-
result = {
|
|
296
|
-
models: probedModels,
|
|
297
|
-
supported: probedModels.length > 0,
|
|
298
|
-
cached: !!probe.cached || !!listResult.cached,
|
|
299
|
-
fallbackUsed: probedModels.length > 0,
|
|
300
|
-
lastChecked: probe.lastChecked || listResult.lastChecked || new Date().toISOString(),
|
|
301
|
-
error: probedModels.length > 0 ? null : (listResult.error || '无法获取可用模型'),
|
|
302
|
-
errorHint: probedModels.length > 0
|
|
303
|
-
? (usingConfiguredProbe ? '已按设置跳过 /v1/models,使用默认模型探测结果' : '模型列表接口不可用,已使用模型探测结果')
|
|
304
|
-
: (listResult.errorHint || (usingConfiguredProbe
|
|
305
|
-
? '已按设置跳过 /v1/models,且默认模型探测无可用结果'
|
|
306
|
-
: '模型列表接口不可用且模型探测无可用结果'))
|
|
307
|
-
};
|
|
308
|
-
}
|
|
275
|
+
const models = [getDefaultClaudeModel()];
|
|
276
|
+
const now = new Date().toISOString();
|
|
277
|
+
const result = {
|
|
278
|
+
models,
|
|
279
|
+
supported: models.length > 0,
|
|
280
|
+
cached: false,
|
|
281
|
+
fallbackUsed: false,
|
|
282
|
+
lastChecked: now,
|
|
283
|
+
error: models.length > 0 ? null : '未配置默认模型列表',
|
|
284
|
+
errorHint: models.length > 0 ? null : '请在设置中配置 Claude 默认模型'
|
|
285
|
+
};
|
|
309
286
|
|
|
310
287
|
res.json({
|
|
311
288
|
channelId: id,
|