foliko 1.1.2 → 1.1.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.
- package/.agent/agents/code-assistant.json +14 -0
- package/.agent/agents/email-assistant.json +14 -0
- package/.agent/agents/file-assistant.json +15 -0
- package/.agent/agents/system-assistant.json +15 -0
- package/.agent/agents/web-assistant.json +12 -0
- package/.agent/data/ambient/goals.json +50 -0
- package/.agent/data/ambient/memories.json +7 -0
- package/.agent/data/default.json +3 -412
- package/.agent/data/plugins-state.json +174 -173
- package/.agent/data/scheduler/tasks.json +1 -0
- package/.agent/memory/core.md +1 -0
- package/.agent/memory/project/mnn93ogy-ypjn27.md +9 -0
- package/.agent/memory/project/mnn98fqy-5nhc1u.md +25 -0
- package/.agent/memory/reference/mnq3oenw-46haj6.md +63 -0
- package/.agent/memory/reference/mnq5qxm2-mjoooh.md +116 -0
- package/.agent/memory/user/mnm67t9m-x8rekk.md +9 -0
- package/.agent/memory/user/mnn5mmqh-w6aktx.md +11 -0
- package/.agent/memory/user/mnnbfhhn-dk1bd1.md +22 -0
- package/.agent/package.json +8 -0
- package/.agent/plugins/__pycache__/file_writer.cpython-312.pyc +0 -0
- package/.agent/plugins/daytona/README.md +89 -0
- package/.agent/plugins/daytona/index.js +377 -0
- package/.agent/plugins/daytona/package.json +12 -0
- package/.agent/plugins/marknative/README.md +134 -0
- package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/marknative/index.js +256 -0
- package/.agent/plugins/marknative/package.json +12 -0
- package/.agent/plugins/marknative/update-readme.js +134 -0
- package/.agent/plugins/poster-plugin/emojis/rocket.png +1 -0
- package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/poster-plugin/src/elements/text.js +3 -1
- package/.agent/plugins/poster-plugin/src/fonts.js +10 -0
- package/.agent/plugins/poster-plugin/yarn.lock +1007 -0
- package/.agent/plugins/system-info/index.js +387 -0
- package/.agent/plugins/system-info/package.json +4 -0
- package/.agent/plugins/system-info/test.js +40 -0
- package/.agent/plugins.json +11 -5
- package/.agent/python-scripts/test_sample.py +24 -0
- package/.agent/sessions/cli_default.json +1869 -691
- package/.agent/skills/agent-browser/SKILL.md +311 -0
- package/.agent/skills/agent-browser/TEST_PLAN.md +200 -0
- package/.agent/skills/sysinfo/SKILL.md +38 -0
- package/.agent/skills/sysinfo/system-info.sh +130 -0
- package/.agent/skills/workflow/SKILL.md +324 -0
- package/.agent/weixin.json +6 -0
- package/.agent/workflows/email-digest.json +50 -0
- package/.agent/workflows/file-backup.json +21 -0
- package/.agent/workflows/get-ip-notify.json +32 -0
- package/.agent/workflows/news-aggregator.json +93 -0
- package/.agent/workflows/news-dashboard-v2.json +94 -0
- package/.agent/workflows/notification-batch.json +32 -0
- package/.claude/settings.local.json +1 -20
- package/.env.example +56 -56
- package/README.md +441 -441
- package/cli/src/commands/chat.js +22 -13
- package/cli/src/ui/chat-ui.js +50 -37
- package/output/emoji-segoe-test-v2.png +0 -0
- package/output/emoji-segoe-test.png +0 -0
- package/output/emoji-test.png +0 -0
- package/output/emoji-windows-test.png +0 -0
- package/output/foliko-emoji-poster.png +0 -0
- package/output/foliko-muji-poster-final.png +0 -0
- package/output/foliko-muji-poster-v2.png +0 -0
- package/output/foliko-muji-poster.png +0 -0
- package/output/foliko-share.png +0 -0
- package/output/progress-circle-test.png +0 -0
- package/output/vb-agent-poster.png +0 -0
- package/package.json +1 -2
- package/plugins/default-plugins.js +4 -3
- package/plugins/extension-executor-plugin.js +12 -91
- package/plugins/file-system-plugin.js +19 -4
- package/plugins/memory-plugin.js +33 -4
- package/plugins/subagent-plugin.js +14 -37
- package/plugins/weixin-plugin.js +40 -168
- package/skills/find-skills/AGENTS.md +162 -162
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/poster-guide/SKILL.md +669 -1426
- package/src/core/agent-chat.js +439 -269
- package/src/core/agent.js +3 -6
- package/.agent/.shared/ui-ux-pro-max/data/charts.csv +0 -26
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +0 -58
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +0 -258
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +0 -106
- package/.agent/ARCHITECTURE.md +0 -288
- package/.agent/agents/ambient-agent.md +0 -57
- package/.agent/agents/debugger.md +0 -55
- package/.agent/agents/email-assistant.md +0 -49
- package/.agent/agents/file-manager.md +0 -42
- package/.agent/agents/python-developer.md +0 -60
- package/.agent/agents/scheduler.md +0 -59
- package/.agent/agents/web-developer.md +0 -45
- package/.agent/data/puppeteer-sessions/undefined.json +0 -6
- package/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
- package/.agent/mcp_config_updated.json +0 -12
- package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
- package/.agent/plugins/puppeteer-plugin/README.md +0 -147
- package/.agent/plugins/puppeteer-plugin/index.js +0 -1418
- package/.agent/plugins/puppeteer-plugin/package.json +0 -9
- package/.agent/rules/GEMINI.md +0 -273
- package/.agent/rules/allow-rule.md +0 -77
- package/.agent/rules/log-rule.md +0 -83
- package/.agent/rules/security-rule.md +0 -93
- package/.agent/scripts/auto_preview.py +0 -148
- package/.agent/scripts/checklist.py +0 -217
- package/.agent/scripts/session_manager.py +0 -120
- package/.agent/scripts/verify_all.py +0 -327
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +0 -11097
- package/.agent/skills/api-patterns/SKILL.md +0 -81
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/scripts/api_validator.py +0 -211
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/SKILL.md +0 -75
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/app-builder/templates/SKILL.md +0 -39
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
- package/.agent/skills/architecture/SKILL.md +0 -55
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/clean-code/SKILL.md +0 -201
- package/.agent/skills/doc.md +0 -177
- package/.agent/skills/frontend-design/SKILL.md +0 -418
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -311
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +0 -183
- package/.agent/skills/frontend-design/scripts/ux_audit.py +0 -722
- package/.agent/skills/frontend-design/typography-system.md +0 -345
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/i18n-localization/SKILL.md +0 -154
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +0 -241
- package/.agent/skills/mcp-builder/SKILL.md +0 -176
- package/.agent/skills/web-design-guidelines/SKILL.md +0 -57
- package/.agent/workflows/brainstorm.md +0 -113
- package/.agent/workflows/create.md +0 -59
- package/.agent/workflows/debug.md +0 -103
- package/.agent/workflows/deploy.md +0 -176
- package/.agent/workflows/enhance.md +0 -63
- package/.agent/workflows/orchestrate.md +0 -237
- package/.agent/workflows/plan.md +0 -89
- package/.agent/workflows/preview.md +0 -81
- package/.agent/workflows/simple-test.md +0 -42
- package/.agent/workflows/status.md +0 -86
- package/.agent/workflows/structured-orchestrate.md +0 -180
- package/.agent/workflows/test.md +0 -144
- package/.agent/workflows/ui-ux-pro-max.md +0 -296
- package/output/beef-love-poster.png +0 -0
- package/output/international-news-daily.png +0 -0
- package/poster-test-2.png +0 -0
package/cli/src/commands/chat.js
CHANGED
|
@@ -71,9 +71,18 @@ function parseArgs(args) {
|
|
|
71
71
|
options.baseURL = args[++i];
|
|
72
72
|
} else if (arg === '--api-key' && args[i + 1]) {
|
|
73
73
|
options.apiKey = args[++i];
|
|
74
|
+
} else if (arg === '--stream') {
|
|
75
|
+
options.stream = true;
|
|
76
|
+
} else if (arg === '--no-stream') {
|
|
77
|
+
options.stream = false;
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
// 默认开启流式
|
|
82
|
+
if (options.stream === undefined) {
|
|
83
|
+
options.stream = true;
|
|
84
|
+
}
|
|
85
|
+
|
|
77
86
|
return options;
|
|
78
87
|
}
|
|
79
88
|
|
|
@@ -94,16 +103,21 @@ async function chatCommand(args) {
|
|
|
94
103
|
baseURL: options.baseURL,
|
|
95
104
|
apiKey: options.apiKey,
|
|
96
105
|
providerOptions: {
|
|
97
|
-
maxOutputTokens:
|
|
98
|
-
reasoning_split: true,
|
|
106
|
+
maxOutputTokens: 8192,
|
|
99
107
|
},
|
|
100
108
|
},
|
|
101
109
|
});
|
|
102
110
|
|
|
103
|
-
//
|
|
104
|
-
const agent = framework.
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
// 使用框架的 _mainAgent(已注册 memory-context 等)
|
|
112
|
+
const agent = framework._mainAgent;
|
|
113
|
+
if (!agent) {
|
|
114
|
+
console.error('错误:框架未正确初始化,请检查 AI 配置');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 更新 _mainAgent 的配置
|
|
119
|
+
agent.setMetadata('WORK_DIR', process.cwd());
|
|
120
|
+
agent.setSystemPrompt(`你是一个有帮助的助手,擅长回答问题和执行任务。
|
|
107
121
|
**重要:** 子Agent 匹配规则必须遵守:
|
|
108
122
|
- 根据【子 Agent 匹配表】,将任务委托给最匹配的子Agent处理
|
|
109
123
|
- 使用 subagent_call 工具并指定 agentName 来委托任务
|
|
@@ -111,15 +125,10 @@ async function chatCommand(args) {
|
|
|
111
125
|
**命令执行规范:**
|
|
112
126
|
- 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
|
|
113
127
|
- 禁止添加 -g 参数
|
|
114
|
-
- 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y
|
|
115
|
-
sharedPrompt: `工作目录: {{WORK_DIR}}`,
|
|
116
|
-
metadata: {
|
|
117
|
-
WORK_DIR: process.cwd(), // 覆盖内置的 WORK_DIR
|
|
118
|
-
},
|
|
119
|
-
});
|
|
128
|
+
- 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`);
|
|
120
129
|
|
|
121
130
|
// 初始化 UI
|
|
122
|
-
const ui = new ChatUI(agent);
|
|
131
|
+
const ui = new ChatUI(agent, { stream: options.stream });
|
|
123
132
|
|
|
124
133
|
// 监听通知事件,在 CLI 中显示
|
|
125
134
|
// 显示当前会话的通知,以及没有指定 sessionId 的广播通知
|
package/cli/src/ui/chat-ui.js
CHANGED
|
@@ -13,6 +13,9 @@ class ChatUI {
|
|
|
13
13
|
this.rl = null;
|
|
14
14
|
this.lines = []; // 多行输入的累积
|
|
15
15
|
|
|
16
|
+
// 流式模式(默认开启)
|
|
17
|
+
this.stream = options.stream !== false;
|
|
18
|
+
|
|
16
19
|
// 会话管理
|
|
17
20
|
this.sessionId = options.sessionId || 'cli_default';
|
|
18
21
|
this.sessionPlugin = null;
|
|
@@ -121,13 +124,6 @@ class ChatUI {
|
|
|
121
124
|
* 发送消息并显示响应
|
|
122
125
|
*/
|
|
123
126
|
async sendMessage(message) {
|
|
124
|
-
// console.log();
|
|
125
|
-
|
|
126
|
-
// // 添加用户消息到会话历史
|
|
127
|
-
// if (this.sessionPlugin) {
|
|
128
|
-
// this.sessionPlugin.addMessage(this.sessionId, { role: 'user', content: message });
|
|
129
|
-
// }
|
|
130
|
-
|
|
131
127
|
// 用于打断的标志
|
|
132
128
|
let interrupted = false;
|
|
133
129
|
|
|
@@ -145,43 +141,65 @@ class ChatUI {
|
|
|
145
141
|
let fullResponse = '';
|
|
146
142
|
|
|
147
143
|
try {
|
|
148
|
-
let lineBuffer = '';
|
|
149
144
|
const renderState = { inThink: false, inCodeBlock: false };
|
|
150
|
-
|
|
151
|
-
console.log(colored('● ', GREEN));
|
|
152
|
-
// console.log()
|
|
153
|
-
|
|
154
145
|
const runWithContext = this.agent.framework?.runWithContext.bind(this.agent.framework);
|
|
155
146
|
const { sessionId } = this;
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
148
|
+
if (this.stream) {
|
|
149
|
+
// 流式模式
|
|
150
|
+
console.log(colored('● ', GREEN));
|
|
151
|
+
|
|
152
|
+
let lineBuffer = '';
|
|
153
|
+
await runWithContext({ sessionId }, async () => {
|
|
154
|
+
for await (const chunk of this.agent.chatStream(message, { sessionId })) {
|
|
155
|
+
if (interrupted) break;
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
if (chunk.type === 'text') {
|
|
158
|
+
fullResponse += chunk.text;
|
|
159
|
+
lineBuffer += chunk.text;
|
|
164
160
|
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
while (lineBuffer.includes('\n')) {
|
|
162
|
+
if (interrupted) break;
|
|
167
163
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
const nlIndex = lineBuffer.indexOf('\n');
|
|
165
|
+
const line = lineBuffer.substring(0, nlIndex);
|
|
166
|
+
lineBuffer = lineBuffer.substring(nlIndex + 1);
|
|
167
|
+
if (line.trim()) {
|
|
168
|
+
console.log(renderLine(line, renderState));
|
|
169
|
+
}
|
|
173
170
|
}
|
|
171
|
+
} else if (chunk.type === 'tool-call') {
|
|
172
|
+
console.log(`\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`);
|
|
173
|
+
} else if (chunk.type === 'error') {
|
|
174
|
+
console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
|
|
174
175
|
}
|
|
175
|
-
} else if (chunk.type === 'tool-call') {
|
|
176
|
-
console.log(`\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`);
|
|
177
|
-
} else if (chunk.type === 'error') {
|
|
178
|
-
console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
|
|
179
176
|
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (lineBuffer.trim() && !interrupted) {
|
|
180
|
+
console.log(renderLine(lineBuffer, renderState));
|
|
180
181
|
}
|
|
181
|
-
}
|
|
182
|
+
} else {
|
|
183
|
+
// 非流式模式
|
|
184
|
+
console.log(colored('○ ', CYAN) + '处理中...\n');
|
|
182
185
|
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
const result = await runWithContext({ sessionId }, async () => {
|
|
187
|
+
return await this.agent.chat(message, { sessionId });
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (interrupted) return;
|
|
191
|
+
|
|
192
|
+
fullResponse = result.message;
|
|
193
|
+
|
|
194
|
+
// 一次性渲染完整响应
|
|
195
|
+
const lines = fullResponse.split('\n');
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
if (line.trim()) {
|
|
198
|
+
console.log(renderLine(line, renderState));
|
|
199
|
+
} else {
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
185
203
|
}
|
|
186
204
|
} catch (err) {
|
|
187
205
|
if (!interrupted) {
|
|
@@ -189,11 +207,6 @@ class ChatUI {
|
|
|
189
207
|
}
|
|
190
208
|
} finally {
|
|
191
209
|
process.removeListener('SIGINT', interruptHandler);
|
|
192
|
-
|
|
193
|
-
// 添加助手回复到会话历史
|
|
194
|
-
// if (this.sessionPlugin && fullResponse) {
|
|
195
|
-
// this.sessionPlugin.addMessage(this.sessionId, { role: 'assistant', content: fullResponse });
|
|
196
|
-
// }
|
|
197
210
|
}
|
|
198
211
|
}
|
|
199
212
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foliko",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "简约的插件化 Agent 框架",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
60
60
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
61
61
|
"ai": "^6.0.146",
|
|
62
|
-
"dayjs": "^1.11.20",
|
|
63
62
|
"dotenv": "^17.3.1",
|
|
64
63
|
"gate-api": "^7.2.57",
|
|
65
64
|
"hono": "^4.12.9",
|
|
@@ -289,7 +289,8 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
// 1.5 创建主 Agent(供 Telegram 等需要绑定 Agent 的插件使用)
|
|
292
|
-
|
|
292
|
+
// 注意:即使没有 AI 配置也创建主 agent,让 memory-plugin 等能注册 prompt parts
|
|
293
|
+
if (!framework._mainAgent) {
|
|
293
294
|
const { Agent } = require('../src/core/agent')
|
|
294
295
|
const aiPlugin = framework.pluginManager.get('ai')
|
|
295
296
|
const aiClient = aiPlugin ? aiPlugin.getAIClient() : null
|
|
@@ -298,8 +299,8 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
298
299
|
framework._mainAgent = framework.createAgent({
|
|
299
300
|
name: 'MainAgent',
|
|
300
301
|
systemPrompt: '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。',
|
|
301
|
-
model: aiConfig.model,
|
|
302
|
-
provider: aiConfig.provider,
|
|
302
|
+
model: aiConfig.model || 'deepseek-chat',
|
|
303
|
+
provider: aiConfig.provider || 'deepseek',
|
|
303
304
|
apiKey: aiConfig.apiKey,
|
|
304
305
|
baseURL: aiConfig.baseURL
|
|
305
306
|
})
|
|
@@ -23,52 +23,6 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
23
23
|
this._extensions = new Map();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* 从 JSON Schema 构建 Zod Schema
|
|
28
|
-
* @param {Object} jsonSchema - JSON Schema 对象
|
|
29
|
-
* @returns {z.ZodObject}
|
|
30
|
-
*/
|
|
31
|
-
_buildZodSchema(jsonSchema) {
|
|
32
|
-
const properties = jsonSchema.properties || {};
|
|
33
|
-
const required = jsonSchema.required || [];
|
|
34
|
-
const shape = {};
|
|
35
|
-
|
|
36
|
-
for (const [name, prop] of Object.entries(properties)) {
|
|
37
|
-
let field;
|
|
38
|
-
const isRequired = required.includes(name);
|
|
39
|
-
|
|
40
|
-
switch (prop.type) {
|
|
41
|
-
case 'string':
|
|
42
|
-
field = z.string();
|
|
43
|
-
break;
|
|
44
|
-
case 'number':
|
|
45
|
-
field = z.number();
|
|
46
|
-
break;
|
|
47
|
-
case 'boolean':
|
|
48
|
-
field = z.boolean();
|
|
49
|
-
break;
|
|
50
|
-
case 'array':
|
|
51
|
-
field = z.array(z.any());
|
|
52
|
-
break;
|
|
53
|
-
case 'object':
|
|
54
|
-
field = z.object({});
|
|
55
|
-
break;
|
|
56
|
-
default:
|
|
57
|
-
field = z.any();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (prop.description) {
|
|
61
|
-
field = field.describe(prop.description);
|
|
62
|
-
}
|
|
63
|
-
if (!isRequired) {
|
|
64
|
-
field = field.optional();
|
|
65
|
-
}
|
|
66
|
-
shape[name] = field;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return z.object(shape);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
26
|
install(framework) {
|
|
73
27
|
this._framework = framework;
|
|
74
28
|
|
|
@@ -178,49 +132,20 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
178
132
|
args: z.record(z.any()).optional().describe('工具参数'),
|
|
179
133
|
}),
|
|
180
134
|
execute: async (args) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
log.info(` ext_call: plugin=${plugin}, tool=${tool}`);
|
|
184
|
-
|
|
185
|
-
const ext = this._extensions.get(plugin);
|
|
186
|
-
if (!ext) {
|
|
187
|
-
return { success: false, error: `扩展插件 '${plugin}' 不存在` };
|
|
188
|
-
}
|
|
135
|
+
const { plugin, tool, args: toolArgs = {} } = args;
|
|
136
|
+
log.info(` ext_call: plugin=${plugin}, tool=${tool}`);
|
|
189
137
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
success: false,
|
|
195
|
-
error: `扩展工具 '${tool}' 不存在。可用工具: ${availableTools || '无'}`
|
|
196
|
-
};
|
|
197
|
-
}
|
|
138
|
+
const ext = this._extensions.get(plugin);
|
|
139
|
+
if (!ext) {
|
|
140
|
+
return { success: false, error: `扩展插件 '${plugin}' 不存在` };
|
|
141
|
+
}
|
|
198
142
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
? toolDef.inputSchema
|
|
204
|
-
: this._buildZodSchema(toolDef.inputSchema);
|
|
205
|
-
schema.parse(toolArgs);
|
|
206
|
-
} catch (err) {
|
|
207
|
-
if (err instanceof z.ZodError) {
|
|
208
|
-
const fieldErrors = err.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join('; ');
|
|
209
|
-
return {
|
|
210
|
-
success: false,
|
|
211
|
-
error: `参数错误: ${fieldErrors}`,
|
|
212
|
-
inputSchema: toolDef.inputSchema,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
success: false,
|
|
217
|
-
error: `参数验证失败: ${err.message}`,
|
|
218
|
-
inputSchema: toolDef.inputSchema,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
}
|
|
143
|
+
const toolDef = ext.tools.find((t) => t.name === tool);
|
|
144
|
+
if (!toolDef) {
|
|
145
|
+
return { success: false, error: `扩展工具 '${tool}' 不存在` };
|
|
146
|
+
}
|
|
222
147
|
|
|
223
|
-
|
|
148
|
+
try {
|
|
224
149
|
// 触发扩展工具开始事件
|
|
225
150
|
framework.emit('tool:call', {
|
|
226
151
|
name: `${plugin}:${tool}`,
|
|
@@ -295,11 +220,7 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
295
220
|
|
|
296
221
|
const toolDef = ext.tools.find((t) => t.name === tool);
|
|
297
222
|
if (!toolDef) {
|
|
298
|
-
|
|
299
|
-
return {
|
|
300
|
-
success: false,
|
|
301
|
-
error: `扩展工具 '${tool}' 不存在。可用工具: ${availableTools || '无'}`
|
|
302
|
-
};
|
|
223
|
+
return { success: false, error: `扩展工具 '${tool}' 不存在` };
|
|
303
224
|
}
|
|
304
225
|
|
|
305
226
|
return {
|
|
@@ -827,9 +827,10 @@ class FileSystemPlugin extends Plugin {
|
|
|
827
827
|
timeout: z.number().optional().describe('超时时间(ms),默认 30000'),
|
|
828
828
|
proxy: z.boolean().optional().describe('是否使用代理,默认 false。访问失败时可自动设为 true 重试'),
|
|
829
829
|
toMarkdown: z.boolean().default(true).describe('是否将 HTML 响应转换为 Markdown 格式,默认 true'),
|
|
830
|
+
maxLength: z.number().optional().describe('最大返回长度(字符数),超过则截断')
|
|
830
831
|
}),
|
|
831
832
|
execute: async (args, framework) => {
|
|
832
|
-
const { url, method = 'GET', headers = {}, body, timeout = 30000, proxy = false, toMarkdown = true } = args
|
|
833
|
+
const { url, method = 'GET', headers = {}, body, timeout = 30000, proxy = false, toMarkdown = true, maxLength } = args
|
|
833
834
|
try {
|
|
834
835
|
const controller = new AbortController()
|
|
835
836
|
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
@@ -858,18 +859,27 @@ class FileSystemPlugin extends Plugin {
|
|
|
858
859
|
const isHtml = /<[a-z][\s\S]*>/i.test(data) || data.trim().startsWith('<')
|
|
859
860
|
if (isHtml) {
|
|
860
861
|
try {
|
|
862
|
+
|
|
861
863
|
const markdown = NodeHtmlMarkdown.translate(data)
|
|
864
|
+
// 限制返回长度
|
|
865
|
+
const truncatedMarkdown = maxLength && markdown.length > maxLength
|
|
866
|
+
? markdown.substring(0, maxLength) + '\n\n...(truncated)'
|
|
867
|
+
: markdown
|
|
862
868
|
return {
|
|
863
869
|
success: true,
|
|
864
870
|
status: response.status,
|
|
865
871
|
statusText: response.statusText,
|
|
866
872
|
headers: Object.fromEntries(response.headers.entries()),
|
|
867
873
|
usedProxy: proxy,
|
|
868
|
-
markdown:
|
|
874
|
+
markdown: truncatedMarkdown,
|
|
869
875
|
originalLength: markdown.length,
|
|
876
|
+
truncated: maxLength && markdown.length > maxLength
|
|
870
877
|
}
|
|
871
878
|
} catch (e) {
|
|
872
879
|
// 转换失败时返回原始 body
|
|
880
|
+
const truncatedBody = maxLength && data.length > maxLength
|
|
881
|
+
? data.substring(0, maxLength) + '\n\n...(truncated)'
|
|
882
|
+
: data
|
|
873
883
|
return {
|
|
874
884
|
success: true,
|
|
875
885
|
status: response.status,
|
|
@@ -877,8 +887,9 @@ class FileSystemPlugin extends Plugin {
|
|
|
877
887
|
headers: Object.fromEntries(response.headers.entries()),
|
|
878
888
|
usedProxy: proxy,
|
|
879
889
|
markdown: null,
|
|
880
|
-
body:
|
|
890
|
+
body: truncatedBody,
|
|
881
891
|
originalLength: data.length,
|
|
892
|
+
truncated: maxLength && data.length > maxLength,
|
|
882
893
|
markdownError: e.message
|
|
883
894
|
}
|
|
884
895
|
}
|
|
@@ -886,14 +897,18 @@ class FileSystemPlugin extends Plugin {
|
|
|
886
897
|
}
|
|
887
898
|
|
|
888
899
|
// toMarkdown 为 false 或非 HTML 内容时,返回原始内容
|
|
900
|
+
const truncatedData = maxLength && typeof data === 'string' && data.length > maxLength
|
|
901
|
+
? data.substring(0, maxLength) + '\n\n...(truncated)'
|
|
902
|
+
: data
|
|
889
903
|
return {
|
|
890
904
|
success: true,
|
|
891
905
|
status: response.status,
|
|
892
906
|
statusText: response.statusText,
|
|
893
907
|
headers: Object.fromEntries(response.headers.entries()),
|
|
894
908
|
usedProxy: proxy,
|
|
895
|
-
body:
|
|
909
|
+
body: truncatedData,
|
|
896
910
|
originalLength: typeof data === 'string' ? data.length : null,
|
|
911
|
+
truncated: maxLength && typeof data === 'string' && data.length > maxLength
|
|
897
912
|
}
|
|
898
913
|
} catch (error) {
|
|
899
914
|
return {
|
package/plugins/memory-plugin.js
CHANGED
|
@@ -9,6 +9,7 @@ const log = logger.child('Memory')
|
|
|
9
9
|
const { z } = require('zod')
|
|
10
10
|
const fs = require('fs')
|
|
11
11
|
const path = require('path')
|
|
12
|
+
const { EventEmitter } = require('events')
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* 记忆类型常量
|
|
@@ -190,8 +191,9 @@ function _extractJSON(text) {
|
|
|
190
191
|
/**
|
|
191
192
|
* MemoryStore - 双层存储(内存 + 文件)
|
|
192
193
|
*/
|
|
193
|
-
class MemoryStore {
|
|
194
|
+
class MemoryStore extends EventEmitter {
|
|
194
195
|
constructor(baseDir) {
|
|
196
|
+
super()
|
|
195
197
|
this._baseDir = path.resolve(process.cwd(), baseDir)
|
|
196
198
|
this._memory = new Map() // memoryId -> memory object
|
|
197
199
|
this._indexByType = new Map() // type -> Set of memoryIds
|
|
@@ -353,6 +355,10 @@ class MemoryStore {
|
|
|
353
355
|
this._fileIndex.set(id, filePath)
|
|
354
356
|
|
|
355
357
|
log.debug(`Added memory: ${id} (${newMemory.type})`)
|
|
358
|
+
|
|
359
|
+
// 触发变化事件
|
|
360
|
+
this.emit('change', { action: 'add', memory: newMemory })
|
|
361
|
+
|
|
356
362
|
return newMemory
|
|
357
363
|
}
|
|
358
364
|
|
|
@@ -393,6 +399,10 @@ class MemoryStore {
|
|
|
393
399
|
this._fileIndex.set(id, filePath)
|
|
394
400
|
|
|
395
401
|
log.debug(`Updated memory: ${id}`)
|
|
402
|
+
|
|
403
|
+
// 触发变化事件
|
|
404
|
+
this.emit('change', { action: 'update', memory })
|
|
405
|
+
|
|
396
406
|
return memory
|
|
397
407
|
}
|
|
398
408
|
|
|
@@ -415,6 +425,10 @@ class MemoryStore {
|
|
|
415
425
|
this._fileIndex.delete(id)
|
|
416
426
|
|
|
417
427
|
log.debug(`Deleted memory: ${id}`)
|
|
428
|
+
|
|
429
|
+
// 触发变化事件
|
|
430
|
+
this.emit('change', { action: 'delete', memory })
|
|
431
|
+
|
|
418
432
|
return true
|
|
419
433
|
}
|
|
420
434
|
|
|
@@ -549,6 +563,9 @@ class MemoryPlugin extends Plugin {
|
|
|
549
563
|
// 注册 memory-context 到系统提示(优先级 350)
|
|
550
564
|
this._registerMemoryContext(framework)
|
|
551
565
|
|
|
566
|
+
// 监听记忆变化,动态刷新系统提示词
|
|
567
|
+
this._setupDynamicRefresh(framework)
|
|
568
|
+
|
|
552
569
|
log.info('Memory plugin started')
|
|
553
570
|
return this
|
|
554
571
|
}
|
|
@@ -899,21 +916,34 @@ ${typeof assistantResponse === 'string' ? assistantResponse : JSON.stringify(ass
|
|
|
899
916
|
* 注册 memory-context 到系统提示
|
|
900
917
|
*/
|
|
901
918
|
_registerMemoryContext(framework) {
|
|
902
|
-
// 获取主 agent 并注册 memory-context 部分
|
|
903
919
|
const mainAgent = framework._mainAgent
|
|
904
920
|
if (mainAgent) {
|
|
905
921
|
mainAgent.registerPromptPart('memory-context', 350, () => {
|
|
906
922
|
return this._buildMemoryContext()
|
|
907
923
|
})
|
|
924
|
+
mainAgent._refreshContext()
|
|
908
925
|
}
|
|
909
926
|
|
|
910
|
-
// 也监听 framework:ready 事件,以防主 agent 还没创建
|
|
911
927
|
framework.on('framework:ready', () => {
|
|
912
928
|
const agent = framework._mainAgent
|
|
913
929
|
if (agent) {
|
|
914
930
|
agent.registerPromptPart('memory-context', 350, () => {
|
|
915
931
|
return this._buildMemoryContext()
|
|
916
932
|
})
|
|
933
|
+
agent._refreshContext()
|
|
934
|
+
}
|
|
935
|
+
})
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* 设置动态刷新 - 记忆变化时自动刷新系统提示词
|
|
940
|
+
*/
|
|
941
|
+
_setupDynamicRefresh(framework) {
|
|
942
|
+
this._store.on('change', ({ action, memory }) => {
|
|
943
|
+
const mainAgent = framework._mainAgent
|
|
944
|
+
if (mainAgent) {
|
|
945
|
+
mainAgent.invalidatePromptPart('memory-context')
|
|
946
|
+
mainAgent._refreshContext()
|
|
917
947
|
}
|
|
918
948
|
})
|
|
919
949
|
}
|
|
@@ -923,7 +953,6 @@ ${typeof assistantResponse === 'string' ? assistantResponse : JSON.stringify(ass
|
|
|
923
953
|
*/
|
|
924
954
|
_buildMemoryContext() {
|
|
925
955
|
try {
|
|
926
|
-
// 获取所有 user 类型记忆作为用户偏好
|
|
927
956
|
const userMemories = this._store.listByType(MEMORY_TYPES.USER, 10)
|
|
928
957
|
const projectMemories = this._store.listByType(MEMORY_TYPES.PROJECT, 5)
|
|
929
958
|
|
|
@@ -9,7 +9,6 @@ const { Plugin } = require('../src/core/plugin-base')
|
|
|
9
9
|
const { logger } = require('../src/utils/logger')
|
|
10
10
|
const log = logger.child('SubAgent')
|
|
11
11
|
const { z } = require('zod')
|
|
12
|
-
const { cleanResponse } = require('../src/utils')
|
|
13
12
|
const { Agent } = require('../src/core/agent')
|
|
14
13
|
|
|
15
14
|
class SubAgentPlugin extends Plugin {
|
|
@@ -461,28 +460,17 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
461
460
|
if (!plugin) {
|
|
462
461
|
return { success: false, error: `SubAgent ${args.agentName} not found` }
|
|
463
462
|
}
|
|
463
|
+
|
|
464
464
|
try {
|
|
465
465
|
const result = await plugin.chat(args.task)
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
// 清理 thinking 标签
|
|
473
|
-
if (typeof output === 'string') {
|
|
474
|
-
output = cleanResponse(output)
|
|
475
|
-
}
|
|
476
|
-
if (result.success !== false) {
|
|
477
|
-
// 确保返回的是字符串
|
|
478
|
-
if (typeof output === 'string') {
|
|
479
|
-
return output
|
|
480
|
-
}
|
|
481
|
-
return JSON.stringify(output, null, 2)
|
|
466
|
+
return {
|
|
467
|
+
success: true,
|
|
468
|
+
agent: args.agentName,
|
|
469
|
+
result: result.message || result,
|
|
470
|
+
success: result.success !== false
|
|
482
471
|
}
|
|
483
|
-
return { error: typeof output === 'string' ? output : JSON.stringify(output) }
|
|
484
472
|
} catch (err) {
|
|
485
|
-
return { error: err.message }
|
|
473
|
+
return { success: false, error: err.message }
|
|
486
474
|
}
|
|
487
475
|
}
|
|
488
476
|
})
|
|
@@ -535,28 +523,17 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
535
523
|
if (!plugin) {
|
|
536
524
|
return { success: false, error: `SubAgent ${args.agentName} not found` }
|
|
537
525
|
}
|
|
526
|
+
|
|
538
527
|
try {
|
|
539
528
|
const result = await plugin.chat(args.task)
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
// 清理 thinking 标签
|
|
547
|
-
if (typeof output === 'string') {
|
|
548
|
-
output = cleanResponse(output)
|
|
549
|
-
}
|
|
550
|
-
if (result.success !== false) {
|
|
551
|
-
// 确保返回的是字符串
|
|
552
|
-
if (typeof output === 'string') {
|
|
553
|
-
return output
|
|
554
|
-
}
|
|
555
|
-
return JSON.stringify(output, null, 2)
|
|
529
|
+
return {
|
|
530
|
+
success: true,
|
|
531
|
+
agent: args.agentName,
|
|
532
|
+
result: result.message || result,
|
|
533
|
+
success: result.success !== false
|
|
556
534
|
}
|
|
557
|
-
return { error: typeof output === 'string' ? output : JSON.stringify(output) }
|
|
558
535
|
} catch (err) {
|
|
559
|
-
return { error: err.message }
|
|
536
|
+
return { success: false, error: err.message }
|
|
560
537
|
}
|
|
561
538
|
}
|
|
562
539
|
})
|