kc-beta 0.1.2 → 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/bin/kc-beta.js +14 -2
- package/package.json +1 -1
- package/src/agent/context-window.js +151 -0
- package/src/agent/context.js +8 -4
- package/src/agent/engine.js +261 -8
- package/src/agent/event-log.js +111 -0
- package/src/agent/llm-client.js +352 -59
- package/src/agent/pipelines/base.js +6 -0
- package/src/agent/pipelines/distillation.js +18 -0
- package/src/agent/pipelines/extraction.js +21 -0
- package/src/agent/pipelines/initializer.js +75 -14
- package/src/agent/pipelines/production-qc.js +19 -0
- package/src/agent/pipelines/skill-authoring.js +14 -0
- package/src/agent/pipelines/skill-testing.js +20 -0
- package/src/agent/retry.js +83 -0
- package/src/agent/session-state.js +79 -0
- package/src/agent/skill-loader.js +13 -1
- package/src/agent/token-counter.js +62 -0
- package/src/agent/tools/document-parse.js +104 -21
- package/src/agent/tools/document-search.js +24 -8
- package/src/agent/tools/sandbox-exec.js +16 -5
- package/src/agent/tools/web-search.js +107 -0
- package/src/agent/tools/worker-llm-call.js +14 -5
- package/src/agent/tools/workspace-file.js +47 -20
- package/src/agent/workspace.js +24 -1
- package/src/cli/components.js +24 -5
- package/src/cli/config.js +340 -0
- package/src/cli/index.js +113 -11
- package/src/cli/onboard.js +216 -53
- package/src/config.js +63 -10
- package/src/model-tiers.json +153 -0
- package/src/providers.js +367 -0
- package/template/AGENT.md +20 -0
- package/template/skills/en/meta/compliance-judgment/SKILL.md +10 -42
- package/template/skills/en/meta/document-chunking/SKILL.md +32 -0
- package/template/skills/en/meta/document-parsing/SKILL.md +11 -18
- package/template/skills/en/meta/entity-extraction/SKILL.md +13 -28
- package/template/skills/en/meta/tree-processing/SKILL.md +19 -1
- package/template/skills/en/meta-meta/auto-model-selection/SKILL.md +53 -0
- package/template/skills/en/meta-meta/pdf-review-dashboard/SKILL.md +57 -0
- package/template/skills/en/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
- package/template/skills/en/meta-meta/rule-extraction/SKILL.md +24 -1
- package/template/skills/en/meta-meta/skill-authoring/SKILL.md +6 -0
- package/template/skills/en/meta-meta/skill-to-workflow/SKILL.md +4 -0
- package/template/skills/zh/meta/compliance-judgment/SKILL.md +41 -262
- package/template/skills/zh/meta/document-chunking/SKILL.md +32 -0
- package/template/skills/zh/meta/document-parsing/SKILL.md +65 -132
- package/template/skills/zh/meta/entity-extraction/SKILL.md +68 -230
- package/template/skills/zh/meta/tree-processing/SKILL.md +82 -194
- package/template/skills/zh/meta-meta/auto-model-selection/SKILL.md +51 -0
- package/template/skills/zh/meta-meta/pdf-review-dashboard/SKILL.md +55 -0
- package/template/skills/zh/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
- package/template/skills/zh/meta-meta/rule-extraction/SKILL.md +79 -164
- package/template/skills/zh/meta-meta/skill-authoring/SKILL.md +64 -185
- package/template/skills/zh/meta-meta/skill-to-workflow/SKILL.md +95 -216
package/src/cli/onboard.js
CHANGED
|
@@ -2,6 +2,8 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import readline from "node:readline";
|
|
4
4
|
import os from "node:os";
|
|
5
|
+
import { getProviders, getProviderById, getProviderLabels, classifyModels, getCuratedModels } from "../providers.js";
|
|
6
|
+
import { LLMClient } from "../agent/llm-client.js";
|
|
5
7
|
|
|
6
8
|
const CONFIG_DIR = path.join(os.homedir(), ".kc_agent");
|
|
7
9
|
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
@@ -23,27 +25,33 @@ const L = {
|
|
|
23
25
|
langPrompt: "Language",
|
|
24
26
|
langOptions: ["English", "中文"],
|
|
25
27
|
providerPrompt: "LLM Provider",
|
|
26
|
-
providerLabels: [
|
|
27
|
-
"SiliconFlow (recommended for China)",
|
|
28
|
-
"Aliyun Bailian",
|
|
29
|
-
"Anthropic",
|
|
30
|
-
"OpenAI",
|
|
31
|
-
"Custom (enter base URL)",
|
|
32
|
-
],
|
|
33
28
|
current: "current",
|
|
34
29
|
choose: "Choose",
|
|
35
30
|
baseUrl: "Base URL",
|
|
36
31
|
baseUrlRequired: "Base URL is required for custom provider.",
|
|
37
32
|
apiKey: "API Key",
|
|
38
33
|
apiKeyRequired: "required",
|
|
39
|
-
apiKeyKeep: "Enter to keep",
|
|
34
|
+
apiKeyKeep: "Press Enter to keep",
|
|
40
35
|
apiKeyMissing: "API key is required. Run 'kc-beta onboard' again.",
|
|
36
|
+
keyType: "Key Type",
|
|
37
|
+
keyTypeOptions: ["API Key (pay-per-use)", "Coding Plan Key (subscription)"],
|
|
41
38
|
conductorModel: "Conductor Model",
|
|
42
39
|
workerTiers: "Worker LLM Tiers",
|
|
43
|
-
|
|
40
|
+
vlmTiers: "VLM Tiers (Vision/OCR)",
|
|
41
|
+
tierHint: "Press Enter to accept defaults",
|
|
42
|
+
workerConfig: "Worker LLM Provider",
|
|
43
|
+
workerSameProvider: "Use same provider for worker LLMs?",
|
|
44
|
+
yesNo: "Y/n",
|
|
44
45
|
accuracy: "Accuracy Threshold",
|
|
45
46
|
saved: "Saved to",
|
|
46
47
|
runHint: "Run {cmd} to start the agent.",
|
|
48
|
+
discovering: "Discovering available models...",
|
|
49
|
+
discoveryFailed: "Could not auto-discover models. Using provider defaults.",
|
|
50
|
+
discoveryFound: "Found {n} models. Suggested tier assignments:",
|
|
51
|
+
discoveryAccept: "Press Enter to accept, or type model name to override",
|
|
52
|
+
enterSkip: "Press Enter to skip",
|
|
53
|
+
enterDefault: "Press Enter to use default",
|
|
54
|
+
bedrockWarn: "AWS Bedrock is not yet fully supported. Authentication will fail at runtime.",
|
|
47
55
|
},
|
|
48
56
|
zh: {
|
|
49
57
|
title: "KC Agent 配置向导",
|
|
@@ -51,13 +59,6 @@ const L = {
|
|
|
51
59
|
langPrompt: "语言",
|
|
52
60
|
langOptions: ["English", "中文"],
|
|
53
61
|
providerPrompt: "大模型服务商",
|
|
54
|
-
providerLabels: [
|
|
55
|
-
"SiliconFlow(国内推荐)",
|
|
56
|
-
"阿里云百炼",
|
|
57
|
-
"Anthropic",
|
|
58
|
-
"OpenAI",
|
|
59
|
-
"自定义(输入接口地址)",
|
|
60
|
-
],
|
|
61
62
|
current: "当前",
|
|
62
63
|
choose: "选择",
|
|
63
64
|
baseUrl: "接口地址",
|
|
@@ -66,31 +67,37 @@ const L = {
|
|
|
66
67
|
apiKeyRequired: "必填",
|
|
67
68
|
apiKeyKeep: "回车保留当前密钥",
|
|
68
69
|
apiKeyMissing: "API 密钥为必填项。请重新运行 'kc-beta onboard'。",
|
|
70
|
+
keyType: "密钥类型",
|
|
71
|
+
keyTypeOptions: ["API Key(按量付费)", "Coding Plan Key(包年包月)"],
|
|
69
72
|
conductorModel: "主模型",
|
|
70
73
|
workerTiers: "Worker 模型分层",
|
|
74
|
+
vlmTiers: "VLM 视觉模型分层(OCR)",
|
|
71
75
|
tierHint: "回车接受默认值",
|
|
76
|
+
workerConfig: "Worker LLM 服务商",
|
|
77
|
+
workerSameProvider: "Worker LLM 使用同一服务商?",
|
|
78
|
+
yesNo: "Y/n",
|
|
72
79
|
accuracy: "准确率阈值",
|
|
73
80
|
saved: "已保存至",
|
|
74
81
|
runHint: "运行 {cmd} 启动 Agent。",
|
|
82
|
+
discovering: "正在发现可用模型...",
|
|
83
|
+
discoveryFailed: "无法自动发现模型,使用默认配置。",
|
|
84
|
+
discoveryFound: "发现 {n} 个模型。建议分层:",
|
|
85
|
+
discoveryAccept: "回车接受,或输入模型名称覆盖",
|
|
86
|
+
enterSkip: "回车跳过",
|
|
87
|
+
enterDefault: "回车使用默认值",
|
|
88
|
+
bedrockWarn: "AWS Bedrock 尚未完全支持。运行时认证将失败。",
|
|
75
89
|
},
|
|
76
90
|
};
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
{ name: "SiliconFlow", base_url: "https://api.siliconflow.cn/v1", model: "Pro/zai-org/GLM-5",
|
|
80
|
-
tiers: { tier1: "Pro/zai-org/GLM-5, Pro/moonshotai/Kimi-K2.5", tier2: "Pro/deepseek-ai/DeepSeek-V3.2, Pro/MiniMaxAI/MiniMax-M2.5", tier3: "Qwen/Qwen3.5-122B-A10B", tier4: "Qwen/Qwen3.5-35B-A3B" } },
|
|
81
|
-
{ name: "Aliyun", base_url: "https://coding.dashscope.aliyuncs.com/v1", model: "glm-5",
|
|
82
|
-
tiers: { tier1: "glm-5", tier2: "deepseek-v3", tier3: "qwen-plus", tier4: "qwen-turbo" } },
|
|
83
|
-
{ name: "Anthropic", base_url: "https://api.anthropic.com/v1", model: "claude-sonnet-4-20250514",
|
|
84
|
-
tiers: { tier1: "claude-sonnet-4-20250514", tier2: "claude-sonnet-4-20250514", tier3: "claude-haiku-4-5-20251001", tier4: "claude-haiku-4-5-20251001" } },
|
|
85
|
-
{ name: "OpenAI", base_url: "https://api.openai.com/v1", model: "gpt-4o",
|
|
86
|
-
tiers: { tier1: "gpt-4o", tier2: "gpt-4o-mini", tier3: "gpt-4o-mini", tier4: "gpt-4o-mini" } },
|
|
87
|
-
{ name: "Custom", base_url: "", model: "", tiers: { tier1: "", tier2: "", tier3: "", tier4: "" } },
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
function ask(rl, question, defaultValue = "") {
|
|
92
|
+
function ask(rl, question, defaultValue = "", hint = "") {
|
|
91
93
|
const suffix = defaultValue ? ` ${DIM}[${defaultValue}]${RESET}` : "";
|
|
94
|
+
const hintText = hint
|
|
95
|
+
? ` ${GRAY}(${hint})${RESET}`
|
|
96
|
+
: defaultValue
|
|
97
|
+
? ` ${GRAY}(Press Enter to keep)${RESET}`
|
|
98
|
+
: "";
|
|
92
99
|
return new Promise((resolve) => {
|
|
93
|
-
rl.question(`${question}${suffix}: `, (answer) => resolve(answer.trim() || defaultValue));
|
|
100
|
+
rl.question(`${question}${suffix}${hintText}: `, (answer) => resolve(answer.trim() || defaultValue));
|
|
94
101
|
});
|
|
95
102
|
}
|
|
96
103
|
|
|
@@ -101,11 +108,14 @@ export async function onboard() {
|
|
|
101
108
|
if (fs.existsSync(CONFIG_PATH)) {
|
|
102
109
|
try { existing = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); } catch { /* ignore */ }
|
|
103
110
|
}
|
|
111
|
+
const isUpdate = Object.keys(existing).length > 0;
|
|
104
112
|
|
|
105
113
|
console.log();
|
|
106
114
|
console.log(` ${BOLD}KC Agent Setup / KC Agent 配置向导${RESET}`);
|
|
107
115
|
console.log(` ${GRAY}${"─".repeat(40)}${RESET}`);
|
|
108
116
|
console.log();
|
|
117
|
+
|
|
118
|
+
// --- Language ---
|
|
109
119
|
console.log(` ${CYAN}Language / 语言:${RESET}`);
|
|
110
120
|
console.log(` 1. English`);
|
|
111
121
|
console.log(` 2. 中文`);
|
|
@@ -115,69 +125,218 @@ export async function onboard() {
|
|
|
115
125
|
const t = L[lang];
|
|
116
126
|
console.log();
|
|
117
127
|
|
|
118
|
-
if (
|
|
128
|
+
if (isUpdate) {
|
|
119
129
|
console.log(` ${DIM}${t.existingConfig}${RESET}`);
|
|
120
130
|
console.log();
|
|
121
131
|
}
|
|
122
132
|
|
|
133
|
+
// --- Provider ---
|
|
134
|
+
const providers = getProviders();
|
|
135
|
+
const labels = getProviderLabels(lang);
|
|
123
136
|
console.log(` ${CYAN}${t.providerPrompt}:${RESET}`);
|
|
124
|
-
for (let i = 0; i <
|
|
125
|
-
const marker =
|
|
126
|
-
console.log(` ${i + 1}. ${
|
|
137
|
+
for (let i = 0; i < labels.length; i++) {
|
|
138
|
+
const marker = providers[i].id === existing.provider ? ` ${GREEN}(${t.current})${RESET}` : "";
|
|
139
|
+
console.log(` ${i + 1}. ${labels[i].label}${marker}`);
|
|
127
140
|
}
|
|
128
141
|
const providerIdx = parseInt(await ask(rl, ` ${GRAY}>${RESET} ${t.choose}`, "1"), 10) - 1;
|
|
129
|
-
const provider =
|
|
142
|
+
const provider = providers[Math.max(0, Math.min(providerIdx, providers.length - 1))];
|
|
130
143
|
console.log();
|
|
131
144
|
|
|
132
|
-
|
|
133
|
-
if (provider.
|
|
145
|
+
// Bedrock warning
|
|
146
|
+
if (provider.id === "bedrock") {
|
|
147
|
+
console.log(` ${YELLOW}⚠ ${t.bedrockWarn}${RESET}`);
|
|
148
|
+
console.log();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// --- Base URL ---
|
|
152
|
+
let baseUrl = provider.baseUrl;
|
|
153
|
+
if (provider.id === "custom") {
|
|
134
154
|
baseUrl = await ask(rl, ` ${t.baseUrl}`, existing.base_url || "");
|
|
135
155
|
if (!baseUrl) { console.log(` ${RED}${t.baseUrlRequired}${RESET}`); rl.close(); process.exit(1); }
|
|
156
|
+
console.log();
|
|
136
157
|
}
|
|
137
158
|
|
|
159
|
+
// --- Aliyun coding plan key sub-option ---
|
|
160
|
+
let useCodingPlan = false;
|
|
161
|
+
if (provider.supportsCodingPlanKey) {
|
|
162
|
+
console.log(` ${CYAN}${t.keyType}:${RESET}`);
|
|
163
|
+
console.log(` 1. ${t.keyTypeOptions[0]}`);
|
|
164
|
+
console.log(` 2. ${t.keyTypeOptions[1]}`);
|
|
165
|
+
const keyTypeChoice = await ask(rl, ` ${GRAY}>${RESET} ${t.choose}`, "1");
|
|
166
|
+
useCodingPlan = keyTypeChoice === "2";
|
|
167
|
+
if (useCodingPlan && provider.codingPlanUrl) {
|
|
168
|
+
baseUrl = provider.codingPlanUrl;
|
|
169
|
+
}
|
|
170
|
+
console.log();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// --- API Key ---
|
|
138
174
|
const maskedExisting = existing.api_key ? existing.api_key.slice(0, 6) + "..." + existing.api_key.slice(-4) : "";
|
|
175
|
+
const keyHint = maskedExisting ? t.apiKeyKeep : t.apiKeyRequired;
|
|
139
176
|
const keyPrompt = maskedExisting
|
|
140
|
-
? ` ${CYAN}${t.apiKey}${RESET} ${DIM}(${maskedExisting}
|
|
177
|
+
? ` ${CYAN}${t.apiKey}${RESET} ${DIM}(${maskedExisting})${RESET}`
|
|
141
178
|
: ` ${CYAN}${t.apiKey}${RESET} ${YELLOW}(${t.apiKeyRequired})${RESET}`;
|
|
142
|
-
const apiKey = await ask(rl, keyPrompt, "");
|
|
179
|
+
const apiKey = await ask(rl, keyPrompt, "", keyHint);
|
|
143
180
|
const finalKey = apiKey || existing.api_key || "";
|
|
144
181
|
if (!finalKey) { console.log(` ${RED}${t.apiKeyMissing}${RESET}`); rl.close(); process.exit(1); }
|
|
145
182
|
console.log();
|
|
146
183
|
|
|
147
|
-
|
|
148
|
-
|
|
184
|
+
// --- Auto-discovery ---
|
|
185
|
+
let discoveredModels = null;
|
|
186
|
+
let suggestedTiers = null;
|
|
187
|
+
let suggestedConductor = null;
|
|
188
|
+
|
|
189
|
+
// Try curated models first (for providers without /models endpoint)
|
|
190
|
+
const curated = getCuratedModels(provider.id);
|
|
191
|
+
|
|
192
|
+
if (curated) {
|
|
193
|
+
// Use curated model list
|
|
194
|
+
discoveredModels = curated;
|
|
195
|
+
const classified = classifyModels(curated);
|
|
196
|
+
suggestedTiers = classified.tiers;
|
|
197
|
+
suggestedConductor = classified.conductor;
|
|
198
|
+
console.log(` ${GREEN}✓${RESET} ${t.discoveryFound.replace("{n}", curated.length)}`);
|
|
199
|
+
if (suggestedConductor) {
|
|
200
|
+
console.log(` ${DIM}Conductor: ${suggestedConductor}${RESET}`);
|
|
201
|
+
}
|
|
202
|
+
for (const [tier, models] of Object.entries(suggestedTiers)) {
|
|
203
|
+
if (models) console.log(` ${DIM}${tier.toUpperCase()}: ${models}${RESET}`);
|
|
204
|
+
}
|
|
205
|
+
console.log();
|
|
206
|
+
} else if (provider.modelsEndpoint) {
|
|
207
|
+
// Query /models endpoint
|
|
208
|
+
console.log(` ${DIM}${t.discovering}${RESET}`);
|
|
209
|
+
try {
|
|
210
|
+
const tempClient = new LLMClient({
|
|
211
|
+
apiKey: finalKey,
|
|
212
|
+
baseUrl: baseUrl,
|
|
213
|
+
authType: provider.authType,
|
|
214
|
+
apiFormat: provider.apiFormat,
|
|
215
|
+
});
|
|
216
|
+
discoveredModels = await tempClient.listModels();
|
|
217
|
+
|
|
218
|
+
if (discoveredModels && discoveredModels.length > 0) {
|
|
219
|
+
const classified = classifyModels(discoveredModels);
|
|
220
|
+
suggestedTiers = classified.tiers;
|
|
221
|
+
suggestedConductor = classified.conductor;
|
|
222
|
+
console.log(` ${GREEN}✓${RESET} ${t.discoveryFound.replace("{n}", discoveredModels.length)}`);
|
|
223
|
+
if (suggestedConductor) {
|
|
224
|
+
console.log(` ${DIM}Conductor: ${suggestedConductor}${RESET}`);
|
|
225
|
+
}
|
|
226
|
+
for (const [tier, models] of Object.entries(suggestedTiers)) {
|
|
227
|
+
if (models) console.log(` ${DIM}${tier.toUpperCase()}: ${models}${RESET}`);
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
console.log(` ${DIM}${t.discoveryFailed}${RESET}`);
|
|
231
|
+
}
|
|
232
|
+
} catch {
|
|
233
|
+
console.log(` ${DIM}${t.discoveryFailed}${RESET}`);
|
|
234
|
+
}
|
|
235
|
+
console.log();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// --- Conductor model ---
|
|
239
|
+
const defaultModel = suggestedConductor || provider.defaultModel || existing.conductor_model || "";
|
|
240
|
+
const model = await ask(
|
|
241
|
+
rl,
|
|
242
|
+
` ${CYAN}${t.conductorModel}${RESET}`,
|
|
243
|
+
defaultModel,
|
|
244
|
+
isUpdate ? t.enterDefault : "",
|
|
245
|
+
);
|
|
149
246
|
console.log();
|
|
150
247
|
|
|
248
|
+
// --- Worker LLM tiers ---
|
|
151
249
|
console.log(` ${CYAN}${t.workerTiers}${RESET} ${DIM}(${t.tierHint})${RESET}`);
|
|
152
250
|
const tiers = {};
|
|
153
251
|
for (const tier of ["tier1", "tier2", "tier3", "tier4"]) {
|
|
154
|
-
const def = provider.
|
|
155
|
-
tiers[tier] = await ask(
|
|
252
|
+
const def = suggestedTiers?.[tier] || provider.defaultTiers[tier] || existing?.tiers?.[tier] || "";
|
|
253
|
+
tiers[tier] = await ask(
|
|
254
|
+
rl,
|
|
255
|
+
` ${tier.toUpperCase()}`,
|
|
256
|
+
def,
|
|
257
|
+
t.discoveryAccept ? "" : "",
|
|
258
|
+
);
|
|
156
259
|
}
|
|
157
260
|
console.log();
|
|
158
261
|
|
|
159
|
-
|
|
160
|
-
|
|
262
|
+
// --- VLM tiers (vision/OCR) ---
|
|
263
|
+
console.log(` ${CYAN}${t.vlmTiers}${RESET} ${DIM}(${t.tierHint})${RESET}`);
|
|
264
|
+
const vlmTiers = {};
|
|
265
|
+
for (const tier of ["tier1", "tier2", "tier3"]) {
|
|
266
|
+
const def = provider.defaultVlm?.[tier] || existing?.vlm_tiers?.[tier] || "";
|
|
267
|
+
vlmTiers[tier] = await ask(
|
|
268
|
+
rl,
|
|
269
|
+
` ${tier.toUpperCase()}`,
|
|
270
|
+
def,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
161
273
|
console.log();
|
|
162
274
|
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
275
|
+
// --- Worker LLM provider (optional) ---
|
|
276
|
+
console.log(` ${CYAN}${t.workerConfig}${RESET}`);
|
|
277
|
+
const sameProvider = await ask(rl, ` ${t.workerSameProvider}`, "Y", t.yesNo);
|
|
278
|
+
let workerProvider = "";
|
|
279
|
+
let workerApiKey = "";
|
|
280
|
+
let workerBaseUrl = "";
|
|
281
|
+
let workerAuthType = "";
|
|
282
|
+
let workerApiFormat = "";
|
|
283
|
+
|
|
284
|
+
if (sameProvider.toLowerCase() === "n" || sameProvider.toLowerCase() === "no") {
|
|
285
|
+
// Pick a different provider for workers
|
|
286
|
+
console.log();
|
|
287
|
+
console.log(` ${CYAN}${t.providerPrompt} (Worker):${RESET}`);
|
|
288
|
+
for (let i = 0; i < labels.length; i++) {
|
|
289
|
+
console.log(` ${i + 1}. ${labels[i].label}`);
|
|
290
|
+
}
|
|
291
|
+
const wIdx = parseInt(await ask(rl, ` ${GRAY}>${RESET} ${t.choose}`, "1"), 10) - 1;
|
|
292
|
+
const wp = providers[Math.max(0, Math.min(wIdx, providers.length - 1))];
|
|
293
|
+
workerProvider = wp.id;
|
|
294
|
+
workerAuthType = wp.authType;
|
|
295
|
+
workerApiFormat = wp.apiFormat;
|
|
296
|
+
workerBaseUrl = wp.baseUrl;
|
|
297
|
+
|
|
298
|
+
if (wp.id === "custom") {
|
|
299
|
+
workerBaseUrl = await ask(rl, ` ${t.baseUrl}`, existing.worker_base_url || "");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Worker API key
|
|
303
|
+
const wMasked = existing.worker_api_key ? existing.worker_api_key.slice(0, 6) + "..." + existing.worker_api_key.slice(-4) : "";
|
|
304
|
+
const wKeyHint = wMasked ? t.apiKeyKeep : t.apiKeyRequired;
|
|
305
|
+
workerApiKey = await ask(
|
|
306
|
+
rl,
|
|
307
|
+
` ${CYAN}${t.apiKey} (Worker)${RESET}`,
|
|
308
|
+
"",
|
|
309
|
+
wKeyHint,
|
|
310
|
+
);
|
|
311
|
+
workerApiKey = workerApiKey || existing.worker_api_key || "";
|
|
312
|
+
}
|
|
170
313
|
console.log();
|
|
171
314
|
|
|
172
315
|
rl.close();
|
|
173
316
|
|
|
317
|
+
// Preserve existing thresholds or set defaults (editable via 'kc-beta config')
|
|
318
|
+
const accuracy = existing.accuracy_threshold ?? 0.9;
|
|
319
|
+
const systemicThreshold = existing.systemic_threshold ?? 0.10;
|
|
320
|
+
const spotCheckRate = existing.spot_check_rate ?? 0.10;
|
|
321
|
+
const tierTolerance = existing.tier_tolerance ?? 0.05;
|
|
322
|
+
|
|
174
323
|
const config = {
|
|
175
324
|
language: lang,
|
|
176
|
-
provider: provider.
|
|
325
|
+
provider: provider.id,
|
|
177
326
|
api_key: finalKey,
|
|
178
327
|
base_url: baseUrl,
|
|
328
|
+
auth_type: provider.authType,
|
|
329
|
+
api_format: provider.apiFormat,
|
|
179
330
|
conductor_model: model,
|
|
180
331
|
tiers,
|
|
332
|
+
vlm_tiers: vlmTiers,
|
|
333
|
+
// Worker LLM (optional — empty means use conductor config)
|
|
334
|
+
worker_provider: workerProvider,
|
|
335
|
+
worker_api_key: workerApiKey,
|
|
336
|
+
worker_base_url: workerBaseUrl,
|
|
337
|
+
worker_auth_type: workerAuthType,
|
|
338
|
+
worker_api_format: workerApiFormat,
|
|
339
|
+
// Thresholds
|
|
181
340
|
accuracy_threshold: accuracy,
|
|
182
341
|
systemic_threshold: systemicThreshold,
|
|
183
342
|
spot_check_rate: spotCheckRate,
|
|
@@ -190,5 +349,9 @@ export async function onboard() {
|
|
|
190
349
|
console.log(` ${GREEN}✓${RESET} ${t.saved} ${GRAY}${CONFIG_PATH}${RESET}`);
|
|
191
350
|
console.log();
|
|
192
351
|
console.log(` ${t.runHint.replace("{cmd}", `${BOLD}kc-beta${RESET}`)}`);
|
|
352
|
+
const configHint = lang === "zh"
|
|
353
|
+
? ` ${DIM}运行 ${BOLD}kc-beta config${RESET}${DIM} 调整阈值和高级设置。${RESET}`
|
|
354
|
+
: ` ${DIM}Run ${BOLD}kc-beta config${RESET}${DIM} to adjust thresholds and advanced settings.${RESET}`;
|
|
355
|
+
console.log(configHint);
|
|
193
356
|
console.log();
|
|
194
357
|
}
|
package/src/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import os from "node:os";
|
|
4
|
+
import { getProviderById } from "./providers.js";
|
|
4
5
|
|
|
5
6
|
const GLOBAL_CONFIG_DIR = path.join(os.homedir(), ".kc_agent");
|
|
6
7
|
const GLOBAL_CONFIG_PATH = path.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
@@ -43,31 +44,46 @@ function loadEnvFile(envPath) {
|
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* Load settings by merging: global config (lowest) -> workspace .env (highest).
|
|
47
|
+
* Supports both new generic keys (LLM_API_KEY) and legacy keys (SILICONFLOW_API_KEY).
|
|
46
48
|
* @param {string} [workspacePath] - Optional workspace directory for .env override
|
|
47
49
|
*/
|
|
48
50
|
export function loadSettings(workspacePath) {
|
|
49
51
|
const gc = loadGlobalConfig();
|
|
50
52
|
const env = workspacePath ? loadEnvFile(path.join(workspacePath, ".env")) : {};
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Resolve provider metadata for authType/apiFormat defaults
|
|
55
|
+
const provider = gc.provider || "siliconflow";
|
|
56
|
+
const providerDef = getProviderById(provider);
|
|
57
|
+
|
|
58
|
+
const settings = {
|
|
59
|
+
// Provider identity
|
|
60
|
+
provider,
|
|
61
|
+
authType: gc.auth_type || providerDef?.authType || "bearer",
|
|
62
|
+
apiFormat: gc.api_format || providerDef?.apiFormat || "openai",
|
|
63
|
+
|
|
64
|
+
// Conductor LLM (generic keys with legacy fallback)
|
|
65
|
+
llmApiKey: env.LLM_API_KEY || env.SILICONFLOW_API_KEY || gc.api_key || "",
|
|
66
|
+
llmBaseUrl: env.LLM_BASE_URL || env.SILICONFLOW_BASE_URL || gc.base_url || "https://api.siliconflow.cn/v1",
|
|
56
67
|
kcModel: gc.conductor_model || "glm-5",
|
|
57
68
|
kcMaxTokens: 65536,
|
|
58
69
|
|
|
59
|
-
// Worker LLMs (SiliconFlow)
|
|
60
|
-
siliconflowApiKey: env.SILICONFLOW_API_KEY || gc.api_key || "",
|
|
61
|
-
siliconflowBaseUrl: env.SILICONFLOW_BASE_URL || gc.base_url || "https://api.siliconflow.cn/v1",
|
|
62
|
-
|
|
63
70
|
// Tier models (from .env or global config tiers)
|
|
64
71
|
tier1: env.TIER1 || gc.tiers?.tier1 || "",
|
|
65
72
|
tier2: env.TIER2 || gc.tiers?.tier2 || "",
|
|
66
73
|
tier3: env.TIER3 || gc.tiers?.tier3 || "",
|
|
67
74
|
tier4: env.TIER4 || gc.tiers?.tier4 || "",
|
|
68
75
|
|
|
69
|
-
// OCR models
|
|
70
|
-
|
|
76
|
+
// VLM tiers (vision/OCR models)
|
|
77
|
+
vlmTier1: env.VLM_TIER1 || gc.vlm_tiers?.tier1 || "",
|
|
78
|
+
vlmTier2: env.VLM_TIER2 || gc.vlm_tiers?.tier2 || "",
|
|
79
|
+
vlmTier3: env.VLM_TIER3 || gc.vlm_tiers?.tier3 || "",
|
|
80
|
+
|
|
81
|
+
// Worker LLM — optional, defaults to conductor config
|
|
82
|
+
workerProvider: gc.worker_provider || "",
|
|
83
|
+
workerApiKey: env.WORKER_API_KEY || gc.worker_api_key || "",
|
|
84
|
+
workerBaseUrl: env.WORKER_BASE_URL || gc.worker_base_url || "",
|
|
85
|
+
workerAuthType: gc.worker_auth_type || "",
|
|
86
|
+
workerApiFormat: gc.worker_api_format || "",
|
|
71
87
|
|
|
72
88
|
// Document parsing
|
|
73
89
|
mineruApiUrl: env.MINERU_API_URL || "",
|
|
@@ -90,9 +106,46 @@ export function loadSettings(workspacePath) {
|
|
|
90
106
|
maxIterations: parseInt(env.MAX_ITERATIONS || "20", 10),
|
|
91
107
|
monitorFrequency: env.MONITOR_FREQUENCY || "mid",
|
|
92
108
|
|
|
109
|
+
// Web search
|
|
110
|
+
tavilyApiKey: env.TAVILY_API_KEY || gc.tavily_api_key || "",
|
|
111
|
+
|
|
112
|
+
// Context management
|
|
113
|
+
kcContextLimit: parseInt(env.KC_CONTEXT_LIMIT || "200000", 10),
|
|
114
|
+
|
|
93
115
|
// Language
|
|
94
116
|
language: env.LANGUAGE || gc.language || "en",
|
|
95
117
|
};
|
|
118
|
+
|
|
119
|
+
// Effective worker config (falls back to conductor config)
|
|
120
|
+
settings.effectiveWorkerProvider = () => settings.workerProvider || settings.provider;
|
|
121
|
+
settings.effectiveWorkerApiKey = () => settings.workerApiKey || settings.llmApiKey;
|
|
122
|
+
settings.effectiveWorkerBaseUrl = () => {
|
|
123
|
+
if (settings.workerBaseUrl) return settings.workerBaseUrl;
|
|
124
|
+
// If worker uses a different provider, use that provider's default base URL
|
|
125
|
+
if (settings.workerProvider && settings.workerProvider !== settings.provider) {
|
|
126
|
+
const wp = getProviderById(settings.workerProvider);
|
|
127
|
+
return wp?.baseUrl || settings.llmBaseUrl;
|
|
128
|
+
}
|
|
129
|
+
return settings.llmBaseUrl;
|
|
130
|
+
};
|
|
131
|
+
settings.effectiveWorkerAuthType = () => {
|
|
132
|
+
if (settings.workerAuthType) return settings.workerAuthType;
|
|
133
|
+
if (settings.workerProvider && settings.workerProvider !== settings.provider) {
|
|
134
|
+
const wp = getProviderById(settings.workerProvider);
|
|
135
|
+
return wp?.authType || settings.authType;
|
|
136
|
+
}
|
|
137
|
+
return settings.authType;
|
|
138
|
+
};
|
|
139
|
+
settings.effectiveWorkerApiFormat = () => {
|
|
140
|
+
if (settings.workerApiFormat) return settings.workerApiFormat;
|
|
141
|
+
if (settings.workerProvider && settings.workerProvider !== settings.provider) {
|
|
142
|
+
const wp = getProviderById(settings.workerProvider);
|
|
143
|
+
return wp?.apiFormat || settings.apiFormat;
|
|
144
|
+
}
|
|
145
|
+
return settings.apiFormat;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return settings;
|
|
96
149
|
}
|
|
97
150
|
|
|
98
151
|
export { GLOBAL_CONFIG_DIR, GLOBAL_CONFIG_PATH };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Model selections per provider. LLM tiers 1-4, VLM tiers 1-3. Edit this file directly to update model assignments.",
|
|
3
|
+
|
|
4
|
+
"siliconflow": {
|
|
5
|
+
"conductor": "Pro/zai-org/GLM-5",
|
|
6
|
+
"llm": {
|
|
7
|
+
"tier1": "Pro/zai-org/GLM-5, Pro/moonshotai/Kimi-K2.5",
|
|
8
|
+
"tier2": "Pro/deepseek-ai/DeepSeek-V3.2, Pro/MiniMaxAI/MiniMax-M2.5",
|
|
9
|
+
"tier3": "Qwen/Qwen3.5-122B-A10B",
|
|
10
|
+
"tier4": "Qwen/Qwen3.5-35B-A3B"
|
|
11
|
+
},
|
|
12
|
+
"vlm": {
|
|
13
|
+
"tier1": "Pro/Qwen/Qwen2.5-VL-72B-Instruct",
|
|
14
|
+
"tier2": "Qwen/Qwen2.5-VL-32B-Instruct",
|
|
15
|
+
"tier3": "Qwen/Qwen2.5-VL-7B-Instruct"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"aliyun": {
|
|
20
|
+
"conductor": "qwen3.6-plus",
|
|
21
|
+
"llm": {
|
|
22
|
+
"tier1": "qwen3.6-plus",
|
|
23
|
+
"tier2": "",
|
|
24
|
+
"tier3": "",
|
|
25
|
+
"tier4": ""
|
|
26
|
+
},
|
|
27
|
+
"vlm": {
|
|
28
|
+
"tier1": "qwen-vl-max",
|
|
29
|
+
"tier2": "qwen-vl-plus",
|
|
30
|
+
"tier3": ""
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"volcanocloud": {
|
|
35
|
+
"conductor": "doubao-seed-2-0-pro-260215",
|
|
36
|
+
"llm": {
|
|
37
|
+
"tier1": "doubao-seed-2-0-pro-260215, deepseek-v3-2-251201",
|
|
38
|
+
"tier2": "glm-4-7-251222, doubao-1-5-pro-32k-250115",
|
|
39
|
+
"tier3": "doubao-seed-2-0-mini-260215",
|
|
40
|
+
"tier4": "doubao-seed-2-0-lite-260215, doubao-1-5-lite-32k-250115"
|
|
41
|
+
},
|
|
42
|
+
"vlm": {
|
|
43
|
+
"tier1": "doubao-vision-pro-32k-241028",
|
|
44
|
+
"tier2": "doubao-vision-lite-32k-241028",
|
|
45
|
+
"tier3": ""
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
"anthropic": {
|
|
50
|
+
"conductor": "claude-sonnet-4-20250514",
|
|
51
|
+
"llm": {
|
|
52
|
+
"tier1": "claude-sonnet-4-20250514",
|
|
53
|
+
"tier2": "claude-sonnet-4-20250514",
|
|
54
|
+
"tier3": "claude-haiku-4-5-20251001",
|
|
55
|
+
"tier4": "claude-haiku-4-5-20251001"
|
|
56
|
+
},
|
|
57
|
+
"vlm": {
|
|
58
|
+
"tier1": "claude-sonnet-4-20250514",
|
|
59
|
+
"tier2": "claude-haiku-4-5-20251001",
|
|
60
|
+
"tier3": "claude-haiku-4-5-20251001"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
"openai": {
|
|
65
|
+
"conductor": "gpt-4o",
|
|
66
|
+
"llm": {
|
|
67
|
+
"tier1": "gpt-4o",
|
|
68
|
+
"tier2": "gpt-4o-mini",
|
|
69
|
+
"tier3": "gpt-4o-mini",
|
|
70
|
+
"tier4": "gpt-4o-mini"
|
|
71
|
+
},
|
|
72
|
+
"vlm": {
|
|
73
|
+
"tier1": "gpt-4o",
|
|
74
|
+
"tier2": "gpt-4o-mini",
|
|
75
|
+
"tier3": "gpt-4o-mini"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
"zhipu": {
|
|
80
|
+
"conductor": "glm-4-plus",
|
|
81
|
+
"llm": {
|
|
82
|
+
"tier1": "glm-4-plus",
|
|
83
|
+
"tier2": "glm-4-air",
|
|
84
|
+
"tier3": "glm-4-flash",
|
|
85
|
+
"tier4": "glm-4-flash"
|
|
86
|
+
},
|
|
87
|
+
"vlm": {
|
|
88
|
+
"tier1": "glm-4v-plus",
|
|
89
|
+
"tier2": "glm-4v",
|
|
90
|
+
"tier3": "glm-4v-flash"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
"minimax": {
|
|
95
|
+
"conductor": "MiniMax-M2.5",
|
|
96
|
+
"llm": {
|
|
97
|
+
"tier1": "MiniMax-M2.5",
|
|
98
|
+
"tier2": "MiniMax-M2.5",
|
|
99
|
+
"tier3": "MiniMax-M1",
|
|
100
|
+
"tier4": "MiniMax-M1"
|
|
101
|
+
},
|
|
102
|
+
"vlm": {
|
|
103
|
+
"tier1": "",
|
|
104
|
+
"tier2": "",
|
|
105
|
+
"tier3": ""
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
"openrouter": {
|
|
110
|
+
"conductor": "anthropic/claude-sonnet-4-20250514",
|
|
111
|
+
"llm": {
|
|
112
|
+
"tier1": "anthropic/claude-sonnet-4-20250514",
|
|
113
|
+
"tier2": "google/gemini-2.5-flash",
|
|
114
|
+
"tier3": "google/gemini-2.5-flash",
|
|
115
|
+
"tier4": "google/gemini-2.5-flash"
|
|
116
|
+
},
|
|
117
|
+
"vlm": {
|
|
118
|
+
"tier1": "anthropic/claude-sonnet-4-20250514",
|
|
119
|
+
"tier2": "google/gemini-2.5-flash",
|
|
120
|
+
"tier3": "google/gemini-2.5-flash"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
"bedrock": {
|
|
125
|
+
"conductor": "anthropic.claude-sonnet-4-20250514-v1:0",
|
|
126
|
+
"llm": {
|
|
127
|
+
"tier1": "anthropic.claude-sonnet-4-20250514-v1:0",
|
|
128
|
+
"tier2": "anthropic.claude-sonnet-4-20250514-v1:0",
|
|
129
|
+
"tier3": "anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
130
|
+
"tier4": "anthropic.claude-haiku-4-5-20251001-v1:0"
|
|
131
|
+
},
|
|
132
|
+
"vlm": {
|
|
133
|
+
"tier1": "anthropic.claude-sonnet-4-20250514-v1:0",
|
|
134
|
+
"tier2": "anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
135
|
+
"tier3": "anthropic.claude-haiku-4-5-20251001-v1:0"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
"custom": {
|
|
140
|
+
"conductor": "",
|
|
141
|
+
"llm": {
|
|
142
|
+
"tier1": "",
|
|
143
|
+
"tier2": "",
|
|
144
|
+
"tier3": "",
|
|
145
|
+
"tier4": ""
|
|
146
|
+
},
|
|
147
|
+
"vlm": {
|
|
148
|
+
"tier1": "",
|
|
149
|
+
"tier2": "",
|
|
150
|
+
"tier3": ""
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|