@aalis/core 0.1.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/README.md +21 -0
- package/dist/app.d.ts +166 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +348 -0
- package/dist/app.js.map +1 -0
- package/dist/config.d.ts +174 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +377 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +36 -0
- package/dist/constants.js.map +1 -0
- package/dist/context.d.ts +328 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +521 -0
- package/dist/context.js.map +1 -0
- package/dist/disposable-chain.d.ts +31 -0
- package/dist/disposable-chain.d.ts.map +1 -0
- package/dist/disposable-chain.js +66 -0
- package/dist/disposable-chain.js.map +1 -0
- package/dist/events.d.ts +64 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +145 -0
- package/dist/events.js.map +1 -0
- package/dist/hooks.d.ts +49 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +102 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +26 -0
- package/dist/i18n.js.map +1 -0
- package/dist/identity.d.ts +26 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +36 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +20 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +455 -0
- package/dist/init.js.map +1 -0
- package/dist/llm-router.d.ts.map +1 -0
- package/dist/llm-router.js +123 -0
- package/dist/llm-router.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/marketplace-bootstrap.d.ts +54 -0
- package/dist/marketplace-bootstrap.d.ts.map +1 -0
- package/dist/marketplace-bootstrap.js +132 -0
- package/dist/marketplace-bootstrap.js.map +1 -0
- package/dist/mixin-registry.d.ts +34 -0
- package/dist/mixin-registry.d.ts.map +1 -0
- package/dist/mixin-registry.js +60 -0
- package/dist/mixin-registry.js.map +1 -0
- package/dist/model-ref.d.ts +22 -0
- package/dist/model-ref.d.ts.map +1 -0
- package/dist/model-ref.js +46 -0
- package/dist/model-ref.js.map +1 -0
- package/dist/pending-buffer.d.ts +46 -0
- package/dist/pending-buffer.d.ts.map +1 -0
- package/dist/pending-buffer.js +131 -0
- package/dist/pending-buffer.js.map +1 -0
- package/dist/platform-registry.d.ts +40 -0
- package/dist/platform-registry.d.ts.map +1 -0
- package/dist/platform-registry.js +64 -0
- package/dist/platform-registry.js.map +1 -0
- package/dist/plugin-activation.d.ts +43 -0
- package/dist/plugin-activation.d.ts.map +1 -0
- package/dist/plugin-activation.js +172 -0
- package/dist/plugin-activation.js.map +1 -0
- package/dist/plugin-topology.d.ts +40 -0
- package/dist/plugin-topology.d.ts.map +1 -0
- package/dist/plugin-topology.js +126 -0
- package/dist/plugin-topology.js.map +1 -0
- package/dist/plugin.d.ts +184 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +549 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers.d.ts +85 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +2 -0
- package/dist/providers.js.map +1 -0
- package/dist/semver-mini.d.ts +20 -0
- package/dist/semver-mini.d.ts.map +1 -0
- package/dist/semver-mini.js +94 -0
- package/dist/semver-mini.js.map +1 -0
- package/dist/service-helpers.d.ts +34 -0
- package/dist/service-helpers.d.ts.map +1 -0
- package/dist/service-helpers.js +68 -0
- package/dist/service-helpers.js.map +1 -0
- package/dist/service.d.ts +145 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +279 -0
- package/dist/service.js.map +1 -0
- package/dist/types/agent.d.ts +51 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +3 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/app.d.ts +74 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +3 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/archive.d.ts +59 -0
- package/dist/types/archive.d.ts.map +1 -0
- package/dist/types/archive.js +16 -0
- package/dist/types/archive.js.map +1 -0
- package/dist/types/authority.d.ts +63 -0
- package/dist/types/authority.d.ts.map +1 -0
- package/dist/types/authority.js +3 -0
- package/dist/types/authority.js.map +1 -0
- package/dist/types/capabilities.d.ts +53 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +87 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/cli.d.ts +14 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +3 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/commands.d.ts +98 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +3 -0
- package/dist/types/commands.js.map +1 -0
- package/dist/types/core.d.ts +117 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/core.js +6 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/disposable-service.d.ts +31 -0
- package/dist/types/disposable-service.d.ts.map +1 -0
- package/dist/types/disposable-service.js +3 -0
- package/dist/types/disposable-service.js.map +1 -0
- package/dist/types/embedding.d.ts +7 -0
- package/dist/types/embedding.d.ts.map +1 -0
- package/dist/types/embedding.js +3 -0
- package/dist/types/embedding.js.map +1 -0
- package/dist/types/flow-control.d.ts +51 -0
- package/dist/types/flow-control.d.ts.map +1 -0
- package/dist/types/flow-control.js +12 -0
- package/dist/types/flow-control.js.map +1 -0
- package/dist/types/gateway.d.ts +24 -0
- package/dist/types/gateway.d.ts.map +1 -0
- package/dist/types/gateway.js +15 -0
- package/dist/types/gateway.js.map +1 -0
- package/dist/types/hooks.d.ts +3 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/hooks.js +18 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/image-recognition.d.ts +123 -0
- package/dist/types/image-recognition.d.ts.map +1 -0
- package/dist/types/image-recognition.js +31 -0
- package/dist/types/image-recognition.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +17 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/llm.d.ts +146 -0
- package/dist/types/llm.d.ts.map +1 -0
- package/dist/types/llm.js +27 -0
- package/dist/types/llm.js.map +1 -0
- package/dist/types/memory.d.ts +62 -0
- package/dist/types/memory.d.ts.map +1 -0
- package/dist/types/memory.js +22 -0
- package/dist/types/memory.js.map +1 -0
- package/dist/types/persona.d.ts +45 -0
- package/dist/types/persona.d.ts.map +1 -0
- package/dist/types/persona.js +3 -0
- package/dist/types/persona.js.map +1 -0
- package/dist/types/platform.d.ts +126 -0
- package/dist/types/platform.d.ts.map +1 -0
- package/dist/types/platform.js +5 -0
- package/dist/types/platform.js.map +1 -0
- package/dist/types/plugin.d.ts +84 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +24 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/service.d.ts +43 -0
- package/dist/types/service.d.ts.map +1 -0
- package/dist/types/service.js +38 -0
- package/dist/types/service.js.map +1 -0
- package/dist/types/services.d.ts +17 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +41 -0
- package/dist/types/services.js.map +1 -0
- package/dist/types/session.d.ts +153 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +19 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/storage.d.ts +100 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +29 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/types/tools.d.ts +39 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +3 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/trigger-policy.d.ts +16 -0
- package/dist/types/trigger-policy.d.ts.map +1 -0
- package/dist/types/trigger-policy.js +6 -0
- package/dist/types/trigger-policy.js.map +1 -0
- package/dist/types/vectorstore.d.ts +23 -0
- package/dist/types/vectorstore.d.ts.map +1 -0
- package/dist/types/vectorstore.js +3 -0
- package/dist/types/vectorstore.js.map +1 -0
- package/dist/types/web-search.d.ts +88 -0
- package/dist/types/web-search.d.ts.map +1 -0
- package/dist/types/web-search.js +23 -0
- package/dist/types/web-search.js.map +1 -0
- package/dist/types/webui.d.ts +137 -0
- package/dist/types/webui.d.ts.map +1 -0
- package/dist/types/webui.js +3 -0
- package/dist/types/webui.js.map +1 -0
- package/package.json +22 -0
package/dist/init.js
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 首启交互式初始化向导。
|
|
3
|
+
*
|
|
4
|
+
* 当 aalis.config.yaml 不存在时被 src/index.ts 调用。
|
|
5
|
+
*
|
|
6
|
+
* 设计:
|
|
7
|
+
* - 不依赖任何插件实例(只 dynamic import 各 plugin 的入口模块以读取静态导出的 provides/inject)。
|
|
8
|
+
* - 不再硬编码插件清单或"bundled 必装"概念:
|
|
9
|
+
* · 扫 packages/plugin-* 与已经位于 node_modules/@aalis/plugin-* 的本地包;
|
|
10
|
+
* · 用各 plugin 模块的 `provides[]` 把它们按服务分组,让用户在每个服务里多选;
|
|
11
|
+
* · 不 provide 任何服务的归为"工具与扩展"。
|
|
12
|
+
* - 配置块写空对象 `{}`,密钥等留给用户启动后从 WebUI 或 yaml 填。
|
|
13
|
+
* 末尾会列出"启用了但通常需要进一步配置"的插件提醒。
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, writeFileSync, readdirSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { resolve } from 'node:path';
|
|
17
|
+
import { pathToFileURL } from 'node:url';
|
|
18
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
19
|
+
import * as readline from 'node:readline/promises';
|
|
20
|
+
import { stdin as input, stdout as output } from 'node:process';
|
|
21
|
+
import { MarketplaceBootstrap, runRootPnpmInstall } from './marketplace-bootstrap.js';
|
|
22
|
+
const EXTERNAL_HINTS = {
|
|
23
|
+
'@aalis/plugin-deepseek': '需要 apiKey',
|
|
24
|
+
'@aalis/plugin-openai': '需要 apiKey 和(可选)baseURL',
|
|
25
|
+
'@aalis/plugin-ollama': '需要本地或远端 Ollama 服务地址',
|
|
26
|
+
'@aalis/plugin-embedding-ollama': '需要 Ollama 服务地址',
|
|
27
|
+
'@aalis/plugin-memory-mongodb': '需要 MongoDB 连接 URI',
|
|
28
|
+
'@aalis/plugin-adapter-onebot': '需要 OneBot 账号、wsUrl 等',
|
|
29
|
+
'@aalis/plugin-websearch-serper': '需要 Serper API Key',
|
|
30
|
+
'@aalis/plugin-image-recognition': '需要视觉模型 apiKey/endpoint',
|
|
31
|
+
'@aalis/plugin-okx-trading': '需要交易所 API 凭证',
|
|
32
|
+
'@aalis/plugin-maimai': '需要舞萌相关 token',
|
|
33
|
+
'@aalis/plugin-marketplace-client': '建议至少配置 1 个 registry',
|
|
34
|
+
};
|
|
35
|
+
/** 扫描仓库 packages/plugin-* 与 node_modules/@aalis/plugin-* */
|
|
36
|
+
async function discoverPluginMetas(cwd) {
|
|
37
|
+
const found = [];
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
// 1) 仓库 packages/plugin-*
|
|
40
|
+
const pkgsDir = resolve(cwd, 'packages');
|
|
41
|
+
if (existsSync(pkgsDir)) {
|
|
42
|
+
for (const dir of readdirSync(pkgsDir)) {
|
|
43
|
+
if (!dir.startsWith('plugin-'))
|
|
44
|
+
continue;
|
|
45
|
+
const pkgDir = resolve(pkgsDir, dir);
|
|
46
|
+
const meta = await readPluginMeta(pkgDir, dir);
|
|
47
|
+
if (meta && !seen.has(meta.name)) {
|
|
48
|
+
seen.add(meta.name);
|
|
49
|
+
found.push(meta);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// 2) node_modules/@aalis/plugin-*(带 file:./packages 依赖的未在工作区连接场景)
|
|
54
|
+
const nmAalis = resolve(cwd, 'node_modules', '@aalis');
|
|
55
|
+
if (existsSync(nmAalis)) {
|
|
56
|
+
for (const dir of readdirSync(nmAalis)) {
|
|
57
|
+
if (!dir.startsWith('plugin-'))
|
|
58
|
+
continue;
|
|
59
|
+
const pkgDir = resolve(nmAalis, dir);
|
|
60
|
+
const meta = await readPluginMeta(pkgDir, `@aalis/${dir}`);
|
|
61
|
+
if (meta && !seen.has(meta.name)) {
|
|
62
|
+
seen.add(meta.name);
|
|
63
|
+
found.push(meta);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
found.sort((a, b) => a.name.localeCompare(b.name));
|
|
68
|
+
return found;
|
|
69
|
+
}
|
|
70
|
+
async function readPluginMeta(pkgDir, dirHint) {
|
|
71
|
+
const pjPath = resolve(pkgDir, 'package.json');
|
|
72
|
+
if (!existsSync(pjPath))
|
|
73
|
+
return null;
|
|
74
|
+
let pkg;
|
|
75
|
+
try {
|
|
76
|
+
pkg = JSON.parse(readFileSync(pjPath, 'utf-8'));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
if (!pkg.name)
|
|
82
|
+
return null;
|
|
83
|
+
if (pkg.aalis?.core || pkg.aalis?.client)
|
|
84
|
+
return null;
|
|
85
|
+
if (!(pkg.keywords ?? []).includes('aalis-plugin'))
|
|
86
|
+
return null;
|
|
87
|
+
// 尝试 dynamic import 读取 provides / inject
|
|
88
|
+
let provides = [];
|
|
89
|
+
let injectRequired = [];
|
|
90
|
+
const mainRel = pkg.main ?? 'dist/index.js';
|
|
91
|
+
const mainAbs = resolve(pkgDir, mainRel);
|
|
92
|
+
if (existsSync(mainAbs)) {
|
|
93
|
+
try {
|
|
94
|
+
const mod = await import(pathToFileURL(mainAbs).href);
|
|
95
|
+
const exp = (mod && (mod.default ?? mod));
|
|
96
|
+
if (Array.isArray(mod.provides)) {
|
|
97
|
+
provides = (mod.provides).filter(x => typeof x === 'string');
|
|
98
|
+
}
|
|
99
|
+
else if (Array.isArray(exp.provides)) {
|
|
100
|
+
provides = (exp.provides).filter(x => typeof x === 'string');
|
|
101
|
+
}
|
|
102
|
+
const injSrc = mod.inject ?? exp.inject;
|
|
103
|
+
if (injSrc && typeof injSrc === 'object') {
|
|
104
|
+
const req = injSrc.required;
|
|
105
|
+
if (Array.isArray(req))
|
|
106
|
+
injectRequired = req.filter(x => typeof x === 'string');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch { /* 静默忽略 import 失败的 plugin */ }
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
name: pkg.name,
|
|
113
|
+
dir: dirHint,
|
|
114
|
+
description: pkg.description ?? '',
|
|
115
|
+
displayName: pkg.aalis?.displayName,
|
|
116
|
+
provides,
|
|
117
|
+
injectRequired,
|
|
118
|
+
needsExternalConfig: pkg.name in EXTERNAL_HINTS,
|
|
119
|
+
origin: 'local',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** 将 registry 返回的 BootstrapIndexEntry 转换为 PluginMeta(仅用于本地未命中的远端项) */
|
|
123
|
+
function remoteEntryToMeta(e) {
|
|
124
|
+
return {
|
|
125
|
+
name: e.name,
|
|
126
|
+
dir: pluginDirName(e.name),
|
|
127
|
+
description: e.description ?? '',
|
|
128
|
+
displayName: e.displayName,
|
|
129
|
+
provides: e.provides ?? [],
|
|
130
|
+
injectRequired: e.inject ?? [],
|
|
131
|
+
needsExternalConfig: e.name in EXTERNAL_HINTS,
|
|
132
|
+
origin: 'remote',
|
|
133
|
+
remoteVersion: e.latest,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function pluginDirName(manifestName) {
|
|
137
|
+
if (manifestName.startsWith('@')) {
|
|
138
|
+
const slash = manifestName.indexOf('/');
|
|
139
|
+
return slash > 0 ? manifestName.slice(slash + 1) : manifestName;
|
|
140
|
+
}
|
|
141
|
+
return manifestName;
|
|
142
|
+
}
|
|
143
|
+
// ─────────────────────── 服务分组 ───────────────────────
|
|
144
|
+
/** 已知服务的中文标签与排序优先级。未知服务用原名兜底。 */
|
|
145
|
+
const SERVICE_LABELS = {
|
|
146
|
+
storage: { label: '存储 (storage)', order: 10, recommended: true },
|
|
147
|
+
platform: { label: '平台基类 (platform)', order: 11, recommended: true },
|
|
148
|
+
gateway: { label: '消息网关 (gateway)', order: 12, recommended: true },
|
|
149
|
+
marketplace: { label: '插件市场客户端 (marketplace)', order: 13, recommended: true },
|
|
150
|
+
llm: { label: '语言模型 (llm)', order: 20 },
|
|
151
|
+
memory: { label: '消息记忆 (memory)', order: 30 },
|
|
152
|
+
embedding: { label: 'Embedding 模型 (embedding)', order: 40 },
|
|
153
|
+
vectorstore: { label: '向量数据库 (vectorstore)', order: 41 },
|
|
154
|
+
agent: { label: '对话代理 (agent)', order: 50 },
|
|
155
|
+
authority: { label: '权限分级 (authority)', order: 51 },
|
|
156
|
+
persona: { label: '人格 / 角色卡 (persona)', order: 52 },
|
|
157
|
+
scheduler: { label: '调度器 (scheduler)', order: 53 },
|
|
158
|
+
session: { label: '会话 (session)', order: 54 },
|
|
159
|
+
webui: { label: 'WebUI 服务 (webui)', order: 60 },
|
|
160
|
+
cli: { label: 'CLI REPL (cli)', order: 61 },
|
|
161
|
+
};
|
|
162
|
+
function groupByService(metas) {
|
|
163
|
+
// 一个 plugin 可能 provides 多个 service,会被加入多个组(用户在每个组里都能看到它)。
|
|
164
|
+
const groups = new Map();
|
|
165
|
+
const noProvides = [];
|
|
166
|
+
for (const m of metas) {
|
|
167
|
+
if (m.provides.length === 0) {
|
|
168
|
+
noProvides.push(m);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
for (const svc of m.provides) {
|
|
172
|
+
const meta = SERVICE_LABELS[svc];
|
|
173
|
+
let g = groups.get(svc);
|
|
174
|
+
if (!g) {
|
|
175
|
+
g = {
|
|
176
|
+
service: svc,
|
|
177
|
+
label: meta?.label ?? `${svc} 服务`,
|
|
178
|
+
members: [],
|
|
179
|
+
recommended: meta?.recommended ?? false,
|
|
180
|
+
};
|
|
181
|
+
groups.set(svc, g);
|
|
182
|
+
}
|
|
183
|
+
g.members.push(m);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (noProvides.length) {
|
|
187
|
+
groups.set('__misc__', {
|
|
188
|
+
service: '__misc__',
|
|
189
|
+
label: '工具与扩展(不提供具体服务)',
|
|
190
|
+
members: noProvides,
|
|
191
|
+
recommended: false,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return [...groups.values()].sort((a, b) => {
|
|
195
|
+
const oa = SERVICE_LABELS[a.service]?.order ?? (a.service === '__misc__' ? 999 : 500);
|
|
196
|
+
const ob = SERVICE_LABELS[b.service]?.order ?? (b.service === '__misc__' ? 999 : 500);
|
|
197
|
+
return oa - ob || a.service.localeCompare(b.service);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// ─────────────────────── 交互工具 ───────────────────────
|
|
201
|
+
class StdinClosedError extends Error {
|
|
202
|
+
constructor() { super('stdin closed during init wizard'); }
|
|
203
|
+
}
|
|
204
|
+
async function safeQuestion(rl, prompt) {
|
|
205
|
+
let onClose = null;
|
|
206
|
+
const closePromise = new Promise((_, reject) => {
|
|
207
|
+
onClose = () => reject(new StdinClosedError());
|
|
208
|
+
rl.once('close', onClose);
|
|
209
|
+
});
|
|
210
|
+
try {
|
|
211
|
+
return await Promise.race([rl.question(prompt), closePromise]);
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
if (onClose)
|
|
215
|
+
rl.off('close', onClose);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 多选:列出 entries,用户输入逗号分隔的编号;回车采用 defaultIdx 集合。
|
|
220
|
+
* 输入 'a' = 全选,'n' = 全不选。
|
|
221
|
+
*/
|
|
222
|
+
async function pickMany(rl, title, entries, defaultIdx) {
|
|
223
|
+
console.log(`\n${title}`);
|
|
224
|
+
console.log(' (多选,逗号分隔编号;回车采用默认;a=全选;n=全不选)');
|
|
225
|
+
const defSet = new Set(defaultIdx);
|
|
226
|
+
for (let i = 0; i < entries.length; i++) {
|
|
227
|
+
const e = entries[i];
|
|
228
|
+
const star = defSet.has(i) ? '*' : ' ';
|
|
229
|
+
console.log(` ${star} ${i + 1}) ${e.label}`);
|
|
230
|
+
if (e.sub)
|
|
231
|
+
console.log(` ${e.sub}`);
|
|
232
|
+
}
|
|
233
|
+
while (true) {
|
|
234
|
+
const ans = (await safeQuestion(rl, `选择 [${defaultIdx.map(i => i + 1).join(',') || '无'}]: `)).trim();
|
|
235
|
+
if (!ans)
|
|
236
|
+
return [...defaultIdx];
|
|
237
|
+
if (ans.toLowerCase() === 'a')
|
|
238
|
+
return entries.map((_, i) => i);
|
|
239
|
+
if (ans.toLowerCase() === 'n')
|
|
240
|
+
return [];
|
|
241
|
+
const tokens = ans.split(/[,\s]+/).filter(Boolean);
|
|
242
|
+
const out = [];
|
|
243
|
+
let bad = false;
|
|
244
|
+
for (const t of tokens) {
|
|
245
|
+
const n = Number(t);
|
|
246
|
+
if (!Number.isInteger(n) || n < 1 || n > entries.length) {
|
|
247
|
+
bad = true;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
out.push(n - 1);
|
|
251
|
+
}
|
|
252
|
+
if (!bad)
|
|
253
|
+
return [...new Set(out)];
|
|
254
|
+
console.log(' 存在无效编号,请重新输入。');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function askBool(rl, prompt, def) {
|
|
258
|
+
const hint = def ? 'Y/n' : 'y/N';
|
|
259
|
+
while (true) {
|
|
260
|
+
const ans = (await safeQuestion(rl, `${prompt} [${hint}]: `)).trim().toLowerCase();
|
|
261
|
+
if (!ans)
|
|
262
|
+
return def;
|
|
263
|
+
if (['y', 'yes'].includes(ans))
|
|
264
|
+
return true;
|
|
265
|
+
if (['n', 'no'].includes(ans))
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
export async function runInitWizardIfNeeded(opts = {}) {
|
|
270
|
+
const configPath = opts.configPath ?? resolve(process.cwd(), 'aalis.config.yaml');
|
|
271
|
+
if (existsSync(configPath))
|
|
272
|
+
return false;
|
|
273
|
+
if (opts.requireTty !== false && !input.isTTY) {
|
|
274
|
+
console.warn('[init] 检测到 aalis.config.yaml 不存在,但当前 stdin 非 TTY,跳过交互式初始化。');
|
|
275
|
+
console.warn('[init] 请手动创建 aalis.config.yaml 后再启动。');
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
console.log('\n========================================');
|
|
279
|
+
console.log(' Aalis 首次启动 · 交互式初始化');
|
|
280
|
+
console.log('========================================');
|
|
281
|
+
console.log('未检测到 aalis.config.yaml,正在扫描可用插件…');
|
|
282
|
+
const localMetas = await discoverPluginMetas(process.cwd());
|
|
283
|
+
console.log(`本地发现 ${localMetas.length} 个插件(packages/)。`);
|
|
284
|
+
// ── 在线 registry(可选) ──
|
|
285
|
+
// packages/ 下没有插件时强烈建议接入;否则询问是否补全。
|
|
286
|
+
let registryUrl = '';
|
|
287
|
+
let registryName = 'default';
|
|
288
|
+
let registryPublicKey = '';
|
|
289
|
+
let remoteEntries = [];
|
|
290
|
+
const rl = readline.createInterface({ input, output });
|
|
291
|
+
try {
|
|
292
|
+
const wantOnline = await askBool(rl, localMetas.length === 0
|
|
293
|
+
? '本地没有任何插件,是否从在线 registry 拉取?'
|
|
294
|
+
: '是否从在线 registry 补全插件清单?', localMetas.length === 0);
|
|
295
|
+
if (wantOnline) {
|
|
296
|
+
const defaultUrl = 'http://127.0.0.1:7820';
|
|
297
|
+
registryUrl = (await safeQuestion(rl, `Registry URL [${defaultUrl}]: `)).trim() || defaultUrl;
|
|
298
|
+
registryName = (await safeQuestion(rl, `Registry 名称 [default]: `)).trim() || 'default';
|
|
299
|
+
registryPublicKey = (await safeQuestion(rl, `Registry 公钥(base64,可留空跳过签名校验): `)).trim();
|
|
300
|
+
try {
|
|
301
|
+
const bootstrap = new MarketplaceBootstrap(registryUrl);
|
|
302
|
+
remoteEntries = await bootstrap.listPlugins();
|
|
303
|
+
console.log(`在线发现 ${remoteEntries.length} 个插件。`);
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
console.warn(`[init] 拉取 registry 失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
307
|
+
console.warn(`[init] 跳过在线流程,仅使用本地插件。`);
|
|
308
|
+
registryUrl = '';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// 合并:本地优先(同名取本地版本)
|
|
312
|
+
const localNames = new Set(localMetas.map(m => m.name));
|
|
313
|
+
const remoteOnlyMetas = remoteEntries
|
|
314
|
+
.filter(e => !localNames.has(e.name))
|
|
315
|
+
.map(remoteEntryToMeta);
|
|
316
|
+
const metas = [...localMetas, ...remoteOnlyMetas]
|
|
317
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
318
|
+
if (metas.length === 0) {
|
|
319
|
+
console.error('[init] 未发现任何插件。请确认 packages/ 已 build,或正确配置 registry URL。');
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
console.log(`合并后共 ${metas.length} 个插件,按服务分组如下。\n`);
|
|
323
|
+
console.log('提示:Aalis 是多服务架构 —— 同一服务可以同时启用多个插件,');
|
|
324
|
+
console.log(' 运行时由 servicePreferences 决定首选;不需要的服务可以一个都不选。');
|
|
325
|
+
if (remoteOnlyMetas.length) {
|
|
326
|
+
console.log(` 标记 [远程] 的插件将自动从 ${registryUrl} 下载到 packages/。`);
|
|
327
|
+
}
|
|
328
|
+
console.log('');
|
|
329
|
+
const groups = groupByService(metas);
|
|
330
|
+
const enabled = new Set();
|
|
331
|
+
let step = 1;
|
|
332
|
+
const total = groups.length;
|
|
333
|
+
for (const g of groups) {
|
|
334
|
+
const defaultIdx = [];
|
|
335
|
+
if (g.recommended && g.members.length > 0)
|
|
336
|
+
defaultIdx.push(0);
|
|
337
|
+
const entries = g.members.map(m => {
|
|
338
|
+
const tag = m.origin === 'remote' ? `${dim('[远程]')} ` : '';
|
|
339
|
+
return {
|
|
340
|
+
label: `${tag}${m.displayName ?? m.name} ${dim('(' + m.name + (m.remoteVersion ? '@' + m.remoteVersion : '') + ')')}`,
|
|
341
|
+
sub: trim(m.description, 110) || (m.injectRequired.length ? `依赖服务: ${m.injectRequired.join(', ')}` : ''),
|
|
342
|
+
};
|
|
343
|
+
});
|
|
344
|
+
const picked = await pickMany(rl, `【${step}/${total}】${g.label} —— ${g.members.length} 个候选${g.recommended ? '(推荐至少选一个)' : ''}`, entries, defaultIdx);
|
|
345
|
+
for (const i of picked)
|
|
346
|
+
enabled.add(g.members[i].name);
|
|
347
|
+
step++;
|
|
348
|
+
}
|
|
349
|
+
// ── 下载需要的远程插件 ──
|
|
350
|
+
const toDownload = metas.filter(m => m.origin === 'remote' && enabled.has(m.name));
|
|
351
|
+
if (toDownload.length) {
|
|
352
|
+
console.log(`\n正在下载 ${toDownload.length} 个远程插件到 packages/ ...`);
|
|
353
|
+
const bootstrap = new MarketplaceBootstrap(registryUrl);
|
|
354
|
+
const packagesDir = resolve(process.cwd(), 'packages');
|
|
355
|
+
const cacheDir = resolve(process.cwd(), 'data/marketplace/cache/tarballs');
|
|
356
|
+
const downloadFailed = [];
|
|
357
|
+
for (const m of toDownload) {
|
|
358
|
+
const ver = m.remoteVersion ?? 'latest';
|
|
359
|
+
try {
|
|
360
|
+
await bootstrap.installToPackages(m.name, ver, { packagesDir, cacheDir });
|
|
361
|
+
console.log(` ✓ ${m.name}@${ver}`);
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
365
|
+
console.warn(` ✗ ${m.name}@${ver}: ${msg}`);
|
|
366
|
+
downloadFailed.push(m.name);
|
|
367
|
+
enabled.delete(m.name);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (downloadFailed.length) {
|
|
371
|
+
console.warn(`[init] ${downloadFailed.length} 个插件下载失败,已从启用列表移除。`);
|
|
372
|
+
}
|
|
373
|
+
// 触发 pnpm install 让 workspace 重新解析
|
|
374
|
+
console.log('正在运行 pnpm install 以同步 workspace ...');
|
|
375
|
+
try {
|
|
376
|
+
await runRootPnpmInstall(process.cwd());
|
|
377
|
+
console.log('✓ pnpm install 完成');
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
console.warn(`[init] pnpm install 失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
381
|
+
console.warn('[init] 请稍后手动运行 `pnpm install && pnpm -r build`。');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// disabledPlugins:本地已存在但未启用的(远程未启用的不写入,避免列表噪声)
|
|
385
|
+
const disabledPlugins = localMetas
|
|
386
|
+
.filter(m => !enabled.has(m.name))
|
|
387
|
+
.map(m => m.name)
|
|
388
|
+
.sort();
|
|
389
|
+
// plugins 配置块:全部空对象,参数留待用户填
|
|
390
|
+
const plugins = {};
|
|
391
|
+
for (const name of [...enabled].sort())
|
|
392
|
+
plugins[name] = {};
|
|
393
|
+
// 若用户配置了 registry 且启用了 marketplace-client,把 registry 自动写入它的配置
|
|
394
|
+
if (registryUrl && plugins['@aalis/plugin-marketplace-client']) {
|
|
395
|
+
plugins['@aalis/plugin-marketplace-client'] = {
|
|
396
|
+
registries: [{
|
|
397
|
+
name: registryName,
|
|
398
|
+
url: registryUrl,
|
|
399
|
+
publicKey: registryPublicKey || undefined,
|
|
400
|
+
priority: 0,
|
|
401
|
+
timeoutMs: 15000,
|
|
402
|
+
acceptAudit: 'approved',
|
|
403
|
+
}],
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const cfg = {
|
|
407
|
+
name: 'Aalis',
|
|
408
|
+
logLevel: 'info',
|
|
409
|
+
plugins,
|
|
410
|
+
disabledPlugins,
|
|
411
|
+
};
|
|
412
|
+
const yaml = '# Aalis 配置文件(由 init 向导生成,可随时手改)\n' +
|
|
413
|
+
'# - plugins: 启用的插件及其配置\n' +
|
|
414
|
+
'# - disabledPlugins: 显式禁用的本地插件(启动时不加载)\n' +
|
|
415
|
+
'# 文档:docs/architecture.md / docs/plugin-development.md\n\n' +
|
|
416
|
+
stringifyYaml(cfg, { lineWidth: 0 });
|
|
417
|
+
writeFileSync(configPath, yaml, 'utf-8');
|
|
418
|
+
console.log(`\n✓ 已写入 ${configPath}`);
|
|
419
|
+
console.log(` 启用 ${enabled.size} 个插件,显式禁用 ${disabledPlugins.length} 个。`);
|
|
420
|
+
// 末尾提醒:启用了但需要外部配置的插件
|
|
421
|
+
const needsConfig = [];
|
|
422
|
+
for (const name of enabled) {
|
|
423
|
+
if (name in EXTERNAL_HINTS)
|
|
424
|
+
needsConfig.push({ name, hint: EXTERNAL_HINTS[name] });
|
|
425
|
+
}
|
|
426
|
+
if (needsConfig.length) {
|
|
427
|
+
console.log('\n⚠ 以下插件已启用但通常需要进一步配置(启动后请到 aalis.config.yaml 或 WebUI 填写):');
|
|
428
|
+
for (const n of needsConfig)
|
|
429
|
+
console.log(` · ${n.name}:${n.hint}`);
|
|
430
|
+
}
|
|
431
|
+
console.log('\n 即将启动 Aalis...\n');
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
if (err instanceof StdinClosedError) {
|
|
436
|
+
console.error('\n[init] 输入流已关闭,初始化向导被中止。');
|
|
437
|
+
console.error('[init] 请重新运行 `pnpm start` 并完成所有问题。');
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
throw err;
|
|
441
|
+
}
|
|
442
|
+
finally {
|
|
443
|
+
rl.close();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// ─────────────────────── helpers ───────────────────────
|
|
447
|
+
function trim(s, n) {
|
|
448
|
+
if (!s)
|
|
449
|
+
return '';
|
|
450
|
+
return s.length > n ? s.slice(0, n - 1) + '…' : s;
|
|
451
|
+
}
|
|
452
|
+
function dim(s) {
|
|
453
|
+
return process.stdout.isTTY ? `\x1b[2m${s}\x1b[0m` : s;
|
|
454
|
+
}
|
|
455
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-router.d.ts","sourceRoot":"","sources":["../src/llm-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,eAAe;AACf,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAwB;AACxB,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD;;;;;;;;;;;GAWG;AACH,qBAAa,SAAS;IAOR,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAW,OAAO,CAAC,QAAQ,CAAC,MAAM;IANlE,OAAO,CAAC,MAAM,CAAoC;IAClD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAA6C;IAElE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAU;gBAEd,GAAG,EAAE,OAAO,EAAmB,MAAM,EAAE,MAAM;IAE1E;;;;;;OAMG;IACG,aAAa,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAmBrD;;;;;;;;;;OAUG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAsBnF;;;OAGG;IACH,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAInD,4CAA4C;IAC5C,UAAU,IAAI,IAAI;IAKlB,OAAO,CAAC,YAAY;CA2BrB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM 路由器
|
|
3
|
+
*
|
|
4
|
+
* 负责:
|
|
5
|
+
* 1. 聚合所有已注册 'llm' 服务的模型列表。
|
|
6
|
+
* 2. 按 model ID 反查所属提供者(带缓存,服务变更时自动失效)。
|
|
7
|
+
* 3. 作为后续扩展点(负载均衡、能力过滤、成本路由等)的载体。
|
|
8
|
+
*
|
|
9
|
+
* 本类不持有全局状态:每个 Context 拥有一份实例,缓存在实例上。
|
|
10
|
+
* 由 ServiceContainer 共享真实数据源,所以同一 App 下不同子 Context
|
|
11
|
+
* 的路由结果一致。
|
|
12
|
+
*/
|
|
13
|
+
export class LLMRouter {
|
|
14
|
+
ctx;
|
|
15
|
+
logger;
|
|
16
|
+
_cache = null;
|
|
17
|
+
_cacheTime = 0;
|
|
18
|
+
_cachePromise = null;
|
|
19
|
+
static CACHE_TTL = 60_000;
|
|
20
|
+
constructor(ctx, logger) {
|
|
21
|
+
this.ctx = ctx;
|
|
22
|
+
this.logger = logger;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 聚合所有 LLM 提供者的模型列表
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const models = await router.listAllModels();
|
|
29
|
+
* // [{ id: 'gpt-4o', capabilities: [...], provider: 'OpenAI', contextId: '...' }, ...]
|
|
30
|
+
*/
|
|
31
|
+
async listAllModels() {
|
|
32
|
+
const providers = this.ctx.getAllServices('llm');
|
|
33
|
+
const results = [];
|
|
34
|
+
await Promise.all(providers.map(async ({ instance, contextId, label }) => {
|
|
35
|
+
if (typeof instance.listModels !== 'function')
|
|
36
|
+
return;
|
|
37
|
+
try {
|
|
38
|
+
const models = await instance.listModels();
|
|
39
|
+
for (const m of models) {
|
|
40
|
+
results.push({ ...m, provider: label ?? contextId, contextId });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
this.logger.warn(`获取模型列表失败 [${contextId}]:`, err);
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
return results;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 按 model ID 查找拥有该模型的 LLM 提供者
|
|
51
|
+
*
|
|
52
|
+
* 解析顺序:
|
|
53
|
+
* 1. 若提供者实现了 `supportsModel(id)`,优先按此同步判断;
|
|
54
|
+
* 2. 否则回退到 `listModels()` 枚举构建缓存(TTL 60s)。
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const result = await router.resolveModelProvider('gpt-4o');
|
|
58
|
+
* if (result) await (result.instance as LLMService).chat({ messages, model: result.model });
|
|
59
|
+
*/
|
|
60
|
+
async resolveModelProvider(modelId) {
|
|
61
|
+
// 快路径:提供者自报支持
|
|
62
|
+
const providers = this.ctx.getAllServices('llm');
|
|
63
|
+
for (const { instance, contextId } of providers) {
|
|
64
|
+
if (typeof instance.supportsModel === 'function') {
|
|
65
|
+
try {
|
|
66
|
+
if (await instance.supportsModel(modelId)) {
|
|
67
|
+
return { instance, model: modelId, contextId };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch { /* ignore, fall back to enumeration */ }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 慢路径:缓存 + listModels 枚举
|
|
74
|
+
const cache = await this._ensureCache();
|
|
75
|
+
const targetContextId = cache.get(modelId);
|
|
76
|
+
if (!targetContextId)
|
|
77
|
+
return undefined;
|
|
78
|
+
const found = providers.find(p => p.contextId === targetContextId);
|
|
79
|
+
return found ? { instance: found.instance, model: modelId, contextId: targetContextId } : undefined;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 获取完整的 model→contextId 映射(带缓存)
|
|
83
|
+
* 供需要批量查找或自行路由的插件使用。
|
|
84
|
+
*/
|
|
85
|
+
getModelProviderMap() {
|
|
86
|
+
return this._ensureCache();
|
|
87
|
+
}
|
|
88
|
+
/** 使 model→provider 缓存立即失效(服务注册/注销时应当调用) */
|
|
89
|
+
invalidate() {
|
|
90
|
+
this._cache = null;
|
|
91
|
+
this._cachePromise = null;
|
|
92
|
+
}
|
|
93
|
+
_ensureCache() {
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
if (this._cache && (now - this._cacheTime) < LLMRouter.CACHE_TTL) {
|
|
96
|
+
return Promise.resolve(this._cache);
|
|
97
|
+
}
|
|
98
|
+
if (this._cachePromise)
|
|
99
|
+
return this._cachePromise;
|
|
100
|
+
this._cachePromise = (async () => {
|
|
101
|
+
const map = new Map();
|
|
102
|
+
const providers = this.ctx.getAllServices('llm');
|
|
103
|
+
for (const { instance, contextId } of providers) {
|
|
104
|
+
if (typeof instance.listModels !== 'function')
|
|
105
|
+
continue;
|
|
106
|
+
try {
|
|
107
|
+
const models = await instance.listModels();
|
|
108
|
+
for (const m of models) {
|
|
109
|
+
if (!map.has(m.id))
|
|
110
|
+
map.set(m.id, contextId);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch { /* skip unavailable provider */ }
|
|
114
|
+
}
|
|
115
|
+
this._cache = map;
|
|
116
|
+
this._cacheTime = Date.now();
|
|
117
|
+
this._cachePromise = null;
|
|
118
|
+
return map;
|
|
119
|
+
})();
|
|
120
|
+
return this._cachePromise;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=llm-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-router.js","sourceRoot":"","sources":["../src/llm-router.ts"],"names":[],"mappings":"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"}
|