kc-beta 0.1.1 → 0.2.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.
Files changed (34) hide show
  1. package/bin/kc-beta.js +14 -2
  2. package/package.json +1 -1
  3. package/src/agent/context-window.js +151 -0
  4. package/src/agent/context.js +58 -88
  5. package/src/agent/engine.js +267 -38
  6. package/src/agent/event-log.js +111 -0
  7. package/src/agent/llm-client.js +352 -59
  8. package/src/agent/pipelines/_archive_v1/distillation.js +113 -0
  9. package/src/agent/pipelines/_archive_v1/extraction.js +92 -0
  10. package/src/agent/pipelines/_archive_v1/initializer.js +163 -0
  11. package/src/agent/pipelines/_archive_v1/production-qc.js +99 -0
  12. package/src/agent/pipelines/_archive_v1/skill-authoring.js +83 -0
  13. package/src/agent/pipelines/_archive_v1/skill-testing.js +111 -0
  14. package/src/agent/pipelines/base.js +6 -0
  15. package/src/agent/pipelines/distillation.js +25 -11
  16. package/src/agent/pipelines/extraction.js +26 -7
  17. package/src/agent/pipelines/initializer.js +30 -20
  18. package/src/agent/pipelines/production-qc.js +22 -5
  19. package/src/agent/pipelines/skill-authoring.js +19 -8
  20. package/src/agent/pipelines/skill-testing.js +26 -8
  21. package/src/agent/retry.js +83 -0
  22. package/src/agent/session-state.js +78 -0
  23. package/src/agent/skill-loader.js +139 -0
  24. package/src/agent/token-counter.js +62 -0
  25. package/src/agent/tools/document-parse.js +3 -3
  26. package/src/agent/tools/tier-downgrade.js +11 -2
  27. package/src/agent/tools/web-search.js +107 -0
  28. package/src/agent/tools/worker-llm-call.js +14 -5
  29. package/src/cli/components.js +16 -4
  30. package/src/cli/config.js +246 -0
  31. package/src/cli/index.js +99 -10
  32. package/src/cli/onboard.js +154 -48
  33. package/src/config.js +25 -7
  34. package/src/providers.js +370 -0
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Provider registry for Multi-LLM support.
3
+ * Centralizes provider metadata, default models, and model classification.
4
+ *
5
+ * Aligned with kc_reborn/platform/backend/app/providers.py
6
+ */
7
+
8
+ const PROVIDERS = [
9
+ {
10
+ id: "siliconflow",
11
+ name: "SiliconFlow",
12
+ baseUrl: "https://api.siliconflow.cn/v1",
13
+ authType: "bearer",
14
+ apiFormat: "openai",
15
+ modelsEndpoint: "/models",
16
+ defaultModel: "glm-5",
17
+ defaultTiers: {
18
+ tier1: "Pro/zai-org/GLM-5, Pro/moonshotai/Kimi-K2.5",
19
+ tier2: "Pro/deepseek-ai/DeepSeek-V3.2, Pro/MiniMaxAI/MiniMax-M2.5",
20
+ tier3: "Qwen/Qwen3.5-122B-A10B",
21
+ tier4: "Qwen/Qwen3.5-35B-A3B",
22
+ },
23
+ labels: {
24
+ en: "SiliconFlow (recommended for China)",
25
+ zh: "SiliconFlow(国内推荐)",
26
+ },
27
+ },
28
+ {
29
+ id: "aliyun",
30
+ name: "Aliyun",
31
+ // Coding plan URL — regular API uses dashscope.aliyuncs.com/compatible-mode/v1
32
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
33
+ codingPlanUrl: "https://coding.dashscope.aliyuncs.com/v1",
34
+ authType: "bearer",
35
+ apiFormat: "openai",
36
+ modelsEndpoint: null, // Aliyun coding plan doesn't support /models
37
+ supportsCodingPlanKey: true,
38
+ defaultModel: "glm-5",
39
+ defaultTiers: {
40
+ tier1: "qwen3.6-plus",
41
+ tier2: "",
42
+ tier3: "",
43
+ tier4: "",
44
+ },
45
+ // Curated model list (coding plan doesn't have /models endpoint)
46
+ curatedModels: [
47
+ { id: "qwen3.6-plus", ownedBy: "qwen" },
48
+ { id: "qwen3.5-plus", ownedBy: "qwen" },
49
+ { id: "qwen3-max-2026-01-23", ownedBy: "qwen" },
50
+ { id: "qwen3-coder-next", ownedBy: "qwen" },
51
+ { id: "qwen3-coder-plus", ownedBy: "qwen" },
52
+ { id: "glm-5", ownedBy: "zhipu" },
53
+ { id: "glm-4.7", ownedBy: "zhipu" },
54
+ { id: "kimi-k2.5", ownedBy: "kimi" },
55
+ { id: "MiniMax-M2.5", ownedBy: "minimax" },
56
+ ],
57
+ labels: {
58
+ en: "Aliyun Bailian",
59
+ zh: "阿里云百炼",
60
+ },
61
+ },
62
+ {
63
+ id: "volcanocloud",
64
+ name: "VolcanoCloud",
65
+ baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
66
+ authType: "bearer",
67
+ apiFormat: "openai",
68
+ modelsEndpoint: null, // VolcanoCloud coding plan — use curated list
69
+ defaultModel: "glm-5",
70
+ defaultTiers: {
71
+ tier1: "doubao-seed-2-0-pro-260215, deepseek-v3-2-251201",
72
+ tier2: "glm-4-7-251222, doubao-1-5-pro-32k-250115",
73
+ tier3: "doubao-seed-2-0-mini-260215",
74
+ tier4: "doubao-seed-2-0-lite-260215, doubao-1-5-lite-32k-250115",
75
+ },
76
+ curatedModels: [
77
+ { id: "doubao-seed-2-0-pro-260215", ownedBy: "bytedance" },
78
+ { id: "deepseek-v3-2-251201", ownedBy: "deepseek" },
79
+ { id: "glm-4-7-251222", ownedBy: "zhipu" },
80
+ { id: "doubao-1-5-pro-32k-250115", ownedBy: "bytedance" },
81
+ { id: "doubao-seed-2-0-mini-260215", ownedBy: "bytedance" },
82
+ { id: "doubao-seed-2-0-lite-260215", ownedBy: "bytedance" },
83
+ { id: "doubao-1-5-lite-32k-250115", ownedBy: "bytedance" },
84
+ ],
85
+ labels: {
86
+ en: "VolcanoCloud (ByteDance)",
87
+ zh: "火山云(字节跳动)",
88
+ },
89
+ },
90
+ {
91
+ id: "anthropic",
92
+ name: "Anthropic",
93
+ baseUrl: "https://api.anthropic.com",
94
+ authType: "x-api-key",
95
+ apiFormat: "anthropic",
96
+ modelsEndpoint: null, // Use curated list
97
+ defaultModel: "claude-sonnet-4-20250514",
98
+ defaultTiers: {
99
+ tier1: "claude-sonnet-4-20250514",
100
+ tier2: "claude-sonnet-4-20250514",
101
+ tier3: "claude-haiku-4-5-20251001",
102
+ tier4: "claude-haiku-4-5-20251001",
103
+ },
104
+ curatedModels: [
105
+ { id: "claude-opus-4-20250514", ownedBy: "anthropic" },
106
+ { id: "claude-sonnet-4-20250514", ownedBy: "anthropic" },
107
+ { id: "claude-haiku-4-5-20251001", ownedBy: "anthropic" },
108
+ ],
109
+ labels: {
110
+ en: "Anthropic",
111
+ zh: "Anthropic",
112
+ },
113
+ },
114
+ {
115
+ id: "openai",
116
+ name: "OpenAI",
117
+ baseUrl: "https://api.openai.com/v1",
118
+ authType: "bearer",
119
+ apiFormat: "openai",
120
+ modelsEndpoint: "/models",
121
+ defaultModel: "gpt-4o",
122
+ defaultTiers: {
123
+ tier1: "gpt-4o",
124
+ tier2: "gpt-4o-mini",
125
+ tier3: "gpt-4o-mini",
126
+ tier4: "gpt-4o-mini",
127
+ },
128
+ labels: {
129
+ en: "OpenAI",
130
+ zh: "OpenAI",
131
+ },
132
+ },
133
+ {
134
+ id: "zhipu",
135
+ name: "Zhipu/GLM",
136
+ baseUrl: "https://open.bigmodel.cn/api/paas/v4",
137
+ authType: "bearer",
138
+ apiFormat: "openai",
139
+ modelsEndpoint: "/models",
140
+ defaultModel: "glm-4-plus",
141
+ defaultTiers: {
142
+ tier1: "glm-4-plus",
143
+ tier2: "glm-4-air",
144
+ tier3: "glm-4-flash",
145
+ tier4: "glm-4-flash",
146
+ },
147
+ labels: {
148
+ en: "Zhipu GLM",
149
+ zh: "智谱 GLM",
150
+ },
151
+ },
152
+ {
153
+ id: "minimax",
154
+ name: "MiniMax",
155
+ baseUrl: "https://api.minimax.chat/v1",
156
+ authType: "bearer",
157
+ apiFormat: "openai",
158
+ modelsEndpoint: "/models",
159
+ defaultModel: "MiniMax-M2.5",
160
+ defaultTiers: {
161
+ tier1: "MiniMax-M2.5",
162
+ tier2: "MiniMax-M2.5",
163
+ tier3: "MiniMax-M1",
164
+ tier4: "MiniMax-M1",
165
+ },
166
+ labels: {
167
+ en: "MiniMax",
168
+ zh: "MiniMax",
169
+ },
170
+ },
171
+ {
172
+ id: "openrouter",
173
+ name: "OpenRouter",
174
+ baseUrl: "https://openrouter.ai/api/v1",
175
+ authType: "bearer",
176
+ apiFormat: "openai",
177
+ modelsEndpoint: "/models",
178
+ defaultModel: "anthropic/claude-sonnet-4-20250514",
179
+ defaultTiers: {
180
+ tier1: "anthropic/claude-sonnet-4-20250514",
181
+ tier2: "google/gemini-2.5-flash",
182
+ tier3: "google/gemini-2.5-flash",
183
+ tier4: "google/gemini-2.5-flash",
184
+ },
185
+ labels: {
186
+ en: "OpenRouter",
187
+ zh: "OpenRouter",
188
+ },
189
+ },
190
+ {
191
+ id: "bedrock",
192
+ name: "Bedrock",
193
+ baseUrl: "",
194
+ authType: "aws-sigv4",
195
+ apiFormat: "anthropic",
196
+ modelsEndpoint: null,
197
+ defaultModel: "anthropic.claude-sonnet-4-20250514-v1:0",
198
+ defaultTiers: {
199
+ tier1: "anthropic.claude-sonnet-4-20250514-v1:0",
200
+ tier2: "anthropic.claude-sonnet-4-20250514-v1:0",
201
+ tier3: "anthropic.claude-haiku-4-5-20251001-v1:0",
202
+ tier4: "anthropic.claude-haiku-4-5-20251001-v1:0",
203
+ },
204
+ labels: {
205
+ en: "AWS Bedrock (not yet supported)",
206
+ zh: "AWS Bedrock(暂未支持)",
207
+ },
208
+ },
209
+ {
210
+ id: "custom",
211
+ name: "Custom",
212
+ baseUrl: "",
213
+ authType: "bearer",
214
+ apiFormat: "openai",
215
+ modelsEndpoint: "/models",
216
+ defaultModel: "",
217
+ defaultTiers: { tier1: "", tier2: "", tier3: "", tier4: "" },
218
+ labels: {
219
+ en: "Custom (enter base URL)",
220
+ zh: "自定义(输入接口地址)",
221
+ },
222
+ },
223
+ ];
224
+
225
+ /**
226
+ * Known model capability rankings (partial — used to sort discovered models).
227
+ * Pattern-matched against lowercase model ID. Higher = more capable.
228
+ * Aligned with kc_reborn providers.py _MODEL_RANKING.
229
+ */
230
+ const MODEL_RANKING = {
231
+ // Anthropic
232
+ "claude-opus-4": 100,
233
+ "claude-sonnet-4": 90,
234
+ "claude-haiku-4": 70,
235
+ // OpenAI
236
+ "gpt-4o": 90,
237
+ "gpt-4o-mini": 70,
238
+ "gpt-4-turbo": 85,
239
+ "o1": 95,
240
+ "o3": 95,
241
+ // Qwen (Aliyun Bailian)
242
+ "qwen3.6-plus": 90,
243
+ "qwen3.5-plus": 85,
244
+ "qwen3-max": 88,
245
+ "qwen3-coder-next": 85,
246
+ "qwen3-coder-plus": 80,
247
+ "qwen-plus": 75,
248
+ "qwen-turbo": 60,
249
+ "qwen3.5-397b": 85,
250
+ "qwen3.5-122b": 75,
251
+ "qwen3.5-35b": 65,
252
+ // Zhipu
253
+ "glm-5": 90,
254
+ "glm-4.7": 80,
255
+ "glm-4": 75,
256
+ // Others
257
+ "kimi-k2.5": 85,
258
+ "kimi-k2": 80,
259
+ "minimax-m2": 80,
260
+ "deepseek-v3": 85,
261
+ "deepseek-r1": 90,
262
+ // VolcanoCloud (ByteDance Doubao)
263
+ "doubao-seed-2-0-pro": 90,
264
+ "doubao-seed-2-0-code": 88,
265
+ "doubao-seed-2-0-mini": 75,
266
+ "doubao-seed-2-0-lite": 65,
267
+ "doubao-seed-1-8": 85,
268
+ "doubao-seed-1-6": 80,
269
+ "doubao-1-5-pro": 80,
270
+ "doubao-1-5-lite": 60,
271
+ };
272
+
273
+ /**
274
+ * Estimate model capability rank (0-100) based on known patterns.
275
+ * @param {string} modelId
276
+ * @returns {number}
277
+ */
278
+ function rankModel(modelId) {
279
+ const lower = modelId.toLowerCase();
280
+ for (const [pattern, rank] of Object.entries(MODEL_RANKING)) {
281
+ if (lower.includes(pattern)) return rank;
282
+ }
283
+ return 50; // Unknown model: assume mid-tier
284
+ }
285
+
286
+ /**
287
+ * Patterns to filter out non-chat models from discovery results.
288
+ */
289
+ const EXCLUDE_PATTERNS = [
290
+ /embed/i, /tts/i, /whisper/i, /dall-e/i, /audio/i, /image/i,
291
+ /moderation/i, /rerank/i,
292
+ ];
293
+
294
+ /** @returns {Array} All provider definitions */
295
+ export function getProviders() {
296
+ return PROVIDERS;
297
+ }
298
+
299
+ /**
300
+ * @param {string} id - Provider ID
301
+ * @returns {object|undefined}
302
+ */
303
+ export function getProviderById(id) {
304
+ return PROVIDERS.find((p) => p.id === id);
305
+ }
306
+
307
+ /**
308
+ * Get display labels for the onboard menu.
309
+ * @param {string} lang - "en" or "zh"
310
+ * @returns {Array<{id: string, label: string}>}
311
+ */
312
+ export function getProviderLabels(lang) {
313
+ return PROVIDERS.map((p) => ({
314
+ id: p.id,
315
+ label: p.labels[lang] || p.labels.en || p.name,
316
+ }));
317
+ }
318
+
319
+ /**
320
+ * Classify a list of discovered models into tier assignments.
321
+ * Uses the same ranking-based approach as kc_reborn's propose_tiers().
322
+ *
323
+ * @param {Array<{id: string, name?: string}>} models - Models from /models endpoint or curated list
324
+ * @returns {{ conductor: string, tiers: {tier1: string, tier2: string, tier3: string, tier4: string}, unclassified: string[] }}
325
+ */
326
+ export function classifyModels(models) {
327
+ // Filter out non-chat models
328
+ const chatModels = models.filter((m) => {
329
+ const name = m.id || m.name || "";
330
+ return !EXCLUDE_PATTERNS.some((re) => re.test(name));
331
+ });
332
+
333
+ // Rank and sort by capability
334
+ const ranked = [...chatModels].sort((a, b) => rankModel(b.id) - rankModel(a.id));
335
+
336
+ // Select conductor (highest ranked)
337
+ const conductor = ranked[0]?.id || "";
338
+
339
+ // Distribute across tiers by rank
340
+ const tierBuckets = { tier1: [], tier2: [], tier3: [], tier4: [] };
341
+
342
+ for (const m of ranked) {
343
+ const rank = rankModel(m.id);
344
+ if (rank >= 85) tierBuckets.tier1.push(m.id);
345
+ else if (rank >= 70) tierBuckets.tier2.push(m.id);
346
+ else if (rank >= 55) tierBuckets.tier3.push(m.id);
347
+ else tierBuckets.tier4.push(m.id);
348
+ }
349
+
350
+ const tiers = {
351
+ tier1: tierBuckets.tier1.slice(0, 3).join(", "),
352
+ tier2: tierBuckets.tier2.slice(0, 3).join(", "),
353
+ tier3: tierBuckets.tier3.slice(0, 2).join(", "),
354
+ tier4: tierBuckets.tier4.slice(0, 2).join(", "),
355
+ };
356
+
357
+ const unclassified = ranked.filter((m) => rankModel(m.id) === 50).map((m) => m.id);
358
+
359
+ return { conductor, tiers, unclassified };
360
+ }
361
+
362
+ /**
363
+ * Get curated models for providers that don't support /models endpoint.
364
+ * @param {string} providerId
365
+ * @returns {Array<{id: string, ownedBy: string}>|null}
366
+ */
367
+ export function getCuratedModels(providerId) {
368
+ const provider = getProviderById(providerId);
369
+ return provider?.curatedModels || null;
370
+ }