@qcluffy/agent-bootstrap 0.0.3 → 0.0.4

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.
@@ -1,169 +1,134 @@
1
1
  /**
2
- * Memory System Hook Handler
2
+ * Memory System Hook Handler - TypeScript 版本
3
3
  *
4
- * 集成 Python memory-system 到 OpenClaw
4
+ * 直接调用 TypeScript 编译后的 memory 模块
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
7
  const path = require('path');
9
- const { spawn } = require('child_process');
10
- const os = require('os');
11
8
 
12
- // 配置
9
+ // 获取插件目录
10
+ const pluginDir = __dirname;
11
+
12
+ // 配置 - 指向 dist/systems
13
13
  const CONFIG = {
14
- memorySystemPath: 'templates/memory-system',
15
- cliScript: 'cli.py',
14
+ memorySystemPath: path.join(pluginDir, 'dist', 'systems'),
16
15
  };
17
16
 
18
17
  /**
19
- * 运行 Python memory-system CLI
18
+ * 加载 TypeScript 编译后的 MemorySystem
20
19
  */
21
- async function runPythonCli(args) {
22
- const workspaceDir = process.env.OPENCLAW_WORKSPACE ||
23
- path.join(os.homedir(), '.openclaw', 'workspace');
24
- const pythonScript = path.join(workspaceDir, CONFIG.memorySystemPath, CONFIG.cliScript);
25
-
26
- return new Promise((resolve) => {
27
- fs.access(pythonScript).then(() => {
28
- const proc = spawn('python3', [pythonScript, ...args], {
29
- cwd: workspaceDir,
30
- env: {
31
- ...process.env,
32
- OPENCLAW_WORKSPACE: workspaceDir,
33
- PYTHONPATH: path.join(workspaceDir, CONFIG.memorySystemPath)
34
- }
35
- });
36
-
37
- let output = '';
38
- let error = '';
39
-
40
- proc.stdout.on('data', (data) => { output += data.toString(); });
41
- proc.stderr.on('data', (data) => { error += data.toString(); });
42
-
43
- proc.on('close', (code) => {
44
- try {
45
- if (output) {
46
- const result = JSON.parse(output);
47
- resolve(result);
48
- } else {
49
- resolve({ success: false, error: 'No output' });
50
- }
51
- } catch (e) {
52
- resolve({ success: false, error: error || 'Parse error' });
53
- }
54
- });
55
-
56
- proc.on('error', (err) => {
57
- resolve({ success: false, error: err.message });
58
- });
59
-
60
- }).catch(() => {
61
- resolve({ success: false, error: 'Memory system not found' });
62
- });
63
- });
64
- }
20
+ let MemorySystem = null;
65
21
 
66
- /**
67
- * 从会话消息中提取文本内容
68
- */
69
- function extractMessageText(message) {
70
- if (!message || !message.content) return '';
71
-
72
- if (typeof message.content === 'string') {
73
- return message.content;
74
- }
75
-
76
- if (Array.isArray(message.content)) {
77
- return message.content
78
- .filter((c) => c.type === 'text')
79
- .map((c) => c.text || '')
80
- .join('');
22
+ async function getMemorySystem() {
23
+ if (!MemorySystem) {
24
+ try {
25
+ const module = await import(path.join(CONFIG.memorySystemPath, 'memory.js'));
26
+ MemorySystem = module.MemorySystem || module.default;
27
+ } catch (e) {
28
+ console.error('[memory-system] Failed to load memory module:', e.message);
29
+ return null;
30
+ }
81
31
  }
82
-
83
- return '';
32
+ return MemorySystem;
84
33
  }
85
34
 
86
35
  /**
87
- * 生成上下文摘要
36
+ * 处理 message:received - 自动保存记忆
88
37
  */
89
- function formatContextSummary(data) {
90
- if (!data || !data.success || !data.context) return '';
38
+ async function handleMessageReceived(event) {
39
+ console.log('[memory-system] Auto-saving memory...');
91
40
 
92
- const { context } = data;
93
- const lines = [];
94
-
95
- if (context.preferences) {
96
- const p = context.preferences;
97
- if (p.userName || p.agentName) {
98
- lines.push(`【用户信息】名字: ${p.userName || p.agentName || '未知'}`);
41
+ try {
42
+ const MemoryClass = await getMemorySystem();
43
+ if (MemoryClass) {
44
+ const ms = new MemoryClass();
45
+ const context = event.context || {};
46
+ const messages = context.messages || [];
47
+
48
+ // 保存最近的对话
49
+ if (messages.length > 0) {
50
+ const recent = messages.slice(-5);
51
+ for (const msg of recent) {
52
+ if (msg.role && msg.content) {
53
+ ms.save(`[${msg.role}] ${msg.content}`, {
54
+ type: 'episodic',
55
+ tags: ['对话'],
56
+ });
57
+ }
58
+ }
59
+ }
60
+ console.log('[memory-system] Memory saved');
99
61
  }
62
+ } catch (e) {
63
+ console.log('[memory-system] Save error:', e.message);
100
64
  }
101
65
 
102
- if (context.recent_memories && context.recent_memories.length > 0) {
103
- lines.push('【近期记忆】');
104
- context.recent_memories.slice(0, 3).forEach((m) => {
105
- const content = m.content ? m.content.substring(0, 50) : '';
106
- const date = m.created_at ? m.created_at.substring(0, 10) : '';
107
- lines.push(` - [${date}] ${content}...`);
108
- });
109
- }
110
-
111
- return lines.length > 0 ? '\n' + lines.join('\n') : '';
66
+ return event;
112
67
  }
113
68
 
114
69
  /**
115
- * 处理 session_start
70
+ * 处理 session_end - 保存会话记忆
116
71
  */
117
- async function handleSessionStart(event) {
118
- console.log('[memory-system] Session start, loading context...');
119
-
120
- const context = event.context || {};
121
- const result = await runPythonCli(['get_context']);
72
+ async function handleSessionEnd(event) {
73
+ console.log('[memory-system] Session end, saving context...');
122
74
 
123
- if (result.success && result.context) {
124
- const summary = formatContextSummary(result);
125
- if (summary) {
126
- if (!context.prependContext) context.prependContext = '';
127
- context.prependContext += '\n\n--- 记忆系统 ---\n' + summary;
128
- console.log('[memory-system] Context injected successfully');
75
+ try {
76
+ const MemoryClass = await getMemorySystem();
77
+ if (MemoryClass) {
78
+ const ms = new MemoryClass();
79
+ const context = event.context || {};
80
+
81
+ // 保存会话摘要
82
+ if (context.summary) {
83
+ ms.rememberThis(`会话摘要: ${context.summary}`, true);
84
+ }
85
+
86
+ console.log('[memory-system] Session memory saved');
129
87
  }
130
- } else {
131
- console.log('[memory-system] No context to load:', result.error);
88
+ } catch (e) {
89
+ console.log('[memory-system] Session save error:', e.message);
132
90
  }
133
91
 
134
- event.context = context;
92
+ return event;
135
93
  }
136
94
 
137
95
  /**
138
- * 处理 agent_end
96
+ * 处理 command - 搜索记忆
139
97
  */
140
- async function handleAgentEnd(event) {
141
- console.log('[memory-system] Agent end, saving conversation...');
142
-
143
- const context = event.context || {};
144
- const messages = context.messages || [];
145
-
146
- if (messages.length === 0) return;
147
-
148
- const reversed = [...messages].reverse();
149
- const lastUserMsg = reversed.find((m) => m.role === 'user');
150
- const lastAssistantMsg = reversed.find((m) => m.role === 'assistant');
98
+ async function handleCommand(event) {
99
+ const action = event.action || '';
151
100
 
152
- if (lastUserMsg) {
153
- const userText = extractMessageText(lastUserMsg);
154
- const assistantText = lastAssistantMsg ? extractMessageText(lastAssistantMsg) : '';
155
-
156
- if (userText && userText.length < 1000 && !userText.startsWith('/')) {
157
- const content = `用户: ${userText}\n助手: ${assistantText}`;
158
- const result = await runPythonCli(['save', content, 'episodic', '对话', '0.3']);
159
-
160
- if (result.success) {
161
- console.log('[memory-system] Conversation saved:', result.memory_id);
162
- } else {
163
- console.log('[memory-system] Save failed:', result.error);
101
+ if (action === 'remember' || action === '记忆') {
102
+ try {
103
+ const MemoryClass = await getMemorySystem();
104
+ if (MemoryClass) {
105
+ const ms = new MemoryClass();
106
+ const content = event.params?.content || '';
107
+
108
+ if (content) {
109
+ ms.rememberThis(content, event.params?.important || false);
110
+ event.response = '已记住: ' + content;
111
+ }
112
+ }
113
+ } catch (e) {
114
+ event.response = '记忆错误: ' + e.message;
115
+ }
116
+ }
117
+ else if (action === 'recall' || action === '想起') {
118
+ try {
119
+ const MemoryClass = await getMemorySystem();
120
+ if (MemoryClass) {
121
+ const ms = new MemorySystem();
122
+ const about = event.params?.about || '';
123
+
124
+ event.response = ms.whatDoYouRemember(about);
164
125
  }
126
+ } catch (e) {
127
+ event.response = '回忆错误: ' + e.message;
165
128
  }
166
129
  }
130
+
131
+ return event;
167
132
  }
168
133
 
169
134
  /**
@@ -176,38 +141,29 @@ async function handle(event) {
176
141
  console.log(`[memory-system] Event: ${type}/${action}`);
177
142
 
178
143
  try {
179
- if (type === 'command') {
180
- if (action === 'new' || action === 'reset') {
181
- await handleAgentEnd(event);
182
- }
183
- }
184
- else if (type === 'lifecycle' || type === 'lifecycle:end') {
185
- if (action === 'end' || action === '') {
186
- await handleAgentEnd(event);
187
- }
144
+ if (type === 'message' || type === 'message:received') {
145
+ await handleMessageReceived(event);
188
146
  }
189
- else if (type === 'session' || type === 'session:start') {
190
- if (action === 'start' || action === '') {
191
- await handleSessionStart(event);
192
- }
147
+ else if (type === 'session' || type === 'session:end') {
148
+ await handleSessionEnd(event);
193
149
  }
194
- else if (type === 'message' || type === 'message:received') {
195
- await handleMessageReceived(event);
150
+ else if (type === 'command') {
151
+ await handleCommand(event);
196
152
  }
197
153
  } catch (error) {
198
154
  console.error('[memory-system] Handler error:', error.message);
199
155
  }
156
+
157
+ return event;
200
158
  }
201
159
 
202
- // 默认导出
203
160
  module.exports = handle;
204
161
  module.exports.handle = handle;
205
162
  module.exports.metadata = {
206
163
  name: 'memory-system',
207
- description: '集成记忆系统,自动保存对话和加载历史上下文',
208
- events: ['command', 'lifecycle', 'session'],
164
+ description: 'Memory System: auto-save conversations and context',
165
+ events: ['session', 'message', 'command'],
209
166
  version: '1.0.0',
210
167
  };
211
168
 
212
- // 也导出 default 兼容
213
169
  module.exports.default = handle;
@@ -1,149 +1,81 @@
1
1
  /**
2
- * Output System Hook Handler
2
+ * Output System Hook Handler - TypeScript 版本
3
3
  *
4
- * 集成 Python output-system 到 OpenClaw
4
+ * 直接调用 TypeScript 编译后的 output 模块
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
7
  const path = require('path');
9
- const { spawn } = require('child_process');
10
- const os = require('os');
11
8
 
12
- // 配置
9
+ // 获取插件目录
10
+ const pluginDir = __dirname;
11
+
12
+ // 配置 - 指向 dist/systems
13
13
  const CONFIG = {
14
- outputSystemPath: 'templates/output-system',
15
- mainScript: 'main.py',
14
+ outputSystemPath: path.join(pluginDir, 'dist', 'systems'),
16
15
  };
17
16
 
18
17
  /**
19
- * 运行 Python output-system CLI
18
+ * 加载 TypeScript 编译后的 OutputSystem
20
19
  */
21
- async function runPythonCli(args = []) {
22
- const workspaceDir = process.env.OPENCLAW_WORKSPACE ||
23
- path.join(os.homedir(), '.openclaw', 'workspace');
24
- const pythonScript = path.join(workspaceDir, CONFIG.outputSystemPath, CONFIG.mainScript);
25
-
26
- return new Promise((resolve) => {
27
- fs.access(pythonScript).then(() => {
28
- const proc = spawn('python3', [pythonScript, ...args], {
29
- cwd: workspaceDir,
30
- env: {
31
- ...process.env,
32
- OPENCLAW_WORKSPACE: workspaceDir,
33
- PYTHONPATH: path.join(workspaceDir, CONFIG.outputSystemPath)
34
- }
35
- });
36
-
37
- let output = '';
38
- let error = '';
39
-
40
- proc.stdout.on('data', (data) => { output += data.toString(); });
41
- proc.stderr.on('data', (data) => { error += data.toString(); });
42
-
43
- proc.on('close', (code) => {
44
- resolve({ success: code === 0, output, error });
45
- });
46
-
47
- proc.on('error', (err) => {
48
- resolve({ success: false, error: err.message });
49
- });
50
-
51
- }).catch(() => {
52
- resolve({ success: false, error: 'Output system not found' });
53
- });
54
- });
55
- }
20
+ let OutputSystem = null;
56
21
 
57
- /**
58
- * 格式化输出
59
- */
60
- function formatOutput(content, context) {
61
- const style = context?.replyStrategy?.style || 'friendly';
62
- const format = context?.replyStrategy?.format || 'text';
63
-
64
- // 附加情感状态
65
- let emotionLine = '';
66
- if (context?.emotionState) {
67
- const e = context.emotionState;
68
- emotionLine = `\n${e.mood_emoji || '🧐'} Lv.${e.level} | ⚡${Math.round(e.energy*100)}% | 💕${Math.round(e.connection*100)}%`;
22
+ async function getOutputSystem() {
23
+ if (!OutputSystem) {
24
+ try {
25
+ const module = await import(path.join(CONFIG.outputSystemPath, 'output.js'));
26
+ OutputSystem = module.OutputSystem || module.default;
27
+ } catch (e) {
28
+ console.error('[output-system] Failed to load output module:', e.message);
29
+ return null;
30
+ }
69
31
  }
70
-
71
- return content + emotionLine;
32
+ return OutputSystem;
72
33
  }
73
34
 
74
35
  /**
75
- * 处理 agent_start - 准备输出
36
+ * 处理 agent:before - 准备输出
76
37
  */
77
- async function handleAgentStart(event) {
38
+ async function handleBeforeAgent(event) {
78
39
  console.log('[output-system] Preparing output...');
79
40
 
80
- const context = event.context || {};
81
-
82
- // 获取回复策略
83
- const strategy = context.replyStrategy || {};
84
-
85
- // 准备输出格式
86
- context.outputConfig = {
87
- style: strategy.style || 'friendly',
88
- format: strategy.format || 'text',
89
- includeEmotion: true,
90
- };
91
-
92
- return event;
93
- }
94
-
95
- /**
96
- * 处理 agent_end - 生成输出
97
- */
98
- async function handleAgentEnd(event) {
99
- console.log('[output-system] Generating output...');
100
-
101
- const context = event.context || {};
102
- const messages = context.messages || [];
103
-
104
- // 获取最后助手回复
105
- const reversed = [...messages].reverse();
106
- const lastAssistantMsg = reversed.find((m) => m.role === 'assistant');
107
-
108
- if (lastAssistantMsg) {
109
- // 获取内容
110
- let content = '';
111
- if (typeof lastAssistantMsg.content === 'string') {
112
- content = lastAssistantMsg.content;
113
- } else if (Array.isArray(lastAssistantMsg.content)) {
114
- content = lastAssistantMsg.content
115
- .filter((c) => c.type === 'text')
116
- .map((c) => c.text || '')
117
- .join('');
41
+ try {
42
+ const OutputClass = await getOutputSystem();
43
+ if (OutputClass) {
44
+ const outputSystem = new OutputClass();
45
+ const context = event.context || {};
46
+
47
+ // 应用输出格式化
48
+ context.outputStyle = context.outputStyle || 'direct';
49
+
50
+ event.context = context;
51
+ console.log('[output-system] Output prepared, style:', context.outputStyle);
118
52
  }
119
-
120
- // 格式化输出(附加情感状态)
121
- const formattedContent = formatOutput(content, context);
122
-
123
- // 更新消息
124
- lastAssistantMsg.content = formattedContent;
125
-
126
- console.log('[output-system] Output formatted with emotion state');
53
+ } catch (e) {
54
+ console.log('[output-system] Prepare error:', e.message);
127
55
  }
128
56
 
129
57
  return event;
130
58
  }
131
59
 
132
60
  /**
133
- * 执行行动
61
+ * 处理 agent:end - 收集反馈
134
62
  */
135
- async function handleExecuteAction(event) {
136
- const action = event.action;
137
- const params = event.params || {};
63
+ async function handleAgentEnd(event) {
64
+ console.log('[output-system] Collecting feedback...');
138
65
 
139
- if (action) {
140
- const result = await runPythonCli([
141
- 'action',
142
- action,
143
- JSON.stringify(params)
144
- ]);
145
-
146
- event.actionResult = result;
66
+ try {
67
+ const OutputClass = await getOutputSystem();
68
+ if (OutputClass) {
69
+ const outputSystem = new OutputClass();
70
+ const response = event.response;
71
+
72
+ if (response) {
73
+ // 可以在这里记录输出统计
74
+ console.log('[output-system] Response sent, length:', response.length);
75
+ }
76
+ }
77
+ } catch (e) {
78
+ console.log('[output-system] Feedback error:', e.message);
147
79
  }
148
80
 
149
81
  return event;
@@ -159,23 +91,12 @@ async function handle(event) {
159
91
  console.log(`[output-system] Event: ${type}/${action}`);
160
92
 
161
93
  try {
162
- if (type === 'agent' || type === 'agent_start') {
163
- await handleAgentStart(event);
94
+ if (type === 'agent' || type === 'agent:before') {
95
+ await handleBeforeAgent(event);
164
96
  }
165
- else if (type === 'lifecycle' || type === 'lifecycle:end' || type === 'agent_end') {
97
+ else if (type === 'agent' || type === 'agent:end') {
166
98
  await handleAgentEnd(event);
167
99
  }
168
- else if (type === 'command') {
169
- if (action === 'execute' || action === 'run') {
170
- await handleExecuteAction(event);
171
- }
172
- else if (action === 'output' || action === 'status') {
173
- const result = await runPythonCli(['status', '--json']);
174
- if (result.success) {
175
- event.response = result.output;
176
- }
177
- }
178
- }
179
100
  } catch (error) {
180
101
  console.error('[output-system] Handler error:', error.message);
181
102
  }
@@ -187,8 +108,8 @@ module.exports = handle;
187
108
  module.exports.handle = handle;
188
109
  module.exports.metadata = {
189
110
  name: 'output-system',
190
- description: '输出执行系统,语言生成、行动执行、反馈收集、多模态输出',
191
- events: ['agent', 'lifecycle', 'command'],
111
+ description: 'Output System: format and execute agent output',
112
+ events: ['agent'],
192
113
  version: '1.0.0',
193
114
  };
194
115
 
@@ -2,7 +2,7 @@
2
2
  "id": "agent-bootstrap",
3
3
  "name": "Agent Bootstrap",
4
4
  "description": "Complete Agent Core System: Memory, Emotion, Heartbeat, Input, Cognition, Output, Bootstrap",
5
- "version": "0.0.3",
5
+ "version": "0.0.4",
6
6
  "kind": "context-engine",
7
7
  "package": "@qcluffy/agent-bootstrap",
8
8
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qcluffy/agent-bootstrap",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "OpenClaw Agent Plugin - Complete Agent Core System: Memory, Emotion, Heartbeat, Input, Cognition, Output, Bootstrap",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",