@bolloon/bolloon-agent 0.4.33 → 0.5.1
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/dist/agents/contacts/chain.js +27 -7
- package/dist/agents/execution-supervisor.js +580 -40
- package/dist/agents/external-events.js +35 -6
- package/dist/agents/gateway-group.js +100 -12
- package/dist/agents/goal-criteria.js +10 -3
- package/dist/agents/goal-flywheel/block-executor.js +346 -0
- package/dist/agents/goal-flywheel/continuation-decision.js +592 -0
- package/dist/agents/goal-flywheel/goal-change.js +754 -0
- package/dist/agents/goal-flywheel/index.js +26 -0
- package/dist/agents/goal-flywheel/memory-layers.js +227 -0
- package/dist/agents/goal-flywheel/run-closure.js +809 -0
- package/dist/agents/goal-flywheel/skill-candidate.js +628 -0
- package/dist/agents/goal-flywheel/types.js +329 -0
- package/dist/agents/goal-flywheel/wiring/change.js +288 -0
- package/dist/agents/goal-flywheel/wiring/closure.js +697 -0
- package/dist/agents/goal-flywheel/wiring/continuation.js +432 -0
- package/dist/agents/goal-flywheel/wiring/contract.js +270 -0
- package/dist/agents/goal-flywheel/wiring/index.js +26 -0
- package/dist/agents/goal-flywheel/wiring/monitor.js +254 -0
- package/dist/agents/goal-flywheel/wiring/seams.js +592 -0
- package/dist/agents/goal-flywheel/work-contract.js +478 -0
- package/dist/agents/goal-flywheel/work-monitor.js +488 -0
- package/dist/agents/goal-flywheel-wiring.js +1870 -0
- package/dist/agents/goal-state-reducer.js +406 -0
- package/dist/agents/goal-store.js +35 -1
- package/dist/agents/mobile-flywheel-view.js +144 -0
- package/dist/agents/mobile-task-actions-verify.js +74 -0
- package/dist/agents/mobile-task-actions.js +178 -0
- package/dist/agents/mobile-task-views.js +199 -0
- package/dist/agents/model-policy.js +651 -0
- package/dist/agents/network-pulse.js +304 -18
- package/dist/agents/pi-sdk-tools.js +84 -33
- package/dist/agents/pi-sdk.js +157 -42
- package/dist/agents/run-store.js +71 -5
- package/dist/agents/skill-readiness.js +52 -10
- package/dist/agents/subagent-manager.js +209 -3
- package/dist/agents/task/task-runner.js +17 -4
- package/dist/agents/task-group.js +8 -51
- package/dist/agents/task-public-text.js +89 -0
- package/dist/agents/workflow-pivot-loop.js +19 -12
- package/dist/cli/clipboard.js +65 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/tasks.js +350 -2
- package/dist/cli/identity-command.js +177 -0
- package/dist/cli/ink-app.js +145 -17
- package/dist/cli/log-gate.js +386 -0
- package/dist/cli/mention-data.js +2 -0
- package/dist/cli/model-selector.js +538 -0
- package/dist/cli/reply-hygiene.js +54 -0
- package/dist/cli/setup-wizard.js +757 -69
- package/dist/cli/startup-notice.js +160 -0
- package/dist/cli/stores.js +22 -1
- package/dist/cli/theme.js +49 -0
- package/dist/cli/tui-select.js +970 -0
- package/dist/cli/update-commands.js +150 -24
- package/dist/cli-entry.js +137 -20
- package/dist/electron-build/agents/contacts/chain.js +26 -6
- package/dist/electron-build/agents/contacts/chain.js.map +1 -1
- package/dist/electron-build/agents/execution-supervisor.js +578 -38
- package/dist/electron-build/agents/execution-supervisor.js.map +1 -1
- package/dist/electron-build/agents/external-events.js +34 -5
- package/dist/electron-build/agents/external-events.js.map +1 -1
- package/dist/electron-build/agents/goal-criteria.js +10 -3
- package/dist/electron-build/agents/goal-criteria.js.map +1 -1
- package/dist/electron-build/agents/goal-flywheel/continuation-decision.js +598 -0
- package/dist/electron-build/agents/goal-flywheel/continuation-decision.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/goal-change.js +773 -0
- package/dist/electron-build/agents/goal-flywheel/goal-change.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/memory-layers.js +269 -0
- package/dist/electron-build/agents/goal-flywheel/memory-layers.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/run-closure.js +818 -0
- package/dist/electron-build/agents/goal-flywheel/run-closure.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/skill-candidate.js +642 -0
- package/dist/electron-build/agents/goal-flywheel/skill-candidate.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/types.js +333 -0
- package/dist/electron-build/agents/goal-flywheel/types.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/change.js +294 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/change.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/closure.js +742 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/closure.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js +444 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/contract.js +279 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/contract.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/index.js +111 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/index.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js +264 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/seams.js +612 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/seams.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/work-contract.js +488 -0
- package/dist/electron-build/agents/goal-flywheel/work-contract.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/work-monitor.js +501 -0
- package/dist/electron-build/agents/goal-flywheel/work-monitor.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel-wiring.js +1962 -0
- package/dist/electron-build/agents/goal-flywheel-wiring.js.map +1 -0
- package/dist/electron-build/agents/goal-state-reducer.js +414 -0
- package/dist/electron-build/agents/goal-state-reducer.js.map +1 -0
- package/dist/electron-build/agents/goal-store.js +35 -1
- package/dist/electron-build/agents/goal-store.js.map +1 -1
- package/dist/electron-build/agents/model-policy.js +706 -0
- package/dist/electron-build/agents/model-policy.js.map +1 -0
- package/dist/electron-build/agents/network-pulse.js +307 -19
- package/dist/electron-build/agents/network-pulse.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-tools.js +84 -33
- package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-types.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +156 -41
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/agents/run-store.js +75 -6
- package/dist/electron-build/agents/run-store.js.map +1 -1
- package/dist/electron-build/agents/skill-readiness.js +52 -9
- package/dist/electron-build/agents/skill-readiness.js.map +1 -1
- package/dist/electron-build/agents/task/task-runner.js +16 -3
- package/dist/electron-build/agents/task/task-runner.js.map +1 -1
- package/dist/electron-build/agents/workflow-pivot-loop.js +19 -12
- package/dist/electron-build/agents/workflow-pivot-loop.js.map +1 -1
- package/dist/electron-build/llm/config-store.js +146 -6
- package/dist/electron-build/llm/config-store.js.map +1 -1
- package/dist/electron-build/llm/connection-probe.js +764 -0
- package/dist/electron-build/llm/connection-probe.js.map +1 -0
- package/dist/electron-build/llm/custom-provider-store.js +272 -0
- package/dist/electron-build/llm/custom-provider-store.js.map +1 -0
- package/dist/electron-build/llm/data/provider-catalog-baked.js +23 -0
- package/dist/electron-build/llm/data/provider-catalog-baked.js.map +1 -0
- package/dist/electron-build/llm/model-catalog.js +778 -0
- package/dist/electron-build/llm/model-catalog.js.map +1 -0
- package/dist/electron-build/llm/model-discovery.js +1202 -0
- package/dist/electron-build/llm/model-discovery.js.map +1 -0
- package/dist/electron-build/llm/model-selection.js +1315 -0
- package/dist/electron-build/llm/model-selection.js.map +1 -0
- package/dist/electron-build/llm/pi-ai.js +70 -11
- package/dist/electron-build/llm/pi-ai.js.map +1 -1
- package/dist/electron-build/llm/provider-catalog.js +969 -0
- package/dist/electron-build/llm/provider-catalog.js.map +1 -0
- package/dist/electron-build/llm/provider-registry.js +950 -0
- package/dist/electron-build/llm/provider-registry.js.map +1 -0
- package/dist/electron-build/llm/tool-name.js +266 -0
- package/dist/electron-build/llm/tool-name.js.map +1 -0
- package/dist/electron-build/orbitdb/cid-database.js +83 -17
- package/dist/electron-build/orbitdb/cid-database.js.map +1 -1
- package/dist/electron-build/orbitdb/ipfs-node.js +31 -2
- package/dist/electron-build/orbitdb/ipfs-node.js.map +1 -1
- package/dist/electron-build/utils/dual-source-facts.js +236 -0
- package/dist/electron-build/utils/dual-source-facts.js.map +1 -0
- package/dist/electron-build/utils/dual-source.js +347 -0
- package/dist/electron-build/utils/dual-source.js.map +1 -0
- package/dist/electron-build/utils/update-manager.js +328 -104
- package/dist/electron-build/utils/update-manager.js.map +1 -1
- package/dist/electron-build/utils/update-state.js +9 -11
- package/dist/electron-build/utils/update-state.js.map +1 -1
- package/dist/electron-build/utils/version-identity.js +193 -0
- package/dist/electron-build/utils/version-identity.js.map +1 -0
- package/dist/electron-build/utils/version-info.js +57 -31
- package/dist/electron-build/utils/version-info.js.map +1 -1
- package/dist/index.js +385 -108
- package/dist/ios/bolloon-web.json +10 -0
- package/dist/ios/chain-explorer.js +617 -0
- package/dist/ios/explorer.html +163 -0
- package/dist/ios/index.html +96 -0
- package/dist/ios/mobile-agent.js +2 -2
- package/dist/ios/mobile-contacts.js +362 -0
- package/dist/ios/mobile-core.js +3102 -310
- package/dist/ios/mobile-privacy.js +185 -0
- package/dist/ios/mobile-tasks.js +339 -0
- package/dist/ios/mobile-update.js +1442 -0
- package/dist/ios/mobile.css +19 -0
- package/dist/ios/mobile.html +96 -0
- package/dist/ios/mobile.js +1013 -41
- package/dist/ios/routes-chain-index.js +108 -0
- package/dist/ios/routes-contacts.js +420 -0
- package/dist/ios/routes-llm-config.js +344 -52
- package/dist/ios/routes-mobile-tasks.js +353 -0
- package/dist/ios/routes-onchain-trade.js +99 -0
- package/dist/ios/routes-x402-info.js +1 -0
- package/dist/ios/server.js +921 -0
- package/dist/ios/sw.js +1 -1
- package/dist/ios/task-frame-server.js +211 -0
- package/dist/llm/config-store.js +146 -6
- package/dist/llm/connection-probe.js +744 -0
- package/dist/llm/custom-provider-store.js +224 -0
- package/dist/llm/data/provider-catalog-baked.js +19 -0
- package/dist/llm/model-catalog.js +717 -0
- package/dist/llm/model-discovery.js +1137 -0
- package/dist/llm/model-selection.js +1241 -0
- package/dist/llm/pi-ai.js +70 -11
- package/dist/llm/provider-catalog.js +898 -0
- package/dist/llm/provider-registry.js +917 -0
- package/dist/llm/tool-name.js +220 -0
- package/dist/orbitdb/cid-database.js +81 -16
- package/dist/orbitdb/ipfs-node.js +31 -2
- package/dist/setup/onboard.js +34 -8
- package/dist/utils/dual-source-facts.js +223 -0
- package/dist/utils/dual-source.js +297 -0
- package/dist/utils/update-cli.js +16 -21
- package/dist/utils/update-health.js +35 -5
- package/dist/utils/update-manager.js +325 -96
- package/dist/utils/update-state.js +13 -10
- package/dist/utils/version-identity.js +176 -0
- package/dist/utils/version-info.js +27 -22
- package/dist/web/bolloon-web.json +10 -0
- package/dist/web/mobile-contacts.js +44 -11
- package/dist/web/mobile-core.js +2901 -580
- package/dist/web/mobile-tasks.js +339 -0
- package/dist/web/mobile-update.js +1442 -0
- package/dist/web/mobile.css +19 -0
- package/dist/web/mobile.html +64 -0
- package/dist/web/mobile.js +838 -35
- package/dist/web/routes-llm-config.js +344 -52
- package/dist/web/routes-mobile-tasks.js +353 -0
- package/dist/web/server.js +163 -4
- package/dist/web/sw.js +1 -1
- package/package.json +3 -1
- package/scripts/build-web.ts +36 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* custom-provider-store.ts — 通用自定义供应商的持久化与迁移 (P3, 2026-09-26)
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么要有这一层
|
|
5
|
+
*
|
|
6
|
+
* "自定义供应商"必须能**落盘、重启后还在、旧配置照样能用**。落盘位置就一个: 与内置供应商同一份
|
|
7
|
+
* 配置文件 (`~/.bolloon/bolloon-config.json`, mode 0600) 里的 `customProviders` 一格 ——
|
|
8
|
+
* 不另开文件, 于是"CLI/Web/子进程读到的是同一份配置"这件事不用再解释一遍。
|
|
9
|
+
*
|
|
10
|
+
* 读写**只**经过 `llmConfigStore` (它已经处理了: 目录变化、文件签名变化、跨进程单飞写锁、
|
|
11
|
+
* 迁移旧文件名)。本层不自己 `fs.writeFile` —— 否则就是第二条写盘路径。
|
|
12
|
+
*
|
|
13
|
+
* ## 向后兼容 (旧 `llm-config.json` 必须原样可用)
|
|
14
|
+
*
|
|
15
|
+
* 旧配置有三种真实形态, 全部在**读**的时候收成规范形 (纯函数在 `provider-registry` 里, 这里只负责
|
|
16
|
+
* 把它接到磁盘数据上), 而且:
|
|
17
|
+
*
|
|
18
|
+
* 1. **一个字都没写** `customProviders` → 空表, 内置 13 家照旧;
|
|
19
|
+
* 2. **早期数组形** `customProviders: [ {...} ]` → 按 `providerId` 收成 map;
|
|
20
|
+
* 3. **只有 provider 条目、没有 customProviders** (旧版本把自定义端点直接写进 `providers.<id>`) →
|
|
21
|
+
* 从 `providers` 里**吸收**成自定义供应商 (协议按 base URL 主机名推), 同时**保留原键不动**。
|
|
22
|
+
*
|
|
23
|
+
* 读的时候**不改盘** (不"读一下就把用户文件改了"); 只有显式 `add/update/remove` 才写回, 写回时
|
|
24
|
+
* 把吸收来的条目一并固化 —— 也就是"用户下一次改配置时, 迁移才落到盘上"。
|
|
25
|
+
*
|
|
26
|
+
* 被拒绝的条目**留名+留理由** (`loadCustomProviders().rejected`), 界面要如实报出来,
|
|
27
|
+
* 不许"读一读就少了两家"。
|
|
28
|
+
*/
|
|
29
|
+
import * as fs from 'fs/promises';
|
|
30
|
+
import * as path from 'path';
|
|
31
|
+
import { llmConfigStore, } from './config-store.js';
|
|
32
|
+
import { normalizeCustomProvider, normalizeCustomProviders, absorbLegacyProviderEntries, ensureProviderRegistryMetadataSource, isValidCustomProviderId, isBuiltinProvider, setCustomProviderSnapshot, customProviderSnapshot, customProviderEntryOf, } from './provider-registry.js';
|
|
33
|
+
/**
|
|
34
|
+
* 读出**当前在册**的自定义供应商 (规范形), 顺带把进程内快照刷新。
|
|
35
|
+
*
|
|
36
|
+
* 吸收 `providers.<未知 id>` 的那段逻辑与 `config-store.initialize()` **共用同一个纯函数**
|
|
37
|
+
* (`provider-registry.absorbLegacyProviderEntries`), 不存在两处各写一份的漂移。
|
|
38
|
+
*/
|
|
39
|
+
export async function loadCustomProviders() {
|
|
40
|
+
await llmConfigStore.initialize();
|
|
41
|
+
ensureProviderRegistryMetadataSource(); // 读自定义供应商 = 注册表在用 → 顺手接线 (幂等)
|
|
42
|
+
const cfg = await llmConfigStore.getConfig();
|
|
43
|
+
const notes = [];
|
|
44
|
+
// 迁移报告必须对着**盘上原本的样子**做: `config-store` 读盘时已经把那一格收成 map 并丢掉了坏条目
|
|
45
|
+
// (那是运行时视图), 所以这里优先看原文件; 文件读不出来才退回内存视图 (会少掉"拒绝/吸收"这份报告)。
|
|
46
|
+
let rawCustom = cfg?.customProviders;
|
|
47
|
+
let rawProviders = cfg?.providers;
|
|
48
|
+
try {
|
|
49
|
+
const rawFile = JSON.parse(await fs.readFile(llmConfigStore.configFilePath(), 'utf-8'));
|
|
50
|
+
if (rawFile && typeof rawFile === 'object') {
|
|
51
|
+
rawCustom = rawFile.customProviders;
|
|
52
|
+
rawProviders = rawFile.providers;
|
|
53
|
+
if (Array.isArray(rawFile.customProviders))
|
|
54
|
+
notes.push('customProviders 是早期数组形 → 已按 providerId 收成 map');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch { /* 文件不在/读不出: 这一条迁移记录就无从谈起, 不编 */ }
|
|
58
|
+
const norm = normalizeCustomProviders(rawCustom);
|
|
59
|
+
const { providers, absorbed } = absorbLegacyProviderEntries(rawProviders, norm.providers);
|
|
60
|
+
if (absorbed.length) {
|
|
61
|
+
notes.push(`从 providers 里吸收 ${absorbed.length} 个自定义端点: ${absorbed.map((a) => a.providerId).join(', ')} (协议按 base URL 主机名推)`);
|
|
62
|
+
}
|
|
63
|
+
setCustomProviderSnapshot(providers);
|
|
64
|
+
return { providers, absorbed, notes, rejected: norm.rejected };
|
|
65
|
+
}
|
|
66
|
+
/** 只要规范形 (大多数调用方只需要这一个) */
|
|
67
|
+
export async function readCustomProviders() {
|
|
68
|
+
return (await loadCustomProviders()).providers;
|
|
69
|
+
}
|
|
70
|
+
/** 把快照刷新到"配置里现在写的这一份" (调用方在别处改过配置后可以主动调一次) */
|
|
71
|
+
export async function refreshCustomProviderSnapshot() {
|
|
72
|
+
return readCustomProviders();
|
|
73
|
+
}
|
|
74
|
+
/** 进程内快照 (纯同步; 元数据填充点与注册表读口用它) */
|
|
75
|
+
export function currentCustomProviders() {
|
|
76
|
+
return customProviderSnapshot();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 自定义供应商的注册表条目清单 (同步, 用快照)。
|
|
80
|
+
* 想保证"盘上最新的那一份" → 先 `await refreshCustomProviderSnapshot()`。
|
|
81
|
+
*/
|
|
82
|
+
export function customProviderEntries() {
|
|
83
|
+
return Object.values(customProviderSnapshot()).map((spec) => customProviderEntryOf(spec));
|
|
84
|
+
}
|
|
85
|
+
/** 校验一条自定义供应商声明 (纯函数; 不读盘不写盘) */
|
|
86
|
+
export function validateCustomProvider(spec) {
|
|
87
|
+
const norm = normalizeCustomProvider(spec);
|
|
88
|
+
if (!norm.ok)
|
|
89
|
+
return { ok: false, reason: norm.reason };
|
|
90
|
+
if (!isValidCustomProviderId(norm.value.providerId)) {
|
|
91
|
+
return { ok: false, reason: isBuiltinProvider(norm.value.providerId) ? `providerId 与内置供应商撞名: ${norm.value.providerId}` : `providerId 形状非法: ${norm.value.providerId}` };
|
|
92
|
+
}
|
|
93
|
+
const entry = customProviderEntryOf(norm.value);
|
|
94
|
+
if (!entry.defaultBaseUrl)
|
|
95
|
+
return { ok: false, reason: 'baseUrl 规范化后为空' };
|
|
96
|
+
if (entry.auth.kind === 'custom' && !entry.auth.header)
|
|
97
|
+
return { ok: false, reason: 'authHeader 给了却是空的' };
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
100
|
+
/** 读出 map → 改 → 整份写回 (走 llmConfigStore 的写锁; 关掉它的内存缓存保证重新读盘) */
|
|
101
|
+
async function writeProviders(mutate) {
|
|
102
|
+
await llmConfigStore.initialize();
|
|
103
|
+
const loaded = await loadCustomProviders();
|
|
104
|
+
// 读不出来的条目**不许**被一次写入悄悄抹掉: 先让人把配置改对 (拒绝 = 什么都没落盘)
|
|
105
|
+
if (loaded.rejected.length) {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
reason: `配置文件里 customProviders 有 ${loaded.rejected.length} 条读不出来 (${loaded.rejected.map((r) => `${r.key}: ${r.reason}`).join('; ')}) — 写回会把这几种写法丢掉, 先修好再改`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const out = mutate({ ...loaded.providers });
|
|
112
|
+
if (out.reason)
|
|
113
|
+
return { ok: false, reason: out.reason };
|
|
114
|
+
if (!out.providers)
|
|
115
|
+
return { ok: false, reason: '内部错误: mutate 没有给回 providers' };
|
|
116
|
+
// 写盘前**重新读**一次配置, 只覆盖 customProviders 一格 —— 不拿旧快照覆盖别人的改动
|
|
117
|
+
llmConfigStore.invalidate();
|
|
118
|
+
await llmConfigStore.initialize();
|
|
119
|
+
await llmConfigStore.setCustomProviders(out.providers);
|
|
120
|
+
setCustomProviderSnapshot(out.providers);
|
|
121
|
+
return { ok: true };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 新增 / 覆盖一个自定义供应商。
|
|
125
|
+
*
|
|
126
|
+
* 与内置撞名 → **拒绝** (内置优先保障清单不许被自定义路覆盖), 理由明确返回。
|
|
127
|
+
*/
|
|
128
|
+
export async function addCustomProvider(spec) {
|
|
129
|
+
const norm = normalizeCustomProvider(spec);
|
|
130
|
+
if (!norm.ok)
|
|
131
|
+
return { ok: false, reason: norm.reason };
|
|
132
|
+
const value = norm.value;
|
|
133
|
+
const check = validateCustomProvider(value);
|
|
134
|
+
if (!check.ok)
|
|
135
|
+
return { ok: false, reason: check.reason };
|
|
136
|
+
const result = await writeProviders((providers) => {
|
|
137
|
+
providers[value.providerId] = { ...value, updatedAt: new Date().toISOString() };
|
|
138
|
+
return { providers };
|
|
139
|
+
});
|
|
140
|
+
if (!result.ok)
|
|
141
|
+
return result;
|
|
142
|
+
return { ok: true, entry: customProviderEntryOf(value) };
|
|
143
|
+
}
|
|
144
|
+
/** 改一个已存在的自定义供应商 (不存在 → 拒绝, 不顺手新建) */
|
|
145
|
+
export async function updateCustomProvider(providerId, patch) {
|
|
146
|
+
const id = String(providerId || '').trim();
|
|
147
|
+
const current = await readCustomProviders();
|
|
148
|
+
const existing = current[id];
|
|
149
|
+
if (!existing)
|
|
150
|
+
return { ok: false, reason: `不在册的自定义供应商: ${id}` };
|
|
151
|
+
const merged = normalizeCustomProvider({ ...existing, ...patch, providerId: id });
|
|
152
|
+
if (!merged.ok)
|
|
153
|
+
return { ok: false, reason: merged.reason };
|
|
154
|
+
const check = validateCustomProvider(merged.value);
|
|
155
|
+
if (!check.ok)
|
|
156
|
+
return { ok: false, reason: check.reason };
|
|
157
|
+
const result = await writeProviders((providers) => {
|
|
158
|
+
providers[id] = { ...merged.value, updatedAt: new Date().toISOString() };
|
|
159
|
+
return { providers };
|
|
160
|
+
});
|
|
161
|
+
if (!result.ok)
|
|
162
|
+
return result;
|
|
163
|
+
return { ok: true, entry: customProviderEntryOf(merged.value) };
|
|
164
|
+
}
|
|
165
|
+
/** 删一个自定义供应商 (不存在 → 拒绝, 让调用方知道"什么都没删") */
|
|
166
|
+
export async function removeCustomProvider(providerId) {
|
|
167
|
+
const id = String(providerId || '').trim();
|
|
168
|
+
const current = await readCustomProviders();
|
|
169
|
+
if (!current[id])
|
|
170
|
+
return { ok: false, reason: `不在册的自定义供应商: ${id}` };
|
|
171
|
+
return writeProviders((providers) => {
|
|
172
|
+
delete providers[id];
|
|
173
|
+
return { providers };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// ============================================================
|
|
177
|
+
// 展示 (凭据**不进**这里)
|
|
178
|
+
// ============================================================
|
|
179
|
+
/**
|
|
180
|
+
* 打印/上报用的自定义供应商行: key 只留尾 4 位, 其余 `[REDACTED]`。
|
|
181
|
+
* 任何"要把配置显示给人看"的地方都走这里, 不要自己拼 JSON。
|
|
182
|
+
*/
|
|
183
|
+
export function formatCustomProviderLine(spec) {
|
|
184
|
+
const entry = customProviderEntryOf(spec);
|
|
185
|
+
const keyState = spec.apiKey
|
|
186
|
+
? `key=已配(尾号 ${String(spec.apiKey).slice(-4)})`
|
|
187
|
+
: spec.apiKeyEnvVar
|
|
188
|
+
? `key=环境变量 ${spec.apiKeyEnvVar}`
|
|
189
|
+
: entry.requiresApiKey ? 'key=缺' : 'key=不需要';
|
|
190
|
+
const bits = [
|
|
191
|
+
`${entry.protocol}`,
|
|
192
|
+
`地址=${entry.defaultBaseUrl}`,
|
|
193
|
+
`模型=${entry.defaultModel || '未设'}`,
|
|
194
|
+
`认证=${entry.auth.kind}${entry.auth.header ? `(${entry.auth.header})` : ''}`,
|
|
195
|
+
`发现=${entry.discovery}`,
|
|
196
|
+
`工具调用=${entry.toolCalling}`,
|
|
197
|
+
keyState,
|
|
198
|
+
entry.allowsLongRunningExecutor ? '可当长期任务执行器' : '不可当长期任务执行器',
|
|
199
|
+
];
|
|
200
|
+
return `· ${entry.id}${entry.displayName && entry.displayName !== entry.id ? ` (${entry.displayName})` : ''} · ${bits.join(' · ')}`;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 整份配置的脱敏副本 (给"导出配置/贴报告"用): `apiKey` 一律 `[REDACTED]`。
|
|
204
|
+
* 深拷贝 + 只改凭据字段, 其他字段原样 (不许把别的字段也顺手"整理"了)。
|
|
205
|
+
*/
|
|
206
|
+
export function redactCustomProviders(map) {
|
|
207
|
+
const out = {};
|
|
208
|
+
for (const [id, spec] of Object.entries(map)) {
|
|
209
|
+
out[id] = { ...spec, ...(spec.apiKey ? { apiKey: '[REDACTED]' } : {}) };
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
/** 配置文件里 `customProviders` 一格的原始文本 (排障用; 凭据已脱敏) —— 不打印原始文件 */
|
|
214
|
+
export async function customProvidersFileSnippet() {
|
|
215
|
+
const file = llmConfigStore.configFilePath();
|
|
216
|
+
try {
|
|
217
|
+
const parsed = JSON.parse(await fs.readFile(file, 'utf-8'));
|
|
218
|
+
const redacted = redactCustomProviders(parsed?.customProviders && typeof parsed.customProviders === 'object' && !Array.isArray(parsed.customProviders) ? parsed.customProviders : {});
|
|
219
|
+
return JSON.stringify({ path: path.basename(file), customProviders: redacted }, null, 2);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return JSON.stringify({ path: path.basename(file), customProviders: {} }, null, 2);
|
|
223
|
+
}
|
|
224
|
+
}
|