@goodandready/dsh-clinebot 0.4.7 → 0.5.0
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 +24 -0
- package/lib/client.js +411 -53
- package/lib/cline-client.js +1 -2
- package/lib/config.js +21 -3
- package/lib/http.js +1 -1
- package/lib/index.js +38 -1
- package/lib/models.js +33 -8
- package/lib/provider-sync.js +50 -25
- package/lib/routes/auth.js +1 -1
- package/lib/routes/proxy.js +290 -0
- package/lib/routes/settings.js +34 -0
- package/lib/session-router.js +236 -0
- package/lib/slash-command.js +1 -3
- package/lib/stats-storage.js +217 -0
- package/package.json +1 -1
package/lib/cline-client.js
CHANGED
|
@@ -26,7 +26,7 @@ export const DEFAULT_BASE_URL = 'https://api.cline.bot/api/v1'
|
|
|
26
26
|
export const DEFAULT_API_KEY_ENV = 'CLINEBOT_API_KEY'
|
|
27
27
|
export const DEFAULT_TIMEOUT_MS = 15000
|
|
28
28
|
export const DEFAULT_SMOKE_TIMEOUT_MS = 25000
|
|
29
|
-
|
|
29
|
+
const USAGE_CACHE_TTL_MS = 60000
|
|
30
30
|
|
|
31
31
|
export { PROVIDER_ID, PROVIDER_DISPLAY_NAME, DEFAULT_MODEL_ID }
|
|
32
32
|
|
|
@@ -508,4 +508,3 @@ export function buildPiAiProvider({
|
|
|
508
508
|
|
|
509
509
|
|
|
510
510
|
|
|
511
|
-
export { resolveAccountPool, isAccountQuotaExhausted, rotateToNextAccount, getLastRotation, setLastRotation, isQuotaExceededError } from './account-pool.js'
|
package/lib/config.js
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
getActiveModelIds,
|
|
13
13
|
} from './models.js'
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
// DSH settings.describe only publishes fields marked volatile. Without them the
|
|
17
16
|
// namespace is omitted and the configuration page stays unavailable.
|
|
18
17
|
if (typeof z.prototype?.volatile !== 'function') {
|
|
@@ -58,6 +57,21 @@ export const Config = z.object({
|
|
|
58
57
|
maxTokens: z.number().default(8192),
|
|
59
58
|
})).default([])
|
|
60
59
|
.description('Custom user-defined model context length and max token overrides.').volatile(),
|
|
60
|
+
modelReasoningDefaults: z.dict(z.string()).default({})
|
|
61
|
+
.description('Configured default reasoning effort per model (low, medium, high, max).').volatile(),
|
|
62
|
+
customModels: z.array(z.object({
|
|
63
|
+
id: z.string(),
|
|
64
|
+
name: z.string(),
|
|
65
|
+
contextLength: z.number().default(128000),
|
|
66
|
+
maxTokens: z.number().default(8192),
|
|
67
|
+
category: z.string().default('general'),
|
|
68
|
+
isReasoning: z.boolean().default(false),
|
|
69
|
+
})).default([])
|
|
70
|
+
.description('User-defined custom gateway models.').volatile(),
|
|
71
|
+
proxyMode: z.boolean().default(true)
|
|
72
|
+
.description('When true, registers local transparent loopback proxy for failover and token tracking.').volatile(),
|
|
73
|
+
statsPath: z.string().default('~/.dsh/clinebot-stats.json')
|
|
74
|
+
.description('Local on-disk persistent path for token usage analytics.').volatile(),
|
|
61
75
|
timeoutMs: z.number().default(DEFAULT_TIMEOUT_MS)
|
|
62
76
|
.description('HTTP probe timeout in milliseconds.').volatile(),
|
|
63
77
|
smokeTimeoutMs: z.number().default(DEFAULT_SMOKE_TIMEOUT_MS)
|
|
@@ -73,7 +87,6 @@ export const Config = z.object({
|
|
|
73
87
|
.description('Manually pinned active account envName or empty for auto/default.').volatile(),
|
|
74
88
|
})
|
|
75
89
|
|
|
76
|
-
|
|
77
90
|
function isVolatileRef(value) {
|
|
78
91
|
return !!value && typeof value === 'object' && !Array.isArray(value) && typeof value.get === 'function'
|
|
79
92
|
}
|
|
@@ -111,9 +124,10 @@ export function volatileConfig(cfg) {
|
|
|
111
124
|
export function publicConfig(cfg) {
|
|
112
125
|
cfg = plainConfig(cfg)
|
|
113
126
|
const dynamic = Array.isArray(cfg?.dynamicModels) ? cfg.dynamicModels : []
|
|
127
|
+
const custom = Array.isArray(cfg?.customModels) ? cfg.customModels : []
|
|
114
128
|
const modelContextOverrides = Array.isArray(cfg?.modelContextOverrides) ? cfg.modelContextOverrides : []
|
|
115
129
|
const isSynced = dynamic.length > 0
|
|
116
|
-
const allModels = getAllModels(dynamic, modelContextOverrides)
|
|
130
|
+
const allModels = getAllModels(dynamic, modelContextOverrides, custom)
|
|
117
131
|
const allDefaultIds = allModels.map((m) => m.id)
|
|
118
132
|
|
|
119
133
|
let disabledList = Array.isArray(cfg?.disabledModels) ? cfg.disabledModels : []
|
|
@@ -148,6 +162,10 @@ export function publicConfig(cfg) {
|
|
|
148
162
|
planSynced: isSynced,
|
|
149
163
|
planSyncedAt,
|
|
150
164
|
modelContextOverrides,
|
|
165
|
+
modelReasoningDefaults: cfg?.modelReasoningDefaults && typeof cfg.modelReasoningDefaults === 'object' ? cfg.modelReasoningDefaults : {},
|
|
166
|
+
customModels: custom,
|
|
167
|
+
proxyMode: cfg?.proxyMode !== false,
|
|
168
|
+
statsPath: String(cfg?.statsPath || '~/.dsh/clinebot-stats.json'),
|
|
151
169
|
disabledModels: disabledList,
|
|
152
170
|
enabledModels: activeIds,
|
|
153
171
|
timeoutMs: Number(cfg?.timeoutMs) || DEFAULT_TIMEOUT_MS,
|
package/lib/http.js
CHANGED
|
@@ -46,7 +46,7 @@ function header(request, name) {
|
|
|
46
46
|
return Array.isArray(value) ? value[0] : value
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function isLoopbackAddress(value) {
|
|
49
|
+
export function isLoopbackAddress(value) {
|
|
50
50
|
const address = String(value || '').toLowerCase().replace(/^\[|\]$/g, '')
|
|
51
51
|
return address === 'localhost' || address === 'localhost.' || address === '::1'
|
|
52
52
|
|| address.startsWith('127.')
|
package/lib/index.js
CHANGED
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
sessionStats,
|
|
5
5
|
recordSessionRequest,
|
|
6
6
|
resetSessionStats,
|
|
7
|
+
} from './cline-client.js'
|
|
8
|
+
import {
|
|
7
9
|
rotateToNextAccount,
|
|
8
10
|
isQuotaExceededError,
|
|
9
|
-
} from './
|
|
11
|
+
} from './account-pool.js'
|
|
10
12
|
import { PROVIDER_ID } from './models.js'
|
|
11
13
|
import {
|
|
12
14
|
upsertPiAiProvider,
|
|
@@ -18,7 +20,9 @@ import { registerSettingsRoutes } from './routes/settings.js'
|
|
|
18
20
|
import { registerAccountsRoutes } from './routes/accounts.js'
|
|
19
21
|
import { registerModelsRoutes } from './routes/models.js'
|
|
20
22
|
import { registerAuthRoutes } from './routes/auth.js'
|
|
23
|
+
import { registerProxyRoutes } from './routes/proxy.js'
|
|
21
24
|
import { registerSlashCommand } from './slash-command.js'
|
|
25
|
+
import { recordUsage } from './stats-storage.js'
|
|
22
26
|
|
|
23
27
|
export const name = '@goodandready/dsh-clinebot'
|
|
24
28
|
export const inject = ['webServer', 'credentials']
|
|
@@ -135,6 +139,7 @@ export function apply(ctx, config) {
|
|
|
135
139
|
registerAccountsRoutes(ctx, routeEnv)
|
|
136
140
|
registerModelsRoutes(ctx, routeEnv)
|
|
137
141
|
registerAuthRoutes(ctx, routeEnv)
|
|
142
|
+
registerProxyRoutes(ctx, routeEnv)
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
registerSlashCommand(ctx, {
|
|
@@ -198,6 +203,15 @@ export function apply(ctx, config) {
|
|
|
198
203
|
completionTokens,
|
|
199
204
|
model: options?.model,
|
|
200
205
|
})
|
|
206
|
+
recordUsage({
|
|
207
|
+
model: options?.model,
|
|
208
|
+
promptTokens,
|
|
209
|
+
completionTokens,
|
|
210
|
+
totalTokens: promptTokens + completionTokens,
|
|
211
|
+
isError: true,
|
|
212
|
+
is429,
|
|
213
|
+
statsPath: live().statsPath,
|
|
214
|
+
})
|
|
201
215
|
if (is429 || isExceeded) {
|
|
202
216
|
handleStream429()
|
|
203
217
|
}
|
|
@@ -218,6 +232,13 @@ export function apply(ctx, config) {
|
|
|
218
232
|
completionTokens,
|
|
219
233
|
model: options?.model,
|
|
220
234
|
})
|
|
235
|
+
recordUsage({
|
|
236
|
+
model: options?.model,
|
|
237
|
+
promptTokens,
|
|
238
|
+
completionTokens,
|
|
239
|
+
totalTokens: promptTokens + completionTokens,
|
|
240
|
+
statsPath: live().statsPath,
|
|
241
|
+
})
|
|
221
242
|
}
|
|
222
243
|
}
|
|
223
244
|
yield chunk
|
|
@@ -230,6 +251,13 @@ export function apply(ctx, config) {
|
|
|
230
251
|
completionTokens,
|
|
231
252
|
model: options?.model,
|
|
232
253
|
})
|
|
254
|
+
recordUsage({
|
|
255
|
+
model: options?.model,
|
|
256
|
+
promptTokens,
|
|
257
|
+
completionTokens,
|
|
258
|
+
totalTokens: promptTokens + completionTokens,
|
|
259
|
+
statsPath: live().statsPath,
|
|
260
|
+
})
|
|
233
261
|
}
|
|
234
262
|
} catch (err) {
|
|
235
263
|
if (isCline) {
|
|
@@ -244,6 +272,15 @@ export function apply(ctx, config) {
|
|
|
244
272
|
completionTokens,
|
|
245
273
|
model: options?.model,
|
|
246
274
|
})
|
|
275
|
+
recordUsage({
|
|
276
|
+
model: options?.model,
|
|
277
|
+
promptTokens,
|
|
278
|
+
completionTokens,
|
|
279
|
+
totalTokens: promptTokens + completionTokens,
|
|
280
|
+
isError: true,
|
|
281
|
+
is429: status === 429,
|
|
282
|
+
statsPath: live().statsPath,
|
|
283
|
+
})
|
|
247
284
|
if (status === 429 || isQuotaExceededError(msg)) {
|
|
248
285
|
handleStream429()
|
|
249
286
|
}
|
package/lib/models.js
CHANGED
|
@@ -20,7 +20,7 @@ export const OBSOLETE_MODEL_ID_MAP = Object.freeze({
|
|
|
20
20
|
'cline-pass/muse-spark-13-contributor': 'cline-pass/muse-spark-1.3-contributor',
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
function migrateModelId(id) {
|
|
24
24
|
if (typeof id !== 'string') return id
|
|
25
25
|
return OBSOLETE_MODEL_ID_MAP[id] || id
|
|
26
26
|
}
|
|
@@ -57,7 +57,7 @@ export function getOriginalModelContext(nameOrId) {
|
|
|
57
57
|
return 200000
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
function getOriginalModelProvider(nameOrId) {
|
|
61
61
|
const norm = String(nameOrId || '').toLowerCase()
|
|
62
62
|
if (norm.includes('kimi')) return 'Moonshot AI'
|
|
63
63
|
if (norm.includes('qwen')) return 'Alibaba Cloud'
|
|
@@ -336,7 +336,7 @@ export function parsePlanIncludedModels(includedInput) {
|
|
|
336
336
|
*
|
|
337
337
|
* Applies user-defined modelContextOverrides (custom contextLength and maxTokens).
|
|
338
338
|
*/
|
|
339
|
-
export function getAllModels(dynamicModels = [], modelContextOverrides = []) {
|
|
339
|
+
export function getAllModels(dynamicModels = [], modelContextOverrides = [], customModels = []) {
|
|
340
340
|
const normalizedDynamic = (Array.isArray(dynamicModels) ? dynamicModels : []).map(migrateModelEntry)
|
|
341
341
|
const overridesMap = new Map()
|
|
342
342
|
if (Array.isArray(modelContextOverrides)) {
|
|
@@ -374,9 +374,10 @@ export function getAllModels(dynamicModels = [], modelContextOverrides = []) {
|
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
+
let baseModels = []
|
|
377
378
|
if (normalizedDynamic.length > 0) {
|
|
378
379
|
const normalize = (s) => String(s || '').toLowerCase().replace(/[\s._-]+/g, '')
|
|
379
|
-
|
|
380
|
+
baseModels = normalizedDynamic.map((dm) => {
|
|
380
381
|
const targetNorm = normalize(dm.id.replace(/^cline-pass\//, ''))
|
|
381
382
|
const curated = CLINE_MODELS.find(
|
|
382
383
|
(cm) => cm.id === dm.id || normalize(cm.id.replace(/^cline-pass\//, '')) === targetNorm || normalize(cm.name) === targetNorm
|
|
@@ -407,23 +408,47 @@ export function getAllModels(dynamicModels = [], modelContextOverrides = []) {
|
|
|
407
408
|
unverified: false,
|
|
408
409
|
})
|
|
409
410
|
})
|
|
411
|
+
} else {
|
|
412
|
+
baseModels = CLINE_MODELS.map((m) => applyOverride({ ...m, unverified: true }))
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (Array.isArray(customModels) && customModels.length > 0) {
|
|
416
|
+
const existingIds = new Set(baseModels.map((m) => m.id))
|
|
417
|
+
for (const cm of customModels) {
|
|
418
|
+
if (cm && cm.id && !existingIds.has(cm.id)) {
|
|
419
|
+
const fullCustom = {
|
|
420
|
+
id: cm.id,
|
|
421
|
+
name: cm.name || cm.id,
|
|
422
|
+
description: cm.description || `Custom model ${cm.name || cm.id}`,
|
|
423
|
+
contextLength: cm.contextLength || 128000,
|
|
424
|
+
maxTokens: cm.maxTokens || 8192,
|
|
425
|
+
input: ['text'],
|
|
426
|
+
category: cm.category || 'general',
|
|
427
|
+
isCustom: true,
|
|
428
|
+
reasoningEfforts: cm.isReasoning ? ['low', 'medium', 'high', 'max'] : undefined,
|
|
429
|
+
unverified: false,
|
|
430
|
+
}
|
|
431
|
+
baseModels.push(applyOverride(fullCustom))
|
|
432
|
+
existingIds.add(cm.id)
|
|
433
|
+
}
|
|
434
|
+
}
|
|
410
435
|
}
|
|
411
436
|
|
|
412
|
-
return
|
|
437
|
+
return baseModels
|
|
413
438
|
}
|
|
414
439
|
|
|
415
|
-
|
|
440
|
+
function findModel(id, dynamicModels = [], modelContextOverrides = [], customModels = []) {
|
|
416
441
|
const all = getAllModels(dynamicModels, modelContextOverrides)
|
|
417
442
|
const found = all.find((m) => m.id === id)
|
|
418
443
|
if (found) return found
|
|
419
444
|
return CLINE_MODELS.find((m) => m.id === id) || null
|
|
420
445
|
}
|
|
421
446
|
|
|
422
|
-
export function isSupportedModel(id, dynamicModels = [], modelContextOverrides = []) {
|
|
447
|
+
export function isSupportedModel(id, dynamicModels = [], modelContextOverrides = [], customModels = []) {
|
|
423
448
|
return findModel(id, dynamicModels, modelContextOverrides) !== null
|
|
424
449
|
}
|
|
425
450
|
|
|
426
|
-
|
|
451
|
+
function getDefaultModelIds(dynamicModels = [], modelContextOverrides = [], customModels = []) {
|
|
427
452
|
return getAllModels(dynamicModels, modelContextOverrides).map((m) => m.id)
|
|
428
453
|
}
|
|
429
454
|
|
package/lib/provider-sync.js
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
import os from 'node:os'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import { publicConfig, plainConfig, Config, LLM_PI_AI_NS } from './config.js'
|
|
4
|
-
import { publicUsage } from './http.js'
|
|
5
3
|
import {
|
|
6
4
|
PROVIDER_ID,
|
|
7
5
|
PROVIDER_DISPLAY_NAME,
|
|
8
6
|
getAllModels,
|
|
9
|
-
loadModelsDiskCache,
|
|
10
7
|
saveModelsDiskCache,
|
|
8
|
+
loadModelsDiskCache,
|
|
9
|
+
OBSOLETE_MODEL_ID_MAP,
|
|
10
|
+
migrateModelEntry,
|
|
11
11
|
} from './models.js'
|
|
12
12
|
import {
|
|
13
|
-
resolveKeyValue,
|
|
14
|
-
resolveAccountPool,
|
|
15
13
|
probeHealth,
|
|
16
14
|
fetchUsageLimits,
|
|
17
|
-
buildPiAiProvider,
|
|
18
15
|
sessionStats,
|
|
19
|
-
getLastRotation,
|
|
20
16
|
usageCache,
|
|
17
|
+
buildPiAiProvider,
|
|
21
18
|
DEFAULT_API_KEY_ENV,
|
|
22
19
|
} from './cline-client.js'
|
|
20
|
+
import { publicConfig, plainConfig, Config, LLM_PI_AI_NS } from './config.js'
|
|
21
|
+
import { publicUsage } from './http.js'
|
|
22
|
+
import { resolveKeyValue } from './credential-refs.js'
|
|
23
|
+
import { resolveAccountPool, getLastRotation } from './account-pool.js'
|
|
23
24
|
|
|
24
25
|
export function resolvePathWithHome(p) {
|
|
25
|
-
if (
|
|
26
|
-
if (p === '~') return os.homedir()
|
|
27
|
-
if (p.startsWith('~/') || p.startsWith('~\\')) {
|
|
26
|
+
if (typeof p === 'string' && p.startsWith('~/')) {
|
|
28
27
|
return path.join(os.homedir(), p.slice(2))
|
|
29
28
|
}
|
|
30
29
|
return p
|
|
@@ -88,7 +87,7 @@ export async function buildStatus(ctx, cfg) {
|
|
|
88
87
|
])
|
|
89
88
|
|
|
90
89
|
const activeAcc = await resolveActiveAccountKey(ctx, cfg, pool)
|
|
91
|
-
const allModels = getAllModels(pub.dynamicModels, pub.modelContextOverrides)
|
|
90
|
+
const allModels = getAllModels(pub.dynamicModels, pub.modelContextOverrides, pub.customModels)
|
|
92
91
|
|
|
93
92
|
let usage = null
|
|
94
93
|
const keyToUse = activeAcc.value || key.value
|
|
@@ -97,19 +96,40 @@ export async function buildStatus(ctx, cfg) {
|
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
let quotaWarning = null
|
|
100
|
-
if (usage?.windows
|
|
101
|
-
const
|
|
102
|
-
|
|
99
|
+
if (usage?.windows) {
|
|
100
|
+
const fiveHour = usage.windows.fiveHour
|
|
101
|
+
const weekly = usage.windows.weekly
|
|
102
|
+
const monthly = usage.windows.monthly
|
|
103
|
+
|
|
104
|
+
if (fiveHour && typeof fiveHour.percentUsed === 'number') {
|
|
105
|
+
if (fiveHour.percentUsed >= 95) {
|
|
106
|
+
quotaWarning = {
|
|
107
|
+
level: 'exhausted',
|
|
108
|
+
message: `5-hour rolling limit is almost exhausted (${fiveHour.percentUsed}%). New requests may be rejected until quota reset.`,
|
|
109
|
+
resetsAt: fiveHour.resetsAt,
|
|
110
|
+
}
|
|
111
|
+
} else if (fiveHour.percentUsed >= 90) {
|
|
112
|
+
quotaWarning = {
|
|
113
|
+
level: 'warning',
|
|
114
|
+
message: `Low quota warning: ${fiveHour.percentUsed}% of 5-hour limit consumed (<10% remaining).`,
|
|
115
|
+
resetsAt: fiveHour.resetsAt,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!quotaWarning && weekly && typeof weekly.percentUsed === 'number' && weekly.percentUsed >= 90) {
|
|
103
121
|
quotaWarning = {
|
|
104
|
-
level: 'exhausted',
|
|
105
|
-
message: `
|
|
106
|
-
resetsAt:
|
|
122
|
+
level: weekly.percentUsed >= 99 ? 'exhausted' : 'warning',
|
|
123
|
+
message: `Low weekly quota warning: ${weekly.percentUsed}% consumed (${weekly.remainingPercent ?? (100 - weekly.percentUsed)}% remaining).`,
|
|
124
|
+
resetsAt: weekly.resetsAt,
|
|
107
125
|
}
|
|
108
|
-
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!quotaWarning && monthly && typeof monthly.percentUsed === 'number' && monthly.percentUsed >= 90) {
|
|
109
129
|
quotaWarning = {
|
|
110
|
-
level: 'warning',
|
|
111
|
-
message: `
|
|
112
|
-
resetsAt:
|
|
130
|
+
level: monthly.percentUsed >= 99 ? 'exhausted' : 'warning',
|
|
131
|
+
message: `Low monthly quota warning: ${monthly.percentUsed}% consumed (${monthly.remainingPercent ?? (100 - monthly.percentUsed)}% remaining).`,
|
|
132
|
+
resetsAt: monthly.resetsAt,
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
}
|
|
@@ -127,7 +147,7 @@ export async function buildStatus(ctx, cfg) {
|
|
|
127
147
|
accounts: pool.map((acc) => {
|
|
128
148
|
const cacheKey = `cline:usage:${(acc.value || '').slice(-8)}`
|
|
129
149
|
const cached = usageCache.get(cacheKey)?.data
|
|
130
|
-
const pct = cached?.windows?.fiveHour?.percentUsed
|
|
150
|
+
const pct = cached?.windows?.weekly?.percentUsed ?? cached?.windows?.monthly?.percentUsed ?? cached?.windows?.fiveHour?.percentUsed ?? null
|
|
131
151
|
return {
|
|
132
152
|
id: acc.id,
|
|
133
153
|
label: acc.label,
|
|
@@ -156,17 +176,22 @@ export async function upsertPiAiProvider(ctx, cfg, activeModelIds) {
|
|
|
156
176
|
}
|
|
157
177
|
|
|
158
178
|
const pub = publicConfig(cfg)
|
|
159
|
-
const allModels = getAllModels(pub.dynamicModels, pub.modelContextOverrides)
|
|
179
|
+
const allModels = getAllModels(pub.dynamicModels, pub.modelContextOverrides, pub.customModels)
|
|
160
180
|
const allowedSet = new Set(activeModelIds || pub.enabledModels)
|
|
161
181
|
const modelsToRegister = allModels.filter((m) => allowedSet.has(m.id))
|
|
162
182
|
|
|
163
183
|
const activeAcc = await resolveActiveAccountKey(ctx, cfg)
|
|
164
184
|
|
|
185
|
+
const port = ctx?.webServer?.port || process.env.PORT || 3080
|
|
186
|
+
const effectiveBaseUrl = pub.proxyMode !== false
|
|
187
|
+
? `http://127.0.0.1:${port}/dsh-clinebot/v1`
|
|
188
|
+
: pub.baseUrl
|
|
189
|
+
|
|
165
190
|
const providerObj = buildPiAiProvider({
|
|
166
|
-
baseUrl:
|
|
191
|
+
baseUrl: effectiveBaseUrl,
|
|
167
192
|
apiKeyEnv: activeAcc?.apiKeyEnv || pub.apiKeyEnv,
|
|
168
193
|
models: modelsToRegister.length ? modelsToRegister : allModels,
|
|
169
|
-
customModels: pub.dynamicModels,
|
|
194
|
+
customModels: [...(pub.dynamicModels || []), ...(pub.customModels || [])],
|
|
170
195
|
displayName: PROVIDER_DISPLAY_NAME,
|
|
171
196
|
})
|
|
172
197
|
|
package/lib/routes/auth.js
CHANGED
|
@@ -5,10 +5,10 @@ import { resolveActiveAccountKey } from '../provider-sync.js'
|
|
|
5
5
|
import {
|
|
6
6
|
smokeChat,
|
|
7
7
|
recordSmokeTest,
|
|
8
|
-
rotateToNextAccount,
|
|
9
8
|
DEFAULT_MODEL_ID,
|
|
10
9
|
normalizeBaseUrl,
|
|
11
10
|
} from '../cline-client.js'
|
|
11
|
+
import { rotateToNextAccount } from '../account-pool.js'
|
|
12
12
|
|
|
13
13
|
export function registerAuthRoutes(ctx, { live, getSettingsApi, syncProviderState }) {
|
|
14
14
|
// POST /dsh-clinebot/key/verify — on-the-fly verification of Cline API key
|