foliko 1.0.74 → 1.0.76

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 (238) 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/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -1,368 +1,370 @@
1
- /**
2
- * Session 会话管理插件
3
- * 管理多个用户会话,支持会话隔离和历史记录
4
- */
5
-
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { z } = require('zod')
8
- const { EventEmitter } = require('events')
9
-
10
- /**
11
- * 生成 UUID
12
- */
13
- function generateId() {
14
- if (require('crypto').randomUUID) {
15
- return require('crypto').randomUUID()
16
- }
17
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
18
- const r = Math.random() * 16 | 0
19
- const v = c === 'x' ? r : (r & 0x3 | 0x8)
20
- return v.toString(16)
21
- })
22
- }
23
-
24
- class SessionPlugin extends Plugin {
25
- constructor(config = {}) {
26
- super()
27
- this.name = 'session'
28
- this.version = '1.0.0'
29
- this.description = '会话管理插件,支持多会话隔离、历史记录、会话超时清理'
30
- this.priority = 5
31
-
32
- this.system = true
33
-
34
- this.config = {
35
- sessionTTL: config.sessionTTL || 30 * 60 * 1000, // 30分钟
36
- maxSessions: config.maxSessions || 100,
37
- maxHistoryLength: config.maxHistoryLength || 150, // 放宽到 150,Agent 已有智能压缩
38
- autoCleanup: config.autoCleanup !== false,
39
- cleanupInterval: config.cleanupInterval || 5 * 60 * 1000 // 5分钟
40
- }
41
-
42
- this._framework = null
43
- this._sessions = new Map()
44
- this._cleanupTimer = null
45
- this._events = new EventEmitter()
46
- }
47
-
48
- install(framework) {
49
- this._framework = framework
50
- return this
51
- }
52
-
53
- start(framework) {
54
- // 注册会话管理工具
55
- framework.registerTool({
56
- name: 'session_create',
57
- description: '创建新会话',
58
- inputSchema: z.object({
59
- sessionId: z.string().optional().describe('可选:指定会话 ID'),
60
- metadata: z.object({}).optional().describe('会话元数据')
61
- }),
62
- execute: async (args) => {
63
- const sessionId = args.sessionId || `session_${generateId()}`
64
- const session = this.createSession(sessionId, { metadata: args.metadata })
65
- return {
66
- success: true,
67
- sessionId: session.id,
68
- createdAt: session.createdAt
69
- }
70
- }
71
- })
72
-
73
- framework.registerTool({
74
- name: 'session_get',
75
- description: '获取会话信息',
76
- inputSchema: z.object({
77
- sessionId: z.string().describe('会话 ID')
78
- }),
79
- execute: async (args) => {
80
- const session = this.getSession(args.sessionId)
81
- if (!session) {
82
- return { success: false, error: 'Session not found' }
83
- }
84
- return {
85
- success: true,
86
- sessionId: session.id,
87
- messageCount: session.messages.length,
88
- variables: Object.keys(session.variables),
89
- createdAt: session.createdAt,
90
- lastActive: session.lastActive
91
- }
92
- }
93
- })
94
-
95
- framework.registerTool({
96
- name: 'session_list',
97
- description: '列出所有会话',
98
- inputSchema: z.object({}),
99
- execute: async () => {
100
- const sessions = this.listSessions()
101
- return {
102
- success: true,
103
- sessions,
104
- total: sessions.length
105
- }
106
- }
107
- })
108
-
109
- framework.registerTool({
110
- name: 'session_delete',
111
- description: '删除会话',
112
- inputSchema: z.object({
113
- sessionId: z.string().describe('会话 ID')
114
- }),
115
- execute: async (args) => {
116
- const deleted = this.deleteSession(args.sessionId)
117
- return { success: deleted, deleted: args.sessionId }
118
- }
119
- })
120
-
121
- framework.registerTool({
122
- name: 'session_history',
123
- description: '获取会话历史消息',
124
- inputSchema: z.object({
125
- sessionId: z.string().describe('会话 ID'),
126
- limit: z.number().optional().describe('返回消息数量限制')
127
- }),
128
- execute: async (args) => {
129
- const history = this.getHistory(args.sessionId, args.limit)
130
- return {
131
- success: true,
132
- sessionId: args.sessionId,
133
- messages: history,
134
- count: history.length
135
- }
136
- }
137
- })
138
-
139
- framework.registerTool({
140
- name: 'session_stats',
141
- description: '获取会话统计信息',
142
- inputSchema: z.object({}),
143
- execute: async () => {
144
- return {
145
- success: true,
146
- stats: this.getMemoryStats()
147
- }
148
- }
149
- })
150
-
151
- // 启动自动清理
152
- if (this.config.autoCleanup) {
153
- this._startAutoCleanup()
154
- }
155
-
156
- return this
157
- }
158
-
159
- /**
160
- * 创建新会话
161
- */
162
- createSession(sessionId, options = {}) {
163
- const id = sessionId || `session_${generateId()}`
164
-
165
- if (this._sessions.has(id)) {
166
- return this._sessions.get(id)
167
- }
168
-
169
- // 如果会话数超过限制,清理最老的
170
- if (this._sessions.size >= this.config.maxSessions) {
171
- this._cleanupLRU()
172
- }
173
-
174
- const session = {
175
- id,
176
- messages: options.initialMessages || [],
177
- variables: options.variables || {},
178
- metadata: options.metadata || {},
179
- createdAt: new Date(),
180
- lastActive: new Date()
181
- }
182
-
183
- this._sessions.set(id, session)
184
- return session
185
- }
186
-
187
- /**
188
- * 获取会话
189
- */
190
- getSession(sessionId) {
191
- const session = this._sessions.get(sessionId)
192
- if (session) {
193
- session.lastActive = new Date()
194
- }
195
- return session
196
- }
197
-
198
- /**
199
- * 获取或创建会话
200
- */
201
- getOrCreateSession(sessionId, options = {}) {
202
- let session = this.getSession(sessionId)
203
- if (!session) {
204
- session = this.createSession(sessionId, options)
205
- }
206
- return session
207
- }
208
-
209
- /**
210
- * 添加消息到会话
211
- */
212
- addMessage(sessionId, message) {
213
- const session = this.getSession(sessionId)
214
- if (session) {
215
- session.messages.push(message)
216
- session.lastActive = new Date()
217
-
218
- // 限制历史长度
219
- if (session.messages.length > this.config.maxHistoryLength) {
220
- session.messages = session.messages.slice(-this.config.maxHistoryLength)
221
- }
222
- }
223
- return session
224
- }
225
-
226
- /**
227
- * 获取会话历史
228
- */
229
- getHistory(sessionId, limit = null) {
230
- const session = this.getSession(sessionId)
231
- if (!session) return []
232
-
233
- const messages = session.messages
234
- if (limit) {
235
- return messages.slice(-limit)
236
- }
237
- return messages
238
- }
239
-
240
- /**
241
- * 删除会话
242
- */
243
- deleteSession(sessionId) {
244
- const deleted = this._sessions.delete(sessionId)
245
- if (deleted) {
246
- this._events.emit('session:deleted', sessionId)
247
- }
248
- return deleted
249
- }
250
-
251
- /**
252
- * 列出所有会话
253
- */
254
- listSessions() {
255
- return Array.from(this._sessions.values()).map(s => ({
256
- id: s.id,
257
- messageCount: s.messages.length,
258
- createdAt: s.createdAt,
259
- lastActive: s.lastActive,
260
- metadata: s.metadata
261
- }))
262
- }
263
-
264
- /**
265
- * 清理过期会话
266
- */
267
- cleanup() {
268
- const now = Date.now()
269
- let cleanedCount = 0
270
-
271
- for (const [sessionId, session] of this._sessions) {
272
- if (now - session.lastActive.getTime() > this.config.sessionTTL) {
273
- this._sessions.delete(sessionId)
274
- cleanedCount++
275
- }
276
- }
277
-
278
- return cleanedCount
279
- }
280
-
281
- /**
282
- * LRU 清理 - 删除最老的 20% 会话
283
- */
284
- _cleanupLRU() {
285
- const sessions = Array.from(this._sessions.values())
286
- if (sessions.length === 0) return
287
-
288
- // 按最后活跃时间排序
289
- sessions.sort((a, b) => a.lastActive.getTime() - b.lastActive.getTime())
290
-
291
- // 删除最老的会话
292
- const toDelete = sessions.slice(0, Math.ceil(sessions.length * 0.2))
293
- for (const session of toDelete) {
294
- this._sessions.delete(session.id)
295
- }
296
- }
297
-
298
- /**
299
- * 获取内存统计
300
- */
301
- getMemoryStats() {
302
- const sessionCount = this._sessions.size
303
- const totalMessages = Array.from(this._sessions.values()).reduce(
304
- (sum, s) => sum + s.messages.length, 0
305
- )
306
-
307
- return {
308
- sessionCount,
309
- maxSessions: this.config.maxSessions,
310
- totalMessages,
311
- ttl: this.config.sessionTTL
312
- }
313
- }
314
-
315
- /**
316
- * 清理所有会话
317
- */
318
- clear() {
319
- const sessionIds = Array.from(this._sessions.keys())
320
- this._sessions.clear()
321
- sessionIds.forEach(id => this._events.emit('session:deleted', id))
322
- }
323
-
324
- /**
325
- * 监听会话事件
326
- */
327
- on(event, listener) {
328
- this._events.on(event, listener)
329
- }
330
-
331
- /**
332
- * 移除会话事件监听
333
- */
334
- off(event, listener) {
335
- this._events.off(event, listener)
336
- }
337
-
338
- /**
339
- * 启动自动清理定时器
340
- */
341
- _startAutoCleanup() {
342
- if (this._cleanupTimer) {
343
- clearInterval(this._cleanupTimer)
344
- }
345
- this._cleanupTimer = setInterval(() => {
346
- const cleaned = this.cleanup()
347
- if (cleaned > 0) {
348
- console.log(`[SessionPlugin] Cleaned up ${cleaned} expired sessions`)
349
- }
350
- }, this.config.cleanupInterval)
351
- }
352
-
353
- reload(framework) {
354
- this._framework = framework
355
- }
356
-
357
- uninstall(framework) {
358
- if (this._cleanupTimer) {
359
- clearInterval(this._cleanupTimer)
360
- this._cleanupTimer = null
361
- }
362
- this._events.removeAllListeners()
363
- this._sessions.clear()
364
- this._framework = null
365
- }
366
- }
367
-
1
+ /**
2
+ * Session 会话管理插件
3
+ * 管理多个用户会话,支持会话隔离和历史记录
4
+ */
5
+
6
+ const { Plugin } = require('../src/core/plugin-base')
7
+ const { logger } = require('../src/utils/logger')
8
+ const log = logger.child('Session')
9
+ const { z } = require('zod')
10
+ const { EventEmitter } = require('events')
11
+
12
+ /**
13
+ * 生成 UUID
14
+ */
15
+ function generateId() {
16
+ if (require('crypto').randomUUID) {
17
+ return require('crypto').randomUUID()
18
+ }
19
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
20
+ const r = Math.random() * 16 | 0
21
+ const v = c === 'x' ? r : (r & 0x3 | 0x8)
22
+ return v.toString(16)
23
+ })
24
+ }
25
+
26
+ class SessionPlugin extends Plugin {
27
+ constructor(config = {}) {
28
+ super()
29
+ this.name = 'session'
30
+ this.version = '1.0.0'
31
+ this.description = '会话管理插件,支持多会话隔离、历史记录、会话超时清理'
32
+ this.priority = 5
33
+
34
+ this.system = true
35
+
36
+ this.config = {
37
+ sessionTTL: config.sessionTTL || 30 * 60 * 1000, // 30分钟
38
+ maxSessions: config.maxSessions || 100,
39
+ maxHistoryLength: config.maxHistoryLength || 150, // 放宽到 150,Agent 已有智能压缩
40
+ autoCleanup: config.autoCleanup !== false,
41
+ cleanupInterval: config.cleanupInterval || 5 * 60 * 1000 // 5分钟
42
+ }
43
+
44
+ this._framework = null
45
+ this._sessions = new Map()
46
+ this._cleanupTimer = null
47
+ this._events = new EventEmitter()
48
+ }
49
+
50
+ install(framework) {
51
+ this._framework = framework
52
+ return this
53
+ }
54
+
55
+ start(framework) {
56
+ // 注册会话管理工具
57
+ framework.registerTool({
58
+ name: 'session_create',
59
+ description: '创建新会话',
60
+ inputSchema: z.object({
61
+ sessionId: z.string().optional().describe('可选:指定会话 ID'),
62
+ metadata: z.object({}).optional().describe('会话元数据')
63
+ }),
64
+ execute: async (args) => {
65
+ const sessionId = args.sessionId || `session_${generateId()}`
66
+ const session = this.createSession(sessionId, { metadata: args.metadata })
67
+ return {
68
+ success: true,
69
+ sessionId: session.id,
70
+ createdAt: session.createdAt
71
+ }
72
+ }
73
+ })
74
+
75
+ framework.registerTool({
76
+ name: 'session_get',
77
+ description: '获取会话信息',
78
+ inputSchema: z.object({
79
+ sessionId: z.string().describe('会话 ID')
80
+ }),
81
+ execute: async (args) => {
82
+ const session = this.getSession(args.sessionId)
83
+ if (!session) {
84
+ return { success: false, error: 'Session not found' }
85
+ }
86
+ return {
87
+ success: true,
88
+ sessionId: session.id,
89
+ messageCount: session.messages.length,
90
+ variables: Object.keys(session.variables),
91
+ createdAt: session.createdAt,
92
+ lastActive: session.lastActive
93
+ }
94
+ }
95
+ })
96
+
97
+ framework.registerTool({
98
+ name: 'session_list',
99
+ description: '列出所有会话',
100
+ inputSchema: z.object({}),
101
+ execute: async () => {
102
+ const sessions = this.listSessions()
103
+ return {
104
+ success: true,
105
+ sessions,
106
+ total: sessions.length
107
+ }
108
+ }
109
+ })
110
+
111
+ framework.registerTool({
112
+ name: 'session_delete',
113
+ description: '删除会话',
114
+ inputSchema: z.object({
115
+ sessionId: z.string().describe('会话 ID')
116
+ }),
117
+ execute: async (args) => {
118
+ const deleted = this.deleteSession(args.sessionId)
119
+ return { success: deleted, deleted: args.sessionId }
120
+ }
121
+ })
122
+
123
+ framework.registerTool({
124
+ name: 'session_history',
125
+ description: '获取会话历史消息',
126
+ inputSchema: z.object({
127
+ sessionId: z.string().describe('会话 ID'),
128
+ limit: z.number().optional().describe('返回消息数量限制')
129
+ }),
130
+ execute: async (args) => {
131
+ const history = this.getHistory(args.sessionId, args.limit)
132
+ return {
133
+ success: true,
134
+ sessionId: args.sessionId,
135
+ messages: history,
136
+ count: history.length
137
+ }
138
+ }
139
+ })
140
+
141
+ framework.registerTool({
142
+ name: 'session_stats',
143
+ description: '获取会话统计信息',
144
+ inputSchema: z.object({}),
145
+ execute: async () => {
146
+ return {
147
+ success: true,
148
+ stats: this.getMemoryStats()
149
+ }
150
+ }
151
+ })
152
+
153
+ // 启动自动清理
154
+ if (this.config.autoCleanup) {
155
+ this._startAutoCleanup()
156
+ }
157
+
158
+ return this
159
+ }
160
+
161
+ /**
162
+ * 创建新会话
163
+ */
164
+ createSession(sessionId, options = {}) {
165
+ const id = sessionId || `session_${generateId()}`
166
+
167
+ if (this._sessions.has(id)) {
168
+ return this._sessions.get(id)
169
+ }
170
+
171
+ // 如果会话数超过限制,清理最老的
172
+ if (this._sessions.size >= this.config.maxSessions) {
173
+ this._cleanupLRU()
174
+ }
175
+
176
+ const session = {
177
+ id,
178
+ messages: options.initialMessages || [],
179
+ variables: options.variables || {},
180
+ metadata: options.metadata || {},
181
+ createdAt: new Date(),
182
+ lastActive: new Date()
183
+ }
184
+
185
+ this._sessions.set(id, session)
186
+ return session
187
+ }
188
+
189
+ /**
190
+ * 获取会话
191
+ */
192
+ getSession(sessionId) {
193
+ const session = this._sessions.get(sessionId)
194
+ if (session) {
195
+ session.lastActive = new Date()
196
+ }
197
+ return session
198
+ }
199
+
200
+ /**
201
+ * 获取或创建会话
202
+ */
203
+ getOrCreateSession(sessionId, options = {}) {
204
+ let session = this.getSession(sessionId)
205
+ if (!session) {
206
+ session = this.createSession(sessionId, options)
207
+ }
208
+ return session
209
+ }
210
+
211
+ /**
212
+ * 添加消息到会话
213
+ */
214
+ addMessage(sessionId, message) {
215
+ const session = this.getSession(sessionId)
216
+ if (session) {
217
+ session.messages.push(message)
218
+ session.lastActive = new Date()
219
+
220
+ // 限制历史长度
221
+ if (session.messages.length > this.config.maxHistoryLength) {
222
+ session.messages = session.messages.slice(-this.config.maxHistoryLength)
223
+ }
224
+ }
225
+ return session
226
+ }
227
+
228
+ /**
229
+ * 获取会话历史
230
+ */
231
+ getHistory(sessionId, limit = null) {
232
+ const session = this.getSession(sessionId)
233
+ if (!session) return []
234
+
235
+ const messages = session.messages
236
+ if (limit) {
237
+ return messages.slice(-limit)
238
+ }
239
+ return messages
240
+ }
241
+
242
+ /**
243
+ * 删除会话
244
+ */
245
+ deleteSession(sessionId) {
246
+ const deleted = this._sessions.delete(sessionId)
247
+ if (deleted) {
248
+ this._events.emit('session:deleted', sessionId)
249
+ }
250
+ return deleted
251
+ }
252
+
253
+ /**
254
+ * 列出所有会话
255
+ */
256
+ listSessions() {
257
+ return Array.from(this._sessions.values()).map(s => ({
258
+ id: s.id,
259
+ messageCount: s.messages.length,
260
+ createdAt: s.createdAt,
261
+ lastActive: s.lastActive,
262
+ metadata: s.metadata
263
+ }))
264
+ }
265
+
266
+ /**
267
+ * 清理过期会话
268
+ */
269
+ cleanup() {
270
+ const now = Date.now()
271
+ let cleanedCount = 0
272
+
273
+ for (const [sessionId, session] of this._sessions) {
274
+ if (now - session.lastActive.getTime() > this.config.sessionTTL) {
275
+ this._sessions.delete(sessionId)
276
+ cleanedCount++
277
+ }
278
+ }
279
+
280
+ return cleanedCount
281
+ }
282
+
283
+ /**
284
+ * LRU 清理 - 删除最老的 20% 会话
285
+ */
286
+ _cleanupLRU() {
287
+ const sessions = Array.from(this._sessions.values())
288
+ if (sessions.length === 0) return
289
+
290
+ // 按最后活跃时间排序
291
+ sessions.sort((a, b) => a.lastActive.getTime() - b.lastActive.getTime())
292
+
293
+ // 删除最老的会话
294
+ const toDelete = sessions.slice(0, Math.ceil(sessions.length * 0.2))
295
+ for (const session of toDelete) {
296
+ this._sessions.delete(session.id)
297
+ }
298
+ }
299
+
300
+ /**
301
+ * 获取内存统计
302
+ */
303
+ getMemoryStats() {
304
+ const sessionCount = this._sessions.size
305
+ const totalMessages = Array.from(this._sessions.values()).reduce(
306
+ (sum, s) => sum + s.messages.length, 0
307
+ )
308
+
309
+ return {
310
+ sessionCount,
311
+ maxSessions: this.config.maxSessions,
312
+ totalMessages,
313
+ ttl: this.config.sessionTTL
314
+ }
315
+ }
316
+
317
+ /**
318
+ * 清理所有会话
319
+ */
320
+ clear() {
321
+ const sessionIds = Array.from(this._sessions.keys())
322
+ this._sessions.clear()
323
+ sessionIds.forEach(id => this._events.emit('session:deleted', id))
324
+ }
325
+
326
+ /**
327
+ * 监听会话事件
328
+ */
329
+ on(event, listener) {
330
+ this._events.on(event, listener)
331
+ }
332
+
333
+ /**
334
+ * 移除会话事件监听
335
+ */
336
+ off(event, listener) {
337
+ this._events.off(event, listener)
338
+ }
339
+
340
+ /**
341
+ * 启动自动清理定时器
342
+ */
343
+ _startAutoCleanup() {
344
+ if (this._cleanupTimer) {
345
+ clearInterval(this._cleanupTimer)
346
+ }
347
+ this._cleanupTimer = setInterval(() => {
348
+ const cleaned = this.cleanup()
349
+ if (cleaned > 0) {
350
+ log.info(` Cleaned up ${cleaned} expired sessions`)
351
+ }
352
+ }, this.config.cleanupInterval)
353
+ }
354
+
355
+ reload(framework) {
356
+ this._framework = framework
357
+ }
358
+
359
+ uninstall(framework) {
360
+ if (this._cleanupTimer) {
361
+ clearInterval(this._cleanupTimer)
362
+ this._cleanupTimer = null
363
+ }
364
+ this._events.removeAllListeners()
365
+ this._sessions.clear()
366
+ this._framework = null
367
+ }
368
+ }
369
+
368
370
  module.exports = { SessionPlugin }