@jclaw/core 0.6.1 → 0.8.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.
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ import { JClawAgent } from '../runtime/agent.js';
3
+ import { createSimpleMemoryClient } from '../context/simple-memory-client.js';
4
+ import { readFile, writeFile } from 'fs/promises';
5
+ import { existsSync } from 'fs';
6
+ import { fileURLToPath } from 'url';
7
+ import { dirname, join } from 'path';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+
12
+ // Read version from package.json
13
+ const packageJsonPath = join(__dirname, '../../package.json');
14
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
15
+ const VERSION = packageJson.version;
16
+
17
+ const args = process.argv.slice(2);
18
+ const command = args[0];
19
+
20
+ function showHelp() {
21
+ console.log(`
22
+ 🧬 JClaw - Universal Self-Evolving Agent Framework
23
+
24
+ 用法:
25
+ jclaw <command> [options]
26
+
27
+ 命令:
28
+ execute <prompt> 执行任务
29
+ chat 交互模式
30
+ init 初始化项目
31
+ help 显示帮助
32
+
33
+ 环境变量:
34
+ LLM_API_KEY API 密钥
35
+ LLM_BASE_URL API 地址
36
+ LLM_MODEL_NAME 模型名称
37
+ `);
38
+ }
39
+
40
+ async function loadLLMConfig() {
41
+ if (existsSync('./jclaw.config.js')) {
42
+ try {
43
+ const config = await import('./jclaw.config.js');
44
+ const { llm, providers } = config.default || config;
45
+ if (llm && llm.provider && providers && providers[llm.provider]) {
46
+ const provider = providers[llm.provider];
47
+ const apiKey = process.env[provider.apiKeyEnv];
48
+ if (!apiKey) {
49
+ console.error(`❌ 请设置 ${provider.apiKeyEnv}`);
50
+ process.exit(1);
51
+ }
52
+ return {
53
+ apiBase: provider.baseURL,
54
+ apiKey: apiKey,
55
+ model: llm.model || provider.models[0]
56
+ };
57
+ }
58
+ if (llm && llm.apiKey) {
59
+ return {
60
+ apiBase: llm.apiBase || 'https://api.openai.com/v1',
61
+ apiKey: llm.apiKey,
62
+ model: llm.model || 'gpt-4'
63
+ };
64
+ }
65
+ } catch (e) {}
66
+ }
67
+ return null;
68
+ }
69
+
70
+ async function getLLMConfig() {
71
+ const configFile = await loadLLMConfig();
72
+ if (configFile) return configFile;
73
+
74
+ if (process.env.LLM_API_KEY) {
75
+ return {
76
+ apiBase: process.env.LLM_BASE_URL || 'https://api.openai.com/v1',
77
+ apiKey: process.env.LLM_API_KEY,
78
+ model: process.env.LLM_MODEL_NAME || 'gpt-4',
79
+ temperature: process.env.LLM_TEMPERATURE ? parseFloat(process.env.LLM_TEMPERATURE) : 1.0
80
+ };
81
+ }
82
+
83
+ if (process.env.OPENAI_API_KEY) {
84
+ return {
85
+ apiBase: process.env.LLM_BASE_URL || 'https://api.openai.com/v1',
86
+ apiKey: process.env.OPENAI_API_KEY,
87
+ model: process.env.LLM_MODEL_NAME || 'gpt-4',
88
+ temperature: process.env.LLM_TEMPERATURE ? parseFloat(process.env.LLM_TEMPERATURE) : 1.0
89
+ };
90
+ }
91
+
92
+ console.error('❌ 请设置 LLM_API_KEY 或 OPENAI_API_KEY');
93
+ process.exit(1);
94
+ }
95
+
96
+ async function execute(prompt) {
97
+ const llmConfig = await getLLMConfig();
98
+ console.log('🧬 启动 JClaw...\n');
99
+ console.log(`📡 模型:${llmConfig.model}`);
100
+ console.log(`🔌 API: ${llmConfig.apiBase}\n`);
101
+
102
+ const agent = new JClawAgent({
103
+ name: 'jclaw-cli',
104
+ version: VERSION,
105
+ enableAutoSkill: true,
106
+ skillShConfig: { enableCache: true },
107
+ llm: llmConfig,
108
+ contextManager: createSimpleMemoryClient({
109
+ enableSynonyms: true,
110
+ enableFuzzyMatch: true
111
+ })
112
+ });
113
+
114
+ await agent.start();
115
+ console.log('✅ JClaw 已启动\n');
116
+ console.log('📝 任务:', prompt, '\n');
117
+
118
+ const result = await agent.execute({ id: 'cli-task', prompt });
119
+
120
+ console.log('\n✅ 结果:\n');
121
+ console.log(result.output || result.error);
122
+ await agent.stop();
123
+ console.log('\n🎉 完成!\n');
124
+ }
125
+
126
+ async function chat() {
127
+ const llmConfig = await getLLMConfig();
128
+ console.log('🧬 JClaw 交互模式 (输入 "exit" 退出)\n');
129
+ console.log(`📡 模型:${llmConfig.model}\n`);
130
+
131
+ const agent = new JClawAgent({ name: 'jclaw-chat', version: VERSION, enableAutoSkill: true, llm: llmConfig });
132
+ await agent.start();
133
+
134
+ const readline = await import('readline');
135
+ const rl = readline.createInterface({
136
+ input: process.stdin,
137
+ output: process.stdout
138
+ });
139
+
140
+ const ask = () => {
141
+ rl.question('你:', async (input) => {
142
+ if (input.toLowerCase() === 'exit') {
143
+ await agent.stop();
144
+ rl.close();
145
+ console.log('\n👋 再见!\n');
146
+ return;
147
+ }
148
+ console.log('\n🤖 JClaw:\n');
149
+ const result = await agent.execute({ id: 'chat', prompt: input });
150
+ console.log(result.output || result.error);
151
+ console.log('');
152
+ ask();
153
+ });
154
+ };
155
+ ask();
156
+ }
157
+
158
+ async function init() {
159
+ console.log('🧬 初始化 JClaw 项目...\n');
160
+ const configTemplate = `export default {
161
+ enableAutoSkill: true,
162
+ llm: { provider: 'openai', model: 'gpt-4' },
163
+ providers: {
164
+ 'openai': {
165
+ baseURL: 'https://api.openai.com/v1',
166
+ apiKeyEnv: 'OPENAI_API_KEY',
167
+ models: ['gpt-4', 'gpt-4o']
168
+ }
169
+ }
170
+ };
171
+ `;
172
+ if (!existsSync('jclaw.config.js')) {
173
+ await writeFile('jclaw.config.js', configTemplate);
174
+ console.log('✅ 创建:jclaw.config.js');
175
+ }
176
+ console.log('\n🎉 初始化完成!\n');
177
+ }
178
+
179
+ switch (command) {
180
+ case 'execute':
181
+ case 'exec':
182
+ case 'e':
183
+ const prompt = args.slice(1).join(' ');
184
+ if (!prompt) {
185
+ console.error('❌ 请提供任务描述');
186
+ process.exit(1);
187
+ }
188
+ execute(prompt);
189
+ break;
190
+ case 'chat':
191
+ case 'c':
192
+ chat();
193
+ break;
194
+ case 'init':
195
+ case 'i':
196
+ init();
197
+ break;
198
+ case 'help':
199
+ case 'h':
200
+ case '--help':
201
+ case '-h':
202
+ showHelp();
203
+ break;
204
+ default:
205
+ if (command) {
206
+ execute(args.join(' '));
207
+ } else {
208
+ showHelp();
209
+ }
210
+ }
211
+
212
+ // Add temperature env var support
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Context Module
3
3
  */
4
+ export { MemSearchTsClient, type MemSearchTsConfig, createMemSearchTsClient } from './memsearch-ts-client.js';
4
5
  export { SimpleMemoryClient, type SimpleMemoryConfig, createSimpleMemoryClient } from './simple-memory-client.js';
5
6
  export { MockClient } from './mock-client.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AASlH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAG9G,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAQlH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * Context Module
3
3
  */
4
- // SimpleMemory (推荐 - 纯 JavaScript,零依赖)
4
+ // MemSearch-TS (推荐 - 纯 TypeScript,零 Python 依赖,语义搜索)
5
+ export { MemSearchTsClient, createMemSearchTsClient } from './memsearch-ts-client.js';
6
+ // SimpleMemory (备选 - 纯 JavaScript,无需向量数据库)
5
7
  export { SimpleMemoryClient, createSimpleMemoryClient } from './simple-memory-client.js';
6
- // MemSearch (需要 Python,有兼容性问题)
8
+ // MemSearch (已弃用 - 需要 Python)
7
9
  // export { MemSearchClient, type MemSearchConfig, createMemSearchClient } from './memsearch-client.js';
8
- // OpenViking (已弃用 - 需要 Docker,安装复杂)
10
+ // OpenViking (已弃用 - 需要 Docker)
9
11
  // export { OpenVikingClient, type OpenVikingConfig } from './openviking-client.js';
10
- // export { OpenVikingMCPClient, type OpenVikingMCPConfig, createOpenVikingMCPClient } from './openviking-mcp-client.js';
11
12
  export { MockClient } from './mock-client.js';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MemSearch-TS Client
3
+ *
4
+ * TypeScript-native semantic memory client using memsearch-core.
5
+ * Zero Python dependency, built on Milvus vector database.
6
+ *
7
+ * @module @jclaw/core/context/memsearch-ts-client
8
+ */
9
+ import type { ContextManager } from '../types.js';
10
+ export interface MemSearchTsConfig {
11
+ memoryPath?: string;
12
+ embeddingProvider?: 'openai' | 'ollama';
13
+ embeddingModel?: string;
14
+ milvusUri?: string;
15
+ collectionName?: string;
16
+ verbose?: boolean;
17
+ }
18
+ export declare class MemSearchTsClient implements ContextManager {
19
+ private initialized;
20
+ private readonly config;
21
+ private mem;
22
+ constructor(config?: MemSearchTsConfig);
23
+ connect(): Promise<void>;
24
+ disconnect(): Promise<void>;
25
+ query(question: string, options?: {
26
+ topK?: number;
27
+ }): Promise<string>;
28
+ saveMemory(content: string, title?: string): Promise<void>;
29
+ addResource(resourcePath: string): Promise<string>;
30
+ isConnected(): boolean;
31
+ getStats(): {
32
+ memoryPath: string;
33
+ connected: boolean;
34
+ };
35
+ }
36
+ export declare function createMemSearchTsClient(config?: MemSearchTsConfig): MemSearchTsClient;
37
+ //# sourceMappingURL=memsearch-ts-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memsearch-ts-client.d.ts","sourceRoot":"","sources":["../../src/context/memsearch-ts-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAcD,qBAAa,iBAAkB,YAAW,cAAc;IACtD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,GAAG,CAAkC;gBAEjC,MAAM,GAAE,iBAAsB;IAWpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBrE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1D,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBxD,WAAW,IAAI,OAAO;IAItB,QAAQ,IAAI;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE;CAMvD;AAED,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAErF"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * MemSearch-TS Client
3
+ *
4
+ * TypeScript-native semantic memory client using memsearch-core.
5
+ * Zero Python dependency, built on Milvus vector database.
6
+ *
7
+ * @module @jclaw/core/context/memsearch-ts-client
8
+ */
9
+ import { writeFile, mkdir } from 'fs/promises';
10
+ import { existsSync } from 'fs';
11
+ import { join } from 'path';
12
+ export class MemSearchTsClient {
13
+ initialized = false;
14
+ config;
15
+ mem = null;
16
+ constructor(config = {}) {
17
+ this.config = {
18
+ memoryPath: config.memoryPath || './.jclaw/memory',
19
+ embeddingProvider: config.embeddingProvider || 'openai',
20
+ embeddingModel: config.embeddingModel || 'text-embedding-3-small',
21
+ milvusUri: config.milvusUri || join(process.env.HOME || '.', '.jclaw', 'milvus.db'),
22
+ collectionName: config.collectionName || 'jclaw_memories',
23
+ verbose: config.verbose || false,
24
+ };
25
+ }
26
+ async connect() {
27
+ try {
28
+ if (!existsSync(this.config.memoryPath)) {
29
+ await mkdir(this.config.memoryPath, { recursive: true });
30
+ }
31
+ const { MemSearch } = await import('memsearch-core');
32
+ this.mem = new MemSearch({
33
+ paths: [this.config.memoryPath],
34
+ embedding: {
35
+ provider: this.config.embeddingProvider,
36
+ model: this.config.embeddingModel,
37
+ },
38
+ milvus: {
39
+ uri: this.config.milvusUri,
40
+ collection: this.config.collectionName,
41
+ },
42
+ });
43
+ await this.mem.index();
44
+ this.initialized = true;
45
+ if (this.config.verbose) {
46
+ console.log('[MemSearch-TS] Connected, memory path: ' + this.config.memoryPath);
47
+ }
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error ? error.message : 'Unknown error';
51
+ throw new Error('Failed to initialize MemSearch-TS: ' + message);
52
+ }
53
+ }
54
+ async disconnect() {
55
+ if (this.mem) {
56
+ this.mem.close();
57
+ this.mem = null;
58
+ }
59
+ this.initialized = false;
60
+ }
61
+ async query(question, options) {
62
+ if (!this.initialized || !this.mem) {
63
+ throw new Error('MemSearch-TS client not initialized');
64
+ }
65
+ try {
66
+ await this.mem.index();
67
+ const results = await this.mem.search(question, { topK: options?.topK ?? 5 });
68
+ if (this.config.verbose) {
69
+ console.log('[MemSearch-TS] Found ' + results.length + ' results');
70
+ }
71
+ return results.map((r, i) => '[' + (i + 1) + '] (score: ' + r.score.toFixed(2) + ')\n' + r.content).join('\n\n---\n\n');
72
+ }
73
+ catch (error) {
74
+ if (this.config.verbose) {
75
+ console.error('[MemSearch-TS] Search failed:', error);
76
+ }
77
+ return '';
78
+ }
79
+ }
80
+ async saveMemory(content, title) {
81
+ const date = new Date().toISOString().split('T')[0];
82
+ const timestamp = new Date().toISOString();
83
+ const fileName = date + '.md';
84
+ const filePath = join(this.config.memoryPath, fileName);
85
+ const entry = title
86
+ ? '\n## ' + title + '\n\n> Saved at: ' + timestamp + '\n\n' + content + '\n\n---\n'
87
+ : '\n> Saved at: ' + timestamp + '\n\n' + content + '\n\n---\n';
88
+ await writeFile(filePath, entry, { flag: 'a' });
89
+ if (this.config.verbose) {
90
+ console.log('[MemSearch-TS] Saved memory: ' + (title || 'untitled'));
91
+ }
92
+ if (this.mem) {
93
+ await this.mem.index();
94
+ }
95
+ }
96
+ async addResource(resourcePath) {
97
+ if (!this.initialized) {
98
+ throw new Error('MemSearch-TS client not initialized');
99
+ }
100
+ const { copyFile } = await import('fs/promises');
101
+ const { basename } = await import('path');
102
+ const destPath = join(this.config.memoryPath, basename(resourcePath));
103
+ await copyFile(resourcePath, destPath);
104
+ if (this.mem) {
105
+ await this.mem.index();
106
+ }
107
+ return destPath;
108
+ }
109
+ isConnected() {
110
+ return this.initialized;
111
+ }
112
+ getStats() {
113
+ return {
114
+ memoryPath: this.config.memoryPath,
115
+ connected: this.initialized,
116
+ };
117
+ }
118
+ }
119
+ export function createMemSearchTsClient(config) {
120
+ return new MemSearchTsClient(config);
121
+ }
package/dist/index.d.ts CHANGED
@@ -12,4 +12,5 @@ export { MutationGenerator, createMutationGenerator, type MutationGeneratorConfi
12
12
  export { AutoSkillGenerator, createAutoSkillGenerator, AutoSkillInstaller, createAutoSkillInstaller, type AutoSkillConfig, type CapabilityGap, type DiscoveryResult, type GeneratedExtension, type GenerationResult, type GenerationStep, type InstallationResult, type SkillUsageStats, type AutoSkillMetadata, type SkillVersion, } from './auto-skill/index.js';
13
13
  export { A2AProtocol, GEPProtocol, type A2AMessage, type A2AMessageType, type GEPPacket, type NodeInfo, type GeneSharePayload, type GeneRequestPayload, type TaskDelegatePayload, EvoMapClient, createEvoMapClient, type EvoMapConfig, type GeneResponse, } from './network/index.js';
14
14
  export { fileOperationsExtension } from './extensions/built-in/file-operations.js';
15
+ export { Planner, createPlanner, type Step, type StepStatus, type Plan, type PlannerConfig, type PlanAdjustment, } from './planning/index.js';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EACV,IAAI,EACJ,UAAU,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,UAAU,EACV,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,wBAAwB,EACxB,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAG3E,OAAO,EACL,SAAS,EACT,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,YAAY,EACZ,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,UAAU,EACV,WAAW,EACX,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,gBAAgB,EAChB,aAAa,EACb,KAAK,aAAa,EAClB,eAAe,EACf,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,cAAc,EACd,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,WAAW,EACX,WAAW,EACX,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EACV,IAAI,EACJ,UAAU,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,UAAU,EACV,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,wBAAwB,EACxB,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAG3E,OAAO,EACL,SAAS,EACT,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,YAAY,EACZ,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,UAAU,EACV,WAAW,EACX,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,gBAAgB,EAChB,aAAa,EACb,KAAK,aAAa,EAClB,eAAe,EACf,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,cAAc,EACd,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,WAAW,EACX,WAAW,EACX,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AAGnF,OAAO,EACL,OAAO,EACP,aAAa,EACb,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -18,3 +18,5 @@ export { AutoSkillGenerator, createAutoSkillGenerator, AutoSkillInstaller, creat
18
18
  // Network
19
19
  export { A2AProtocol, GEPProtocol, EvoMapClient, createEvoMapClient, } from './network/index.js';
20
20
  export { fileOperationsExtension } from './extensions/built-in/file-operations.js';
21
+ // Planning Module (任务规划)
22
+ export { Planner, createPlanner, } from './planning/index.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Planning Module
3
+ *
4
+ * @module @jclaw/core/planning
5
+ */
6
+ export type { Step, StepStatus, Plan, PlannerConfig, PlanAdjustment } from './types.js';
7
+ export { Planner, createPlanner } from './planner.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planning/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Planning Module
3
+ *
4
+ * @module @jclaw/core/planning
5
+ */
6
+ export { Planner, createPlanner } from './planner.js';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Task Planner
3
+ *
4
+ * Breaks down tasks into executable steps using LLM.
5
+ *
6
+ * @module @jclaw/core/planning/planner
7
+ */
8
+ import type { LLMClient } from '../runtime/llm-client.js';
9
+ import type { Plan, Step, PlannerConfig, PlanAdjustment } from './types.js';
10
+ export declare class Planner {
11
+ private readonly llmClient;
12
+ private readonly config;
13
+ constructor(llmClient: LLMClient, config?: PlannerConfig);
14
+ plan(taskPrompt: string, relevantExperiences?: string): Promise<Plan>;
15
+ adjust(plan: Plan, failedStep: Step, error: string): Promise<PlanAdjustment>;
16
+ getNextStep(plan: Plan): Step | null;
17
+ advanceStep(plan: Plan, output?: unknown): Plan;
18
+ markStepFailed(plan: Plan, error: string): Plan;
19
+ isComplete(plan: Plan): boolean;
20
+ private parseSteps;
21
+ }
22
+ export declare function createPlanner(llmClient: LLMClient, config?: PlannerConfig): Planner;
23
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/planning/planner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA+B5E,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,SAAS,EAAE,SAAS,EAAE,MAAM,GAAE,aAAkB;IAQtD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDrE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA8BlF,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI;IAOpC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAkB/C,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAgB/C,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAI/B,OAAO,CAAC,UAAU;CA6BnB;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAEnF"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Task Planner
3
+ *
4
+ * Breaks down tasks into executable steps using LLM.
5
+ *
6
+ * @module @jclaw/core/planning/planner
7
+ */
8
+ const PLANNING_PROMPT = `You are a task planner. Break down the given task into clear, sequential steps.
9
+
10
+ Available capabilities:
11
+ - file_read: Read file contents
12
+ - file_write: Write to file
13
+ - file_create: Create new file
14
+ - file_delete: Delete file
15
+ - dir_create: Create directory
16
+ - dir_list: List directory contents
17
+ - file_glob: Search files by pattern
18
+ - file_find: Find file by name
19
+
20
+ Task: {TASK}
21
+
22
+ {CONTEXT}
23
+
24
+ Output ONLY a JSON array of steps, each with:
25
+ - description: What to do (string)
26
+ - capability: Which capability to use (string, optional)
27
+
28
+ Example:
29
+ [
30
+ {"description": "Read the configuration file", "capability": "file_read"},
31
+ {"description": "Analyze the content and prepare modifications"},
32
+ {"description": "Write the updated configuration", "capability": "file_write"}
33
+ ]
34
+
35
+ Steps:`;
36
+ export class Planner {
37
+ llmClient;
38
+ config;
39
+ constructor(llmClient, config = {}) {
40
+ this.llmClient = llmClient;
41
+ this.config = {
42
+ maxSteps: config.maxSteps ?? 5,
43
+ verbose: config.verbose ?? false,
44
+ };
45
+ }
46
+ async plan(taskPrompt, relevantExperiences) {
47
+ const taskId = 'plan-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
48
+ // Build prompt
49
+ let prompt = PLANNING_PROMPT.replace('{TASK}', taskPrompt);
50
+ prompt = prompt.replace('{CONTEXT}', relevantExperiences
51
+ ? 'Relevant past experiences:\n' + relevantExperiences
52
+ : 'No relevant past experiences found.');
53
+ try {
54
+ // Get plan from LLM
55
+ const response = await this.llmClient.chat([
56
+ { role: 'user', content: prompt }
57
+ ]);
58
+ // Parse steps
59
+ const steps = this.parseSteps(response.content);
60
+ if (this.config.verbose) {
61
+ console.log('[Planner] Created plan with ' + steps.length + ' steps');
62
+ }
63
+ return {
64
+ taskId,
65
+ taskPrompt,
66
+ steps,
67
+ currentStepIndex: 0,
68
+ createdAt: Date.now(),
69
+ relevantExperiences,
70
+ };
71
+ }
72
+ catch (error) {
73
+ // Fallback: single-step plan
74
+ if (this.config.verbose) {
75
+ console.log('[Planner] Using fallback single-step plan');
76
+ }
77
+ return {
78
+ taskId,
79
+ taskPrompt,
80
+ steps: [{
81
+ id: 'step-1',
82
+ description: taskPrompt,
83
+ status: 'pending',
84
+ }],
85
+ currentStepIndex: 0,
86
+ createdAt: Date.now(),
87
+ relevantExperiences,
88
+ };
89
+ }
90
+ }
91
+ async adjust(plan, failedStep, error) {
92
+ // Simple adjustment logic
93
+ const stepIndex = plan.steps.findIndex(s => s.id === failedStep.id);
94
+ if (stepIndex === -1) {
95
+ return { type: 'abort', reason: 'Step not found in plan' };
96
+ }
97
+ // Check if we should retry
98
+ const retryCount = failedStep.retryCount || 0;
99
+ if (retryCount < 2) {
100
+ return {
101
+ type: 'retry',
102
+ reason: 'Retrying failed step',
103
+ newSteps: plan.steps.map(s => s.id === failedStep.id
104
+ ? { ...s, retryCount: retryCount + 1 }
105
+ : s),
106
+ };
107
+ }
108
+ // Check if we can skip
109
+ if (plan.steps.length > stepIndex + 1) {
110
+ return { type: 'skip', reason: 'Skipping failed step, continuing with next' };
111
+ }
112
+ return { type: 'abort', reason: error };
113
+ }
114
+ getNextStep(plan) {
115
+ if (plan.currentStepIndex >= plan.steps.length) {
116
+ return null;
117
+ }
118
+ return plan.steps[plan.currentStepIndex];
119
+ }
120
+ advanceStep(plan, output) {
121
+ const updatedSteps = [...plan.steps];
122
+ if (output !== undefined && plan.currentStepIndex < updatedSteps.length) {
123
+ updatedSteps[plan.currentStepIndex] = {
124
+ ...updatedSteps[plan.currentStepIndex],
125
+ status: 'completed',
126
+ output,
127
+ };
128
+ }
129
+ return {
130
+ ...plan,
131
+ steps: updatedSteps,
132
+ currentStepIndex: plan.currentStepIndex + 1,
133
+ completedAt: plan.currentStepIndex + 1 >= plan.steps.length ? Date.now() : undefined,
134
+ };
135
+ }
136
+ markStepFailed(plan, error) {
137
+ const updatedSteps = [...plan.steps];
138
+ if (plan.currentStepIndex < updatedSteps.length) {
139
+ updatedSteps[plan.currentStepIndex] = {
140
+ ...updatedSteps[plan.currentStepIndex],
141
+ status: 'failed',
142
+ error,
143
+ };
144
+ }
145
+ return {
146
+ ...plan,
147
+ steps: updatedSteps,
148
+ };
149
+ }
150
+ isComplete(plan) {
151
+ return plan.currentStepIndex >= plan.steps.length;
152
+ }
153
+ parseSteps(content) {
154
+ try {
155
+ // Try to extract JSON array from response
156
+ const jsonMatch = content.match(/\[[\s\S]*\]/);
157
+ if (!jsonMatch) {
158
+ throw new Error('No JSON array found');
159
+ }
160
+ const parsed = JSON.parse(jsonMatch[0]);
161
+ if (!Array.isArray(parsed)) {
162
+ throw new Error('Parsed content is not an array');
163
+ }
164
+ return parsed.slice(0, this.config.maxSteps).map((step, i) => ({
165
+ id: 'step-' + (i + 1),
166
+ description: step.description || step,
167
+ status: 'pending',
168
+ capability: step.capability,
169
+ input: step.input,
170
+ }));
171
+ }
172
+ catch {
173
+ // Fallback: treat entire response as single step
174
+ return [{
175
+ id: 'step-1',
176
+ description: content.slice(0, 200),
177
+ status: 'pending',
178
+ }];
179
+ }
180
+ }
181
+ }
182
+ export function createPlanner(llmClient, config) {
183
+ return new Planner(llmClient, config);
184
+ }