free-coding-models 0.2.15 → 0.3.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 +78 -0
- package/README.md +112 -39
- package/bin/fcm-proxy-daemon.js +239 -0
- package/bin/free-coding-models.js +105 -23
- package/package.json +3 -2
- package/src/account-manager.js +34 -0
- package/src/anthropic-translator.js +370 -0
- package/src/config.js +24 -1
- package/src/daemon-manager.js +527 -0
- package/src/endpoint-installer.js +187 -2
- package/src/key-handler.js +355 -150
- package/src/opencode.js +30 -32
- package/src/overlays.js +365 -225
- package/src/proxy-server.js +488 -6
- package/src/proxy-sync.js +552 -0
- package/src/proxy-topology.js +80 -0
- package/src/render-table.js +24 -15
- package/src/tool-launchers.js +138 -18
- package/src/tool-metadata.js +14 -14
package/src/opencode.js
CHANGED
|
@@ -39,12 +39,13 @@ import { join } from 'path'
|
|
|
39
39
|
import { copyFileSync, existsSync } from 'fs'
|
|
40
40
|
import { sources } from '../sources.js'
|
|
41
41
|
import { PROVIDER_COLOR } from './render-table.js'
|
|
42
|
-
import { resolveCloudflareUrl } from './ping.js'
|
|
43
42
|
import { ProxyServer } from './proxy-server.js'
|
|
44
43
|
import { loadOpenCodeConfig, saveOpenCodeConfig, syncToOpenCode } from './opencode-sync.js'
|
|
45
|
-
import { getApiKey, getProxySettings
|
|
44
|
+
import { getApiKey, getProxySettings } from './config.js'
|
|
46
45
|
import { ENV_VAR_NAMES, OPENCODE_MODEL_MAP, isWindows, isMac, isLinux } from './provider-metadata.js'
|
|
47
46
|
import { setActiveProxy } from './render-table.js'
|
|
47
|
+
import { buildProxyTopologyFromConfig as _buildTopology } from './proxy-topology.js'
|
|
48
|
+
import { isDaemonRunning, getDaemonInfo } from './daemon-manager.js'
|
|
48
49
|
|
|
49
50
|
// 📖 OpenCode config location: ~/.config/opencode/opencode.json on ALL platforms.
|
|
50
51
|
// 📖 OpenCode uses xdg-basedir which resolves to %USERPROFILE%\.config on Windows.
|
|
@@ -527,6 +528,7 @@ export async function startOpenCode(model, fcmConfig) {
|
|
|
527
528
|
// ─── Proxy lifecycle ─────────────────────────────────────────────────────────
|
|
528
529
|
|
|
529
530
|
async function cleanupProxy() {
|
|
531
|
+
// 📖 Only clean up in-process proxy. If using daemon, it stays alive.
|
|
530
532
|
if (proxyCleanedUp || !activeProxy) return
|
|
531
533
|
proxyCleanedUp = true
|
|
532
534
|
const proxy = activeProxy
|
|
@@ -546,35 +548,10 @@ function registerExitHandlers() {
|
|
|
546
548
|
process.once('exit', cleanup)
|
|
547
549
|
}
|
|
548
550
|
|
|
551
|
+
// 📖 Thin wrapper that passes module-level mergedModelsRef to the shared topology builder.
|
|
552
|
+
// 📖 The standalone daemon calls _buildTopology() directly with its own merged models.
|
|
549
553
|
export function buildProxyTopologyFromConfig(fcmConfig) {
|
|
550
|
-
|
|
551
|
-
const proxyModels = {}
|
|
552
|
-
|
|
553
|
-
for (const merged of mergedModelsRef) {
|
|
554
|
-
proxyModels[merged.slug] = { name: merged.label }
|
|
555
|
-
|
|
556
|
-
for (const providerEntry of merged.providers) {
|
|
557
|
-
const keys = resolveApiKeys(fcmConfig, providerEntry.providerKey)
|
|
558
|
-
const providerSource = sources[providerEntry.providerKey]
|
|
559
|
-
if (!providerSource) continue
|
|
560
|
-
|
|
561
|
-
const rawUrl = resolveCloudflareUrl(providerSource.url)
|
|
562
|
-
const baseUrl = rawUrl.replace(/\/chat\/completions$/, '')
|
|
563
|
-
|
|
564
|
-
keys.forEach((apiKey, keyIdx) => {
|
|
565
|
-
accounts.push({
|
|
566
|
-
id: `${providerEntry.providerKey}/${merged.slug}/${keyIdx}`,
|
|
567
|
-
providerKey: providerEntry.providerKey,
|
|
568
|
-
proxyModelId: merged.slug,
|
|
569
|
-
modelId: providerEntry.modelId,
|
|
570
|
-
url: baseUrl,
|
|
571
|
-
apiKey,
|
|
572
|
-
})
|
|
573
|
-
})
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return { accounts, proxyModels }
|
|
554
|
+
return _buildTopology(fcmConfig, mergedModelsRef, sources)
|
|
578
555
|
}
|
|
579
556
|
|
|
580
557
|
/**
|
|
@@ -596,6 +573,26 @@ export async function ensureProxyRunning(fcmConfig, { forceRestart = false } = {
|
|
|
596
573
|
throw new Error('Proxy mode is disabled in Settings')
|
|
597
574
|
}
|
|
598
575
|
|
|
576
|
+
// 📖 Phase 1: Check if background daemon is running — delegate instead of starting in-process
|
|
577
|
+
if (!forceRestart) {
|
|
578
|
+
try {
|
|
579
|
+
const daemonRunning = await isDaemonRunning()
|
|
580
|
+
if (daemonRunning) {
|
|
581
|
+
const info = getDaemonInfo()
|
|
582
|
+
if (info) {
|
|
583
|
+
return {
|
|
584
|
+
port: info.port,
|
|
585
|
+
accountCount: info.accountCount || 0,
|
|
586
|
+
proxyToken: info.token,
|
|
587
|
+
proxyModels: null,
|
|
588
|
+
availableModelSlugs: new Set(), // 📖 daemon handles model discovery
|
|
589
|
+
isDaemon: true,
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
} catch { /* daemon check failed — fall through to in-process */ }
|
|
594
|
+
}
|
|
595
|
+
|
|
599
596
|
if (forceRestart && activeProxy) {
|
|
600
597
|
await cleanupProxy()
|
|
601
598
|
}
|
|
@@ -619,8 +616,9 @@ export async function ensureProxyRunning(fcmConfig, { forceRestart = false } = {
|
|
|
619
616
|
throw new Error('No API keys found for proxy-capable models')
|
|
620
617
|
}
|
|
621
618
|
|
|
622
|
-
|
|
619
|
+
// 📖 Use stable token from config so env files / tool configs survive restarts
|
|
623
620
|
const proxySettings = getProxySettings(fcmConfig)
|
|
621
|
+
const proxyToken = proxySettings.stableToken || `fcm_${randomUUID().replace(/-/g, '')}`
|
|
624
622
|
const preferredPort = Number.isInteger(proxySettings.preferredPort) ? proxySettings.preferredPort : 0
|
|
625
623
|
const proxy = new ProxyServer({ port: preferredPort, accounts, proxyApiKey: proxyToken })
|
|
626
624
|
const { port } = await proxy.start()
|
|
@@ -692,7 +690,7 @@ async function startOpenCodeWithProxy(model, port, proxyModelId, proxyModels, fc
|
|
|
692
690
|
|
|
693
691
|
config.provider['fcm-proxy'] = {
|
|
694
692
|
npm: '@ai-sdk/openai-compatible',
|
|
695
|
-
name: 'FCM Proxy',
|
|
693
|
+
name: 'FCM Proxy V2',
|
|
696
694
|
options: {
|
|
697
695
|
baseURL: `http://127.0.0.1:${port}/v1`,
|
|
698
696
|
apiKey: proxyToken
|