foliko 1.1.13 → 1.1.14

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 (246) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/poster-expert.md +135 -196
  36. package/.agent/agents/python-developer.md +60 -0
  37. package/.agent/agents/scheduler.md +59 -0
  38. package/.agent/agents/web-developer.md +45 -0
  39. package/.agent/data/default.json +404 -9
  40. package/.agent/data/plugins-state.json +172 -173
  41. package/.agent/data/puppeteer-sessions/undefined.json +6 -0
  42. package/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
  43. package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
  44. package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
  45. package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
  46. package/.agent/mcp_config.json +21 -0
  47. package/.agent/memory/feedback/mnygjgox-ualjip.md +11 -0
  48. package/.agent/memory/project/mnqx54u5-loqtoe.md +9 -0
  49. package/.agent/memory/project/mnqx84cv-mx6dmd.md +9 -0
  50. package/.agent/memory/project/mnsacuyr-hgtk5n.md +20 -0
  51. package/.agent/memory/project/mnu5hy2x-bjsg7u.md +9 -0
  52. package/.agent/memory/project/mny28ot4-8qe9au.md +9 -0
  53. package/.agent/memory/reference/mnre3cww-penbo1.md +9 -0
  54. package/.agent/memory/reference/mns9wn48-luerua.md +14 -0
  55. package/.agent/memory/reference/mns9yz5c-thc2s0.md +16 -0
  56. package/.agent/memory/reference/mnsfy4um-910f1o.md +23 -0
  57. package/.agent/memory/reference/mnsg37dp-lmfj18.md +32 -0
  58. package/.agent/memory/reference/mnsll60q-0j911u.md +36 -0
  59. package/.agent/memory/reference/mnsmlb5y-nej31u.md +16 -0
  60. package/.agent/memory/reference/mnssle72-yrot96.md +9 -0
  61. package/.agent/memory/reference/mnygj8nb-bjthmc.md +20 -0
  62. package/.agent/memory/user/mnsfuon6-l416q1.md +21 -0
  63. package/.agent/memory/user/mnsg9kut-95m7rf.md +20 -0
  64. package/.agent/memory/user/mnu2eo1v-yy6fhe.md +9 -0
  65. package/.agent/memory/user/mnu2etuo-8u8jk8.md +9 -0
  66. package/.agent/memory/user/mnx0rk6g-gsznjj.md +9 -0
  67. package/.agent/memory/user/mnyf1riz-4yo5yz.md +9 -0
  68. package/.agent/plugins/puppeteer-plugin/README.md +147 -0
  69. package/.agent/plugins/puppeteer-plugin/index.js +1422 -0
  70. package/.agent/plugins/puppeteer-plugin/package.json +9 -0
  71. package/.agent/plugins.json +5 -11
  72. package/.agent/rules/GEMINI.md +273 -0
  73. package/.agent/rules/allow-rule.md +77 -0
  74. package/.agent/rules/log-rule.md +83 -0
  75. package/.agent/rules/security-rule.md +93 -0
  76. package/.agent/scripts/auto_preview.py +148 -0
  77. package/.agent/scripts/checklist.py +217 -0
  78. package/.agent/scripts/session_manager.py +120 -0
  79. package/.agent/scripts/verify_all.py +327 -0
  80. package/.agent/sessions/cli_default.json +11 -641
  81. package/.agent/skills/api-patterns/SKILL.md +81 -0
  82. package/.agent/skills/api-patterns/api-style.md +42 -0
  83. package/.agent/skills/api-patterns/auth.md +24 -0
  84. package/.agent/skills/api-patterns/documentation.md +26 -0
  85. package/.agent/skills/api-patterns/graphql.md +41 -0
  86. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  87. package/.agent/skills/api-patterns/response.md +37 -0
  88. package/.agent/skills/api-patterns/rest.md +40 -0
  89. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  90. package/.agent/skills/api-patterns/security-testing.md +122 -0
  91. package/.agent/skills/api-patterns/trpc.md +41 -0
  92. package/.agent/skills/api-patterns/versioning.md +22 -0
  93. package/.agent/skills/app-builder/SKILL.md +75 -0
  94. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  95. package/.agent/skills/app-builder/feature-building.md +53 -0
  96. package/.agent/skills/app-builder/project-detection.md +34 -0
  97. package/.agent/skills/app-builder/scaffolding.md +118 -0
  98. package/.agent/skills/app-builder/tech-stack.md +40 -0
  99. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  100. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  101. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  102. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  103. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  104. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  105. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  106. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  107. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  108. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  109. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  110. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  111. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  112. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  113. package/.agent/skills/architecture/SKILL.md +55 -0
  114. package/.agent/skills/architecture/context-discovery.md +43 -0
  115. package/.agent/skills/architecture/examples.md +94 -0
  116. package/.agent/skills/architecture/pattern-selection.md +68 -0
  117. package/.agent/skills/architecture/patterns-reference.md +50 -0
  118. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  119. package/.agent/skills/clean-code/SKILL.md +201 -0
  120. package/.agent/skills/doc.md +177 -0
  121. package/.agent/skills/frontend-design/SKILL.md +418 -0
  122. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  123. package/.agent/skills/frontend-design/color-system.md +311 -0
  124. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  125. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  126. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  127. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  128. package/.agent/skills/frontend-design/typography-system.md +345 -0
  129. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  130. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  131. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  132. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  133. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  134. package/.agent/skills/poster-design/SKILL.md +385 -0
  135. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  136. package/.agent/workflows/brainstorm.md +113 -0
  137. package/.agent/workflows/create.md +59 -0
  138. package/.agent/workflows/debug.md +103 -0
  139. package/.agent/workflows/deploy.md +176 -0
  140. package/.agent/workflows/enhance.md +63 -0
  141. package/.agent/workflows/orchestrate.md +237 -0
  142. package/.agent/workflows/plan.md +89 -0
  143. package/.agent/workflows/preview.md +81 -0
  144. package/.agent/workflows/simple-test.md +42 -0
  145. package/.agent/workflows/status.md +86 -0
  146. package/.agent/workflows/structured-orchestrate.md +180 -0
  147. package/.agent/workflows/test.md +144 -0
  148. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  149. package/.claude/settings.local.json +23 -1
  150. package/.env.example +56 -56
  151. package/README.md +441 -441
  152. package/cli/src/commands/chat.js +9 -15
  153. package/cli/src/ui/chat-ui.js +41 -71
  154. package/package.json +1 -1
  155. package/plugins/default-plugins.js +5 -5
  156. package/plugins/file-system-plugin.js +1 -1
  157. package/plugins/memory-plugin.js +12 -12
  158. package/plugins/plugin-manager-plugin.js +1 -0
  159. package/plugins/subagent-plugin.js +55 -1
  160. package/plugins/telegram-plugin.js +9 -6
  161. package/plugins/weixin-plugin.js +50 -34
  162. package/skills/find-skills/AGENTS.md +162 -162
  163. package/skills/find-skills/SKILL.md +133 -133
  164. package/src/core/agent-chat.js +460 -1612
  165. package/src/core/agent.js +53 -134
  166. package/src/core/chat-session.js +423 -0
  167. package/src/core/context-compressor.js +473 -0
  168. package/src/core/context-manager.js +0 -48
  169. package/src/core/framework.js +95 -68
  170. package/src/core/index.js +11 -0
  171. package/src/core/notification-manager.js +125 -0
  172. package/src/core/subagent.js +295 -0
  173. package/src/core/token-counter.js +190 -0
  174. package/src/core/tool-executor.js +270 -0
  175. package/src/executors/mcp-executor.js +14 -1
  176. package/system.md +312 -2373
  177. package/.agent/agents/code-assistant.json +0 -17
  178. package/.agent/agents/email-assistant.json +0 -14
  179. package/.agent/agents/file-assistant.json +0 -18
  180. package/.agent/agents/orchestrator-demo.md +0 -53
  181. package/.agent/agents/orchestrator.json +0 -7
  182. package/.agent/agents/system-assistant.json +0 -15
  183. package/.agent/agents/web-assistant.json +0 -12
  184. package/.agent/data/email/processed-emails.json +0 -1
  185. package/.agent/data/scheduler/tasks.json +0 -1
  186. package/.agent/data/web/web-config.json +0 -5
  187. package/.agent/memory/feedback/mnv3nu27-3o15pf.md +0 -9
  188. package/.agent/memory/feedback/mnv3o078-b959yj.md +0 -9
  189. package/.agent/memory/feedback/mnv3o6ej-u0fif5.md +0 -9
  190. package/.agent/memory/feedback/mnv3obgl-bkkjoj.md +0 -9
  191. package/.agent/memory/feedback/mnv4a3js-dv6onx.md +0 -9
  192. package/.agent/memory/feedback/mnv4aacm-sxxowp.md +0 -9
  193. package/.agent/memory/feedback/mnv4ahto-w40ffm.md +0 -9
  194. package/.agent/memory/feedback/mnv4anvp-3cs06y.md +0 -9
  195. package/.agent/memory/feedback/mnvzgvtd-0o2900.md +0 -9
  196. package/.agent/memory/feedback/mnvzhajn-swbx61.md +0 -15
  197. package/.agent/memory/feedback/mnvzhgsp-p5vog3.md +0 -9
  198. package/.agent/memory/feedback/mnvzho0c-fgql7q.md +0 -14
  199. package/.agent/memory/feedback/mnvzhtzq-ufr5at.md +0 -9
  200. package/.agent/memory/feedback/mnvzhyb3-9byq2z.md +0 -9
  201. package/.agent/memory/feedback/mnvzi7hp-hyeafp.md +0 -9
  202. package/.agent/memory/feedback/mnvzibph-z7rwp5.md +0 -9
  203. package/.agent/memory/feedback/mnvzilys-7h176w.md +0 -14
  204. package/.agent/memory/feedback/mnvziuh5-zjshci.md +0 -9
  205. package/.agent/memory/feedback/mnw07wde-6zqsc8.md +0 -9
  206. package/.agent/memory/feedback/mnw084bp-j0ba2a.md +0 -9
  207. package/.agent/memory/user/mnv3n62r-y0h79j.md +0 -21
  208. package/.agent/memory/user/mnv3n9yf-ead4g8.md +0 -13
  209. package/.agent/memory/user/mnv3ne3j-82tq1k.md +0 -19
  210. package/.agent/memory/user/mnv3nhgm-g2s2us.md +0 -11
  211. package/.agent/memory/user/mnv3nl9u-ejd998.md +0 -16
  212. package/.agent/memory/user/mnv3nofp-ya5szl.md +0 -10
  213. package/.agent/memory/user/mnv49qne-bhk0ki.md +0 -9
  214. package/.agent/memory/user/mnv49w3y-rzr8ju.md +0 -13
  215. package/.agent/package.json +0 -8
  216. package/.agent/plugins/__pycache__/file_writer.cpython-312.pyc +0 -0
  217. package/.agent/plugins/daytona/README.md +0 -89
  218. package/.agent/plugins/daytona/index.js +0 -377
  219. package/.agent/plugins/daytona/package.json +0 -12
  220. package/.agent/plugins/marknative/README.md +0 -134
  221. package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
  222. package/.agent/plugins/marknative/fonts.zip +0 -0
  223. package/.agent/plugins/marknative/index.js +0 -256
  224. package/.agent/plugins/marknative/package.json +0 -12
  225. package/.agent/plugins/system-info/index.js +0 -387
  226. package/.agent/plugins/system-info/package.json +0 -4
  227. package/.agent/plugins/system-info/test.js +0 -40
  228. package/.agent/plugins/test-plugin.py +0 -123
  229. package/.agent/plugins/test_nested_plugin.py +0 -85
  230. package/.agent/python-scripts/test_sample.py +0 -24
  231. package/.agent/sessions/test.json +0 -16
  232. package/.agent/skills/agent-browser/SKILL.md +0 -311
  233. package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
  234. package/.agent/skills/sysinfo/SKILL.md +0 -38
  235. package/.agent/skills/sysinfo/system-info.sh +0 -130
  236. package/.agent/skills/workflow/SKILL.md +0 -324
  237. package/.agent/test-agent.js +0 -35
  238. package/.agent/weixin.json +0 -6
  239. package/.agent/workflows/email-digest.json +0 -50
  240. package/.agent/workflows/file-backup.json +0 -21
  241. package/.agent/workflows/get-ip-notify.json +0 -32
  242. package/.agent/workflows/news-aggregator.json +0 -93
  243. package/.agent/workflows/news-dashboard-v2.json +0 -94
  244. package/.agent/workflows/notification-batch.json +0 -32
  245. package/plugins/python-plugin-loader.js.bak +0 -856
  246. package/src/core/agent-context.js +0 -188
package/src/core/agent.js CHANGED
@@ -6,6 +6,7 @@
6
6
  const { EventEmitter } = require('../utils/event-emitter');
7
7
  const { AgentChatHandler } = require('./agent-chat');
8
8
  const { SystemPromptBuilder } = require('./system-prompt-builder');
9
+ const { NotificationManager } = require('./notification-manager');
9
10
  const { zodSchemaToMarkdown, zodSchemaToTable } = require('@chnak/zod-to-markdown');
10
11
  const { zodSchema } = require('ai');
11
12
  const os = require('os');
@@ -120,6 +121,9 @@ class Agent extends EventEmitter {
120
121
  // 处理后的 system prompt (带上下文)
121
122
  this.systemPrompt = this._buildSystemPrompt();
122
123
 
124
+ // 通知管理器
125
+ this._notificationManager = new NotificationManager(framework);
126
+
123
127
  // 初始化聊天处理器
124
128
  this._initChatHandler();
125
129
 
@@ -246,21 +250,26 @@ class Agent extends EventEmitter {
246
250
  * 构建工具描述(直接调用的工具)
247
251
  */
248
252
  _buildToolsDescription() {
249
- if (this._tools.size === 0) {
253
+ const tools = this.framework.getTools();
254
+ if (!tools || tools.length === 0) {
250
255
  return '';
251
256
  }
252
257
 
253
258
  const directTools = [];
254
259
 
255
- for (const [name, tool] of this._tools) {
260
+ for (const tool of tools) {
256
261
  if (!tool.description) continue;
257
262
 
258
263
  // MCP 和 ext 工具不在这里显示,它们通过专门的描述部分提供
259
- if (name.startsWith('mcp_') || name.startsWith('ext_') || name.startsWith('workflow_')) {
264
+ if (
265
+ tool.name.startsWith('mcp_') ||
266
+ tool.name.startsWith('ext_') ||
267
+ tool.name.startsWith('workflow_')
268
+ ) {
260
269
  continue;
261
270
  }
262
271
 
263
- directTools.push({ name, tool });
272
+ directTools.push({ name: tool.name, tool });
264
273
  }
265
274
 
266
275
  if (directTools.length === 0) {
@@ -610,45 +619,7 @@ class Agent extends EventEmitter {
610
619
  return '';
611
620
  }
612
621
 
613
- // 使用数组收集 + join 模式优化字符串拼接
614
- const lines = ['## 子 Agent 匹配表', ''];
615
- lines.push('');
616
- lines.push('> **提示**:根据任务类型选择最匹配的子 Agent 处理');
617
- lines.push('');
618
-
619
- // 动态从配置文件读取每个子Agent的核心能力
620
- for (const plugin of allSubAgents) {
621
- const name = plugin.name;
622
- const role = plugin.role;
623
- const goal = plugin.description || '';
624
-
625
- // 优先使用 SubAgentConfigManager 获取详细信息
626
- const config = this.framework._subAgentConfigManager?.get(name);
627
- if (config) {
628
- const agentDesc = config.getDescription();
629
- const skills = config.getSkills();
630
- let info = agentDesc || role || goal || '子代理';
631
- if (skills && skills.length > 0) {
632
- info += ` (技能: ${skills.join(', ')})`;
633
- }
634
- lines.push(`- **${name}**:${info}`);
635
- } else {
636
- // 回退到旧逻辑
637
- lines.push(`- **${name}**:${role || goal || '子代理'}`);
638
- }
639
- }
640
-
641
- // 通用规则
642
- lines.push('');
643
- lines.push('### 子 Agent 调用规则');
644
- lines.push('');
645
- lines.push('> **重要**:必须严格遵守以下规则');
646
- lines.push('');
647
- lines.push('1. 根据上述「子 Agent 匹配表」,将任务委托给最匹配的子 Agent 处理');
648
- lines.push('2. 使用 `subagent_call` 工具并指定 `agentName` 来委托任务');
649
- lines.push('3. 只有当没有匹配的子 Agent 时,才直接调用工具');
650
-
651
- return lines.join('\n');
622
+ return subAgentManager._buildDescription();
652
623
  }
653
624
 
654
625
  /**
@@ -924,35 +895,38 @@ class Agent extends EventEmitter {
924
895
  }
925
896
 
926
897
  /**
927
- * 注册工具到 Agent
898
+ * 注册工具到 Framework(统一入口)
928
899
  */
929
900
  registerTool(tool) {
930
- this._tools.set(tool.name, tool);
931
- this._invalidateSystemPromptCache();
901
+ // 注册到 framework(统一管理)
902
+ this.framework.registerTool(tool);
903
+ // 注册到 chatHandler
932
904
  if (this._chatHandler) {
933
905
  this._chatHandler.registerTool(tool);
934
906
  }
907
+ this._invalidateSystemPromptCache();
935
908
  this._refreshContext();
936
909
  return this;
937
910
  }
938
911
 
939
912
  /**
940
- * 获取已注册工具
913
+ * 获取已注册工具(从 framework 获取)
941
914
  */
942
915
  getTools() {
943
- return Array.from(this._tools.values());
916
+ return this.framework.getTools();
944
917
  }
945
918
 
946
919
  /**
947
- * 同步框架中的工具到 Agent
920
+ * 同步框架中的工具到 ChatHandler
948
921
  * @private
949
922
  */
950
923
  _syncTools() {
951
- if (this.framework.toolRegistry.size() > 0) {
952
- for (const tool of this.framework.getTools()) {
953
- if (!this._tools.has(tool.name)) {
954
- this.registerTool(tool);
955
- }
924
+ // framework 获取工具并注册到 chatHandler
925
+ const tools = this.framework.getTools();
926
+ for (const tool of tools) {
927
+ // 直接注册到 chatHandler(registerTool 是幂等的)
928
+ if (this._chatHandler) {
929
+ this._chatHandler.registerTool(tool);
956
930
  }
957
931
  }
958
932
  }
@@ -988,74 +962,6 @@ class Agent extends EventEmitter {
988
962
  return this._subAgents;
989
963
  }
990
964
 
991
- /**
992
- * 获取待处理的调度通知并清除(下次不再重复显示)
993
- */
994
- _getAndClearSchedulerNotifications() {
995
- try {
996
- const scheduler = this.framework.pluginManager.get('scheduler');
997
- if (scheduler && scheduler.instance && scheduler.instance.getPendingNotifications) {
998
- const results = scheduler.instance.getPendingNotifications();
999
- if (results.length > 0) {
1000
- // 使用常量替代硬编码数字
1001
- const notifications = results.slice(-AGENT_CONFIG.MAX_NOTIFICATIONS).reverse();
1002
- // 清除已发送的通知
1003
- if (scheduler.instance.clearDeliveredNotifications) {
1004
- scheduler.instance.clearDeliveredNotifications(notifications.length);
1005
- }
1006
- return notifications;
1007
- }
1008
- }
1009
- } catch (err) {
1010
- logger.warn('Agent', '获取调度通知失败', err.message);
1011
- }
1012
- return [];
1013
- }
1014
-
1015
- /**
1016
- * 获取待处理的思考结果并清除
1017
- */
1018
- _getAndClearThinkNotifications() {
1019
- try {
1020
- const think = this.framework.pluginManager.get('think');
1021
- if (think && think.instance && think.instance.getPendingThoughts) {
1022
- const thoughts = think.instance.getPendingThoughts();
1023
- if (thoughts.length > 0) {
1024
- // 使用常量替代硬编码数字
1025
- return thoughts.slice(-AGENT_CONFIG.MAX_NOTIFICATIONS).reverse();
1026
- }
1027
- }
1028
- } catch (err) {
1029
- logger.warn('Agent', '获取思考通知失败', err.message);
1030
- }
1031
- return [];
1032
- }
1033
-
1034
- /**
1035
- * 获取所有待处理的系统通知(调度 + 思考)
1036
- */
1037
- _getAllPendingNotifications() {
1038
- const notifications = [];
1039
-
1040
- // 调度通知
1041
- const schedulerNotifs = this._getAndClearSchedulerNotifications();
1042
- for (const n of schedulerNotifs) {
1043
- notifications.push(
1044
- `【定时任务通知】\n任务: ${n.taskName || n.taskId}\n执行时间: ${n.executedAt}\n结果: ${n.result || n.action || '执行完成'}`
1045
- );
1046
- }
1047
-
1048
- // 思考通知
1049
- const thinkNotifs = this._getAndClearThinkNotifications();
1050
- for (const t of thinkNotifs) {
1051
- notifications.push(
1052
- `【主动思考】\n模式: ${t.mode}\n主题: ${t.topic}\n结果: ${t.result || '思考完成'}`
1053
- );
1054
- }
1055
-
1056
- return notifications;
1057
- }
1058
-
1059
965
  /**
1060
966
  * 发送消息
1061
967
  */
@@ -1068,12 +974,8 @@ class Agent extends EventEmitter {
1068
974
  this.emit('status', { status: 'busy' });
1069
975
 
1070
976
  try {
1071
- // 检查是否有待处理的系统通知(调度 + 思考)
1072
- const notifications = this._getAllPendingNotifications();
1073
- let enhancedMessage = message;
1074
- if (notifications.length > 0) {
1075
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
1076
- }
977
+ // 使用 NotificationManager 增强消息
978
+ const enhancedMessage = this._notificationManager.enhanceMessage(message);
1077
979
 
1078
980
  // 子agent跳过工具同步,使用createSubAgent时已配置的工具
1079
981
  if (!this._skipSyncTools) {
@@ -1131,12 +1033,8 @@ class Agent extends EventEmitter {
1131
1033
  this.emit('status', { status: 'busy' });
1132
1034
 
1133
1035
  try {
1134
- // 检查是否有待处理的系统通知(调度 + 思考)
1135
- const notifications = this._getAllPendingNotifications();
1136
- let enhancedMessage = message;
1137
- if (notifications.length > 0) {
1138
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
1139
- }
1036
+ // 使用 NotificationManager 增强消息
1037
+ const enhancedMessage = this._notificationManager.enhanceMessage(message);
1140
1038
 
1141
1039
  // 子agent跳过工具同步,使用createSubAgent时已配置的工具
1142
1040
  if (!this._skipSyncTools) {
@@ -1166,6 +1064,27 @@ class Agent extends EventEmitter {
1166
1064
  return this._chatHandler.sendMessage(message, options);
1167
1065
  }
1168
1066
 
1067
+ /**
1068
+ * 流式发送消息(带队列,支持实时yield)
1069
+ */
1070
+ async *sendMessageStream(message, options = {}) {
1071
+ yield* this._chatHandler.sendMessageStream(message, options);
1072
+ }
1073
+
1074
+ /**
1075
+ * 批量发送消息
1076
+ */
1077
+ async sendBatch(messages, options = {}) {
1078
+ return this._chatHandler.sendBatch(messages, options);
1079
+ }
1080
+
1081
+ /**
1082
+ * 取消会话的所有请求
1083
+ */
1084
+ cancelSession(sessionId) {
1085
+ return this._chatHandler.cancelSession(sessionId);
1086
+ }
1087
+
1169
1088
  /**
1170
1089
  * 设置元数据
1171
1090
  */
@@ -0,0 +1,423 @@
1
+ /**
2
+ * ChatSession - 会话管理器
3
+ *
4
+ * 职责:
5
+ * 1. 管理 Per-Session 的消息存储
6
+ * 2. 会话消息历史加载/保存
7
+ * 3. 会话消息队列管理
8
+ * 4. SessionScope 事件作用域
9
+ */
10
+
11
+ const { EventEmitter } = require('../utils/event-emitter');
12
+ const { ChatQueueManager } = require('../utils/chat-queue');
13
+ const { logger } = require('../utils/logger');
14
+
15
+ /**
16
+ * Session 作用域的事件监听器
17
+ * 自动过滤只属于特定 sessionId 的事件
18
+ */
19
+ class SessionScope extends EventEmitter {
20
+ /**
21
+ * @param {ChatSession} session - ChatSession 实例
22
+ * @param {string} sessionId - Session ID
23
+ */
24
+ constructor(session, sessionId) {
25
+ super();
26
+ this.session = session;
27
+ this.sessionId = sessionId;
28
+ this._handlers = new Set();
29
+ }
30
+
31
+ /**
32
+ * 注册事件监听器(自动过滤 sessionId)
33
+ * @param {string} event - 事件名
34
+ * @param {Function} handler - 处理函数
35
+ * @returns {this}
36
+ */
37
+ on(event, handler) {
38
+ const wrapped = (data) => {
39
+ if (data && data.sessionId !== this.sessionId) return;
40
+ handler(data);
41
+ };
42
+ this._handlers.add({ event, wrapped });
43
+ this.session.on(event, wrapped);
44
+ return this;
45
+ }
46
+
47
+ /**
48
+ * 注册一次性事件监听器
49
+ */
50
+ once(event, handler) {
51
+ const wrapped = (data) => {
52
+ if (data && data.sessionId !== this.sessionId) return;
53
+ handler(data);
54
+ };
55
+ this._handlers.add({ event, wrapped });
56
+ this.session.once(event, wrapped);
57
+ return this;
58
+ }
59
+
60
+ /**
61
+ * 移除事件监听器
62
+ */
63
+ off(event, handler) {
64
+ const toRemove = [];
65
+ for (const item of this._handlers) {
66
+ if (item.event === event && item.handler === handler) {
67
+ this.session.off(event, item.wrapped);
68
+ toRemove.push(item);
69
+ }
70
+ }
71
+ for (const item of toRemove) {
72
+ this._handlers.delete(item);
73
+ }
74
+ return this;
75
+ }
76
+
77
+ /**
78
+ * 移除所有这个 scope 注册的监听器
79
+ */
80
+ removeAllListeners() {
81
+ for (const { event, wrapped } of this._handlers) {
82
+ this.session.off(event, wrapped);
83
+ }
84
+ this._handlers.clear();
85
+ return this;
86
+ }
87
+
88
+ /**
89
+ * 获取当前 sessionId
90
+ */
91
+ getSessionId() {
92
+ return this.sessionId;
93
+ }
94
+ }
95
+
96
+ class ChatSession extends EventEmitter {
97
+ /**
98
+ * @param {Object} config - 配置
99
+ * @param {Function} [config.messageProcessor] - 消息处理器函数 (sessionId, message, options) => Promise
100
+ */
101
+ constructor(config = {}) {
102
+ super();
103
+
104
+ this.config = config;
105
+ this.agent = config.agent;
106
+
107
+ // 消息处理器
108
+ this._messageProcessor = config.messageProcessor;
109
+
110
+ // Session 消息存储 Map: sessionId -> { messages: [], historyLoaded: false, compressionState: {} }
111
+ this._sessionMessageStores = new Map();
112
+
113
+ // Session 队列: sessionId -> Queue of {message, options, resolve, reject}
114
+ this._sessionQueues = new Map();
115
+ this._processingSessions = new Set();
116
+
117
+ // Session 事件作用域 Map: sessionId -> Set<{event, handler}>
118
+ this._sessionScopes = new Map();
119
+
120
+ // 队列管理器
121
+ this.queueManager = new ChatQueueManager({
122
+ maxConcurrent: config.maxConcurrent || 1,
123
+ retryAttempts: config.retryAttempts || 3,
124
+ retryDelay: config.retryDelay || 1000,
125
+ });
126
+
127
+ this._setupQueueEvents();
128
+ }
129
+
130
+ /**
131
+ * 设置消息处理器
132
+ * @param {Function} processor - (sessionId, message, options) => Promise
133
+ */
134
+ setMessageProcessor(processor) {
135
+ this._messageProcessor = processor;
136
+ }
137
+
138
+ /**
139
+ * 设置队列事件转发
140
+ * @private
141
+ */
142
+ _setupQueueEvents() {
143
+ const events = [
144
+ 'queue:added',
145
+ 'queue:processing',
146
+ 'queue:completed',
147
+ 'queue:failed',
148
+ 'queue:retry',
149
+ 'queue:empty',
150
+ 'queue:cleared',
151
+ 'queue:session-removed',
152
+ 'stream:chunk',
153
+ ];
154
+
155
+ events.forEach((eventName) => {
156
+ this.queueManager.on(eventName, (data) => {
157
+ this.emit(eventName, data);
158
+ });
159
+ });
160
+ }
161
+
162
+ /**
163
+ * 获取或创建 SessionScope
164
+ * @param {string} sessionId - Session ID
165
+ * @returns {SessionScope}
166
+ */
167
+ createSessionScope(sessionId) {
168
+ return new SessionScope(this, sessionId);
169
+ }
170
+
171
+ /**
172
+ * 获取会话消息存储
173
+ * @param {string} sessionId - Session ID
174
+ * @returns {Object} messageStore
175
+ */
176
+ getSessionMessageStore(sessionId) {
177
+ if (!sessionId) {
178
+ sessionId = 'default';
179
+ }
180
+
181
+ if (!this._sessionMessageStores.has(sessionId)) {
182
+ const store = {
183
+ messages: [],
184
+ historyLoaded: false,
185
+ usage: null,
186
+ compressionState: {
187
+ count: 0,
188
+ lastCompressedAt: null,
189
+ lastTokenCount: 0,
190
+ pendingCompression: false,
191
+ },
192
+ save: () => {
193
+ this.saveHistory(sessionId, store.messages);
194
+ },
195
+ };
196
+ this._sessionMessageStores.set(sessionId, store);
197
+ }
198
+
199
+ return this._sessionMessageStores.get(sessionId);
200
+ }
201
+
202
+ /**
203
+ * 加载会话历史
204
+ * @param {string} sessionId - Session ID
205
+ * @returns {Array} 消息数组
206
+ */
207
+ loadHistory(sessionId) {
208
+ if (!sessionId) return [];
209
+
210
+ const messageStore = this.getSessionMessageStore(sessionId);
211
+ if (messageStore.historyLoaded) {
212
+ return messageStore.messages;
213
+ }
214
+
215
+ // 从 SessionContext 加载
216
+ if (this.agent?.framework) {
217
+ const sessionCtx = this.agent.framework._sessionContexts?.get(sessionId);
218
+ if (sessionCtx) {
219
+ const messages = sessionCtx.getMessages();
220
+ if (messages && messages.length > 0) {
221
+ messageStore.messages = messages;
222
+ messageStore.historyLoaded = true;
223
+ logger.debug(`Loaded ${messages.length} messages for session ${sessionId}`);
224
+ }
225
+ }
226
+ }
227
+
228
+ return messageStore.messages;
229
+ }
230
+
231
+ /**
232
+ * 保存会话历史
233
+ * @param {string} sessionId - Session ID
234
+ * @param {Array} messages - 消息数组
235
+ */
236
+ saveHistory(sessionId, messages) {
237
+ if (!sessionId || !messages) return;
238
+
239
+ const messageStore = this.getSessionMessageStore(sessionId);
240
+
241
+ // 保存到 SessionContext
242
+ if (this.agent?.framework) {
243
+ const sessionCtx = this.agent.framework._sessionContexts?.get(sessionId);
244
+ if (sessionCtx) {
245
+ sessionCtx.replaceMessages(messages);
246
+ }
247
+ }
248
+
249
+ messageStore.historyLoaded = true;
250
+ }
251
+
252
+ /**
253
+ * 添加消息到会话
254
+ * @param {string} sessionId - Session ID
255
+ * @param {Object} message - 消息
256
+ */
257
+ addMessage(sessionId, message) {
258
+ const store = this.getSessionMessageStore(sessionId);
259
+ store.messages.push(message);
260
+ }
261
+
262
+ /**
263
+ * 入队消息
264
+ * @param {string} sessionId - Session ID
265
+ * @param {Object} message - 消息
266
+ * @param {Object} options - 选项
267
+ * @returns {Promise}
268
+ */
269
+ enqueue(sessionId, message, options = {}) {
270
+ if (!this._sessionQueues.has(sessionId)) {
271
+ this._sessionQueues.set(sessionId, []);
272
+ }
273
+
274
+ return new Promise((resolve, reject) => {
275
+ const item = {
276
+ message,
277
+ options,
278
+ resolve,
279
+ reject,
280
+ timestamp: Date.now(),
281
+ executeFunction: options.executeFunction,
282
+ };
283
+ this._sessionQueues.get(sessionId).push(item);
284
+ this.emit('queue:added', {
285
+ sessionId,
286
+ message,
287
+ queueSize: this._sessionQueues.get(sessionId).length,
288
+ });
289
+
290
+ // 触发队列处理
291
+ this._processNext(sessionId);
292
+ });
293
+ }
294
+
295
+ /**
296
+ * 处理队列中的下一条消息
297
+ * @param {string} sessionId - Session ID
298
+ * @private
299
+ */
300
+ async _processNext(sessionId) {
301
+ if (this._processingSessions.has(sessionId)) {
302
+ return;
303
+ }
304
+
305
+ const queue = this._sessionQueues.get(sessionId);
306
+ if (!queue || queue.length === 0) {
307
+ this.emit('queue:empty', { sessionId });
308
+ return;
309
+ }
310
+
311
+ this._processingSessions.add(sessionId);
312
+ this.emit('queue:processing', { sessionId });
313
+
314
+ const item = queue.shift();
315
+ try {
316
+ // 如果有 executeFunction,使用流式处理
317
+ if (item.executeFunction) {
318
+ const chunks = [];
319
+ const stream = item.executeFunction(item.message, { ...item.options, sessionId });
320
+
321
+ for await (const chunk of stream) {
322
+ chunks.push(chunk);
323
+ this.emit('stream:chunk', {
324
+ sessionId,
325
+ chunk,
326
+ accumulated: chunks.length,
327
+ });
328
+ }
329
+
330
+ const fullText = chunks
331
+ .filter((a) => a.type === 'text')
332
+ .map((item) => item.text)
333
+ .join('');
334
+
335
+ item.resolve({ text: fullText, chunks });
336
+ } else {
337
+ const result = await this._processMessage(sessionId, item.message, item.options);
338
+ item.resolve(result);
339
+ }
340
+ } catch (err) {
341
+ item.reject(err);
342
+ } finally {
343
+ this._processingSessions.delete(sessionId);
344
+ // 处理下一条
345
+ setImmediate(() => this._processNext(sessionId));
346
+ }
347
+ }
348
+
349
+ /**
350
+ * 处理单条消息(子类实现)
351
+ * @param {string} sessionId - Session ID
352
+ * @param {Object} message - 消息
353
+ * @param {Object} options - 选项
354
+ * @returns {Promise}
355
+ * @protected
356
+ */
357
+ async _processMessage(sessionId, message, options) {
358
+ // 如果设置了处理器,使用处理器
359
+ if (this._messageProcessor) {
360
+ return this._messageProcessor(sessionId, message, options);
361
+ }
362
+ // 否则使用 agent 的处理逻辑
363
+ if (this.agent?._chatHandler) {
364
+ return this.agent._chatHandler._processMessage(sessionId, message, options);
365
+ }
366
+ throw new Error('No message processor set');
367
+ }
368
+
369
+ /**
370
+ * 取消会话队列
371
+ * @param {string} sessionId - Session ID
372
+ */
373
+ cancelSession(sessionId) {
374
+ const queue = this._sessionQueues.get(sessionId);
375
+ if (queue) {
376
+ queue.forEach((item) => {
377
+ item.reject(new Error('Session cancelled'));
378
+ });
379
+ queue.length = 0;
380
+ }
381
+ this._processingSessions.delete(sessionId);
382
+ this.emit('queue:session-removed', { sessionId });
383
+ }
384
+
385
+ /**
386
+ * 获取队列状态
387
+ * @param {string} sessionId - Session ID
388
+ * @returns {Object}
389
+ */
390
+ getQueueStatus(sessionId) {
391
+ const queue = this._sessionQueues.get(sessionId) || [];
392
+ return {
393
+ sessionId,
394
+ size: queue.length,
395
+ processing: this._processingSessions.has(sessionId),
396
+ };
397
+ }
398
+
399
+ /**
400
+ * 清空队列
401
+ * @param {string} sessionId - Session ID
402
+ */
403
+ clearQueue(sessionId) {
404
+ const queue = this._sessionQueues.get(sessionId);
405
+ if (queue) {
406
+ queue.forEach((item) => {
407
+ item.reject(new Error('Queue cleared'));
408
+ });
409
+ queue.length = 0;
410
+ }
411
+ this.emit('queue:cleared', { sessionId });
412
+ }
413
+
414
+ /**
415
+ * 生成请求 ID
416
+ * @returns {string}
417
+ */
418
+ generateRequestId() {
419
+ return `req_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
420
+ }
421
+ }
422
+
423
+ module.exports = { ChatSession, SessionScope };