foliko 1.0.87 → 1.1.1
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/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
- 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 +258 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
- package/.agent/ARCHITECTURE.md +288 -0
- package/.agent/agents/ambient-agent.md +57 -0
- package/.agent/agents/debugger.md +55 -0
- package/.agent/agents/email-assistant.md +49 -0
- package/.agent/agents/file-manager.md +42 -0
- package/.agent/agents/python-developer.md +60 -0
- package/.agent/agents/scheduler.md +59 -0
- package/.agent/agents/web-developer.md +45 -0
- package/.agent/data/default.json +325 -21
- package/.agent/data/plugins-state.json +194 -162
- package/.agent/data/puppeteer-sessions/undefined.json +6 -0
- package/.agent/mcp_config.json +0 -1
- package/.agent/mcp_config_updated.json +12 -0
- package/.agent/plugins/poster-plugin/README.md +304 -0
- package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221/347/262/227/344/275/223.ttf +0 -0
- package/.agent/plugins/poster-plugin/index.js +13 -0
- package/.agent/plugins/poster-plugin/package.json +28 -0
- package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
- package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
- package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
- package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
- package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
- package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
- package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
- package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
- package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
- package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
- package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
- package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
- package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
- package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
- package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
- package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
- package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
- package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
- package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
- package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
- package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
- package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
- package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
- package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
- package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
- package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
- package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
- package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
- package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
- package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
- package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
- package/.agent/plugins/poster-plugin/src/elements/polygon.js +63 -0
- package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
- package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
- package/.agent/plugins/poster-plugin/src/elements/text.js +107 -0
- package/.agent/plugins/poster-plugin/src/fonts.js +233 -0
- package/.agent/plugins/poster-plugin/src/index.js +1658 -0
- package/.agent/plugins/poster-plugin/src/presets.js +36 -0
- package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
- package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
- package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
- package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
- package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
- package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
- package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
- package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/index.js +1 -1
- package/.agent/plugins.json +5 -11
- package/.agent/rules/GEMINI.md +273 -0
- package/.agent/rules/allow-rule.md +77 -0
- package/.agent/rules/log-rule.md +83 -0
- package/.agent/rules/security-rule.md +93 -0
- package/.agent/scripts/auto_preview.py +148 -0
- package/.agent/scripts/checklist.py +217 -0
- package/.agent/scripts/session_manager.py +120 -0
- package/.agent/scripts/verify_all.py +327 -0
- package/.agent/sessions/cli_default.json +419 -0
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +2195 -0
- package/.agent/skills/api-patterns/SKILL.md +81 -0
- package/.agent/skills/api-patterns/api-style.md +42 -0
- package/.agent/skills/api-patterns/auth.md +24 -0
- package/.agent/skills/api-patterns/documentation.md +26 -0
- package/.agent/skills/api-patterns/graphql.md +41 -0
- package/.agent/skills/api-patterns/rate-limiting.md +31 -0
- package/.agent/skills/api-patterns/response.md +37 -0
- package/.agent/skills/api-patterns/rest.md +40 -0
- package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
- package/.agent/skills/api-patterns/security-testing.md +122 -0
- package/.agent/skills/api-patterns/trpc.md +41 -0
- package/.agent/skills/api-patterns/versioning.md +22 -0
- package/.agent/skills/app-builder/SKILL.md +75 -0
- package/.agent/skills/app-builder/agent-coordination.md +71 -0
- package/.agent/skills/app-builder/feature-building.md +53 -0
- package/.agent/skills/app-builder/project-detection.md +34 -0
- package/.agent/skills/app-builder/scaffolding.md +118 -0
- package/.agent/skills/app-builder/tech-stack.md +40 -0
- package/.agent/skills/app-builder/templates/SKILL.md +39 -0
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
- package/.agent/skills/architecture/SKILL.md +55 -0
- package/.agent/skills/architecture/context-discovery.md +43 -0
- package/.agent/skills/architecture/examples.md +94 -0
- package/.agent/skills/architecture/pattern-selection.md +68 -0
- package/.agent/skills/architecture/patterns-reference.md +50 -0
- package/.agent/skills/architecture/trade-off-analysis.md +77 -0
- package/.agent/skills/clean-code/SKILL.md +201 -0
- package/.agent/skills/doc.md +177 -0
- package/.agent/skills/frontend-design/SKILL.md +418 -0
- package/.agent/skills/frontend-design/animation-guide.md +331 -0
- package/.agent/skills/frontend-design/color-system.md +311 -0
- package/.agent/skills/frontend-design/decision-trees.md +418 -0
- package/.agent/skills/frontend-design/motion-graphics.md +306 -0
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/.agent/skills/frontend-design/typography-system.md +345 -0
- package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
- package/.agent/skills/frontend-design/visual-effects.md +383 -0
- package/.agent/skills/i18n-localization/SKILL.md +154 -0
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
- package/.agent/skills/mcp-builder/SKILL.md +176 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
- package/.agent/workflows/brainstorm.md +113 -0
- package/.agent/workflows/create.md +59 -0
- package/.agent/workflows/debug.md +103 -0
- package/.agent/workflows/deploy.md +176 -0
- package/.agent/workflows/enhance.md +63 -0
- package/.agent/workflows/orchestrate.md +237 -0
- package/.agent/workflows/plan.md +89 -0
- package/.agent/workflows/preview.md +81 -0
- package/.agent/workflows/simple-test.md +42 -0
- package/.agent/workflows/status.md +86 -0
- package/.agent/workflows/structured-orchestrate.md +180 -0
- package/.agent/workflows/test.md +144 -0
- package/.agent/workflows/ui-ux-pro-max.md +296 -0
- package/.claude/settings.local.json +20 -8
- package/.env.example +56 -56
- package/CLAUDE.md +144 -108
- package/README.md +441 -441
- package/calc_tokens_weixin.js +81 -0
- package/cli/src/commands/chat.js +2 -1
- package/docs/CONTEXT_DESIGN.md +1596 -0
- package/examples/test-concurrent-chat.js +60 -60
- package/foliko-creative-3.png +0 -0
- package/foliko-creative-4.png +0 -0
- package/foliko-creative-5.png +0 -0
- package/package.json +2 -2
- package/plugins/default-plugins.js +2 -1
- package/plugins/extension-executor-plugin.js +91 -2
- package/plugins/file-system-plugin.js +2 -2
- package/plugins/memory-plugin.js +984 -0
- package/plugins/session-plugin.js +57 -1
- package/plugins/weixin-plugin.js +33 -23
- package/skills/find-skills/AGENTS.md +162 -162
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/poster-guide/SKILL.md +1059 -0
- package/skills/python-plugin-dev/SKILL.md +238 -238
- package/skills/skill-guide/SKILL.md +130 -108
- package/src/capabilities/skill-manager.js +99 -0
- package/src/core/agent-chat.js +620 -141
- package/src/core/agent-context.js +188 -0
- package/src/core/agent.js +6 -2
- package/src/core/context-manager.js +283 -0
- package/src/core/framework.js +264 -3
- package/src/core/plugin-manager.js +79 -2
- package/src/core/request-context.js +98 -0
- package/src/core/session-context.js +341 -0
- package/src/core/session-storage.js +274 -0
- package/src/executors/mcp-executor.js +2 -2
- package/src/utils/index.js +239 -67
- package/src/utils/plugin-helpers.js +17 -0
- package/story-cover-book-v2.png +0 -0
- package/story-cover-japanese-1.png +0 -0
- package/story-cover-japanese-2.png +0 -0
- package/story-cover-japanese-3.png +0 -0
- package/story-cover-moran.png +0 -0
- package/undefined.png +0 -0
- package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
- package/.agent/agents/code-assistant.json +0 -14
- package/.agent/agents/email-assistant.json +0 -14
- package/.agent/agents/file-assistant.json +0 -15
- package/.agent/agents/system-assistant.json +0 -15
- package/.agent/agents/web-assistant.json +0 -12
- package/.agent/data/ambient/goals.json +0 -50
- package/.agent/data/ambient/memories.json +0 -7
- package/.agent/data/scheduler/tasks.json +0 -1
- package/.agent/package.json +0 -8
- package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
- package/.agent/plugins/daytona/README.md +0 -89
- package/.agent/plugins/daytona/index.js +0 -377
- package/.agent/plugins/daytona/package.json +0 -12
- package/.agent/plugins/marknative/README.md +0 -134
- package/.agent/plugins/marknative/index.js +0 -228
- package/.agent/plugins/marknative/package.json +0 -12
- package/.agent/plugins/marknative/update-readme.js +0 -134
- package/.agent/plugins/system-info/index.js +0 -387
- package/.agent/plugins/system-info/package.json +0 -4
- package/.agent/plugins/system-info/test.js +0 -40
- package/.agent/plugins/temp-repo/LICENSE +0 -201
- package/.agent/plugins/test_plugin.py +0 -304
- package/.agent/python-scripts/test_sample.py +0 -24
- package/.agent/skills/agent-browser/SKILL.md +0 -311
- package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
- package/.agent/skills/sysinfo/SKILL.md +0 -38
- package/.agent/skills/sysinfo/system-info.sh +0 -130
- package/.agent/skills/workflow/SKILL.md +0 -324
- package/.agent/workflows/email-digest.json +0 -50
- package/.agent/workflows/file-backup.json +0 -21
- package/.agent/workflows/get-ip-notify.json +0 -32
- package/.agent/workflows/news-aggregator.json +0 -93
- package/.agent/workflows/news-dashboard-v2.json +0 -94
- package/.agent/workflows/notification-batch.json +0 -32
- package/examples/test-chat-debug.js +0 -102
- package/examples/test-chat-result.js +0 -76
- package/examples/test-chat-stream-diff.js +0 -63
- /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/README.md +0 -0
- /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/package.json +0 -0
package/src/core/framework.js
CHANGED
|
@@ -10,6 +10,9 @@ const { PluginManager } = require('./plugin-manager');
|
|
|
10
10
|
const { ToolRegistry } = require('./tool-registry');
|
|
11
11
|
const { Agent } = require('./agent');
|
|
12
12
|
const { SubAgentConfigManager } = require('./sub-agent-config');
|
|
13
|
+
const { ContextManager } = require('./context-manager');
|
|
14
|
+
const { SessionContext } = require('./session-context');
|
|
15
|
+
const { SessionStorageAdapter, getDefaultAdapter } = require('./session-storage');
|
|
13
16
|
|
|
14
17
|
// 添加框架目录的 node_modules 到全局搜索路径
|
|
15
18
|
// 让项目插件能 require 框架内置的包(如 zod)
|
|
@@ -18,9 +21,14 @@ if (!module.paths.includes(frameworkNodeModules)) {
|
|
|
18
21
|
module.paths.unshift(frameworkNodeModules);
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
// AsyncLocalStorage
|
|
24
|
+
// 现有的 AsyncLocalStorage(保持向后兼容)
|
|
22
25
|
const asyncLocalStorage = new AsyncLocalStorage();
|
|
23
26
|
|
|
27
|
+
// 新增:三层 AsyncLocalStorage
|
|
28
|
+
const requestStorage = new AsyncLocalStorage(); // Request 级别
|
|
29
|
+
const sessionStorage = new AsyncLocalStorage(); // Session 级别
|
|
30
|
+
const agentStorage = new AsyncLocalStorage(); // Agent 级别
|
|
31
|
+
|
|
24
32
|
class Framework extends EventEmitter {
|
|
25
33
|
/**
|
|
26
34
|
* @param {Object} config - 配置
|
|
@@ -48,6 +56,20 @@ class Framework extends EventEmitter {
|
|
|
48
56
|
// 执行上下文(工具调用时可用)
|
|
49
57
|
this._executionContext = null;
|
|
50
58
|
|
|
59
|
+
// ========== 分层上下文系统 ==========
|
|
60
|
+
// Context 管理器
|
|
61
|
+
this._contextManager = new ContextManager(this);
|
|
62
|
+
|
|
63
|
+
// SessionContext 缓存(轻量管理,不依赖 ContextManager)
|
|
64
|
+
this._sessionContexts = new Map(); // sessionId → SessionContext
|
|
65
|
+
|
|
66
|
+
// Session 存储适配器(默认使用文件存储)
|
|
67
|
+
this._sessionStorage = null;
|
|
68
|
+
this._sessionStorageConfig = config.sessionStorage || {
|
|
69
|
+
type: 'file',
|
|
70
|
+
baseDir: '.agent/sessions',
|
|
71
|
+
};
|
|
72
|
+
|
|
51
73
|
// 事件转发 - ToolRegistry 事件
|
|
52
74
|
this.toolRegistry.on('tool:registered', (tool) => {
|
|
53
75
|
this.emit('tool:registered', tool);
|
|
@@ -283,6 +305,239 @@ class Framework extends EventEmitter {
|
|
|
283
305
|
*/
|
|
284
306
|
clearExecutionContext() {}
|
|
285
307
|
|
|
308
|
+
// ============================================================================
|
|
309
|
+
// 分层上下文系统 - Session Context
|
|
310
|
+
// ============================================================================
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* 获取或创建 SessionContext
|
|
314
|
+
* @param {string} sessionId - 会话 ID
|
|
315
|
+
* @param {Object} options - 配置选项
|
|
316
|
+
* @returns {SessionContext}
|
|
317
|
+
*/
|
|
318
|
+
getOrCreateSessionContext(sessionId, options = {}) {
|
|
319
|
+
if (!sessionId) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 先检查内存缓存
|
|
324
|
+
let ctx = this._sessionContexts.get(sessionId);
|
|
325
|
+
if (ctx) {
|
|
326
|
+
return ctx;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// 尝试从存储同步加载(仅文件存储支持)
|
|
330
|
+
const storage = this._getSessionStorage();
|
|
331
|
+
const loadedCtx = SessionContext.loadSync(sessionId, this, { ...options, storage });
|
|
332
|
+
if (loadedCtx) {
|
|
333
|
+
this._sessionContexts.set(sessionId, loadedCtx);
|
|
334
|
+
this.emit('session:context-created', loadedCtx);
|
|
335
|
+
return loadedCtx;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 创建新的 SessionContext
|
|
339
|
+
ctx = new SessionContext(sessionId, this, { ...options, storage });
|
|
340
|
+
this._sessionContexts.set(sessionId, ctx);
|
|
341
|
+
this.emit('session:context-created', ctx);
|
|
342
|
+
return ctx;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* 异步加载 SessionContext(如果存在)
|
|
347
|
+
* @param {string} sessionId
|
|
348
|
+
* @param {Object} options
|
|
349
|
+
* @returns {Promise<SessionContext|null>}
|
|
350
|
+
*/
|
|
351
|
+
async loadSessionContext(sessionId, options = {}) {
|
|
352
|
+
if (!sessionId) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// 先检查内存缓存
|
|
357
|
+
let ctx = this._sessionContexts.get(sessionId);
|
|
358
|
+
if (ctx) {
|
|
359
|
+
return ctx;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const storage = this._getSessionStorage();
|
|
363
|
+
ctx = await SessionContext.load(sessionId, this, { ...options, storage });
|
|
364
|
+
if (ctx) {
|
|
365
|
+
this._sessionContexts.set(sessionId, ctx);
|
|
366
|
+
this.emit('session:context-created', ctx);
|
|
367
|
+
}
|
|
368
|
+
return ctx;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* 获取 Session 存储适配器
|
|
373
|
+
* @returns {SessionStorageAdapter}
|
|
374
|
+
* @private
|
|
375
|
+
*/
|
|
376
|
+
_getSessionStorage() {
|
|
377
|
+
if (!this._sessionStorage) {
|
|
378
|
+
this._sessionStorage = new SessionStorageAdapter(this._sessionStorageConfig);
|
|
379
|
+
}
|
|
380
|
+
return this._sessionStorage;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* 配置 Session 存储类型
|
|
385
|
+
* @param {Object} config - 存储配置
|
|
386
|
+
* @param {string} [config.type='memory'] - 存储类型: 'memory', 'file'
|
|
387
|
+
* @param {string} [config.baseDir='.agent/sessions'] - 文件存储目录
|
|
388
|
+
*/
|
|
389
|
+
configureSessionStorage(config) {
|
|
390
|
+
this._sessionStorageConfig = config;
|
|
391
|
+
this._sessionStorage = new SessionStorageAdapter(config);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 获取当前 Session 存储适配器
|
|
396
|
+
* @returns {SessionStorageAdapter}
|
|
397
|
+
*/
|
|
398
|
+
getSessionStorage() {
|
|
399
|
+
return this._getSessionStorage();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* 获取 SessionContext
|
|
404
|
+
* @param {string} sessionId - 会话 ID
|
|
405
|
+
* @returns {SessionContext|null}
|
|
406
|
+
*/
|
|
407
|
+
getSessionContext(sessionId) {
|
|
408
|
+
return this._sessionContexts.get(sessionId) || null;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* 获取当前 Session 上下文(从 AsyncLocalStorage 获取)
|
|
413
|
+
* @returns {SessionContext|null}
|
|
414
|
+
*/
|
|
415
|
+
getCurrentSessionContext() {
|
|
416
|
+
const store = sessionStorage.getStore();
|
|
417
|
+
return store?.sessionContext || null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* 获取当前 sessionId(从 AsyncLocalStorage 获取)
|
|
422
|
+
* @returns {string|null}
|
|
423
|
+
*/
|
|
424
|
+
getCurrentSessionId() {
|
|
425
|
+
const store = sessionStorage.getStore();
|
|
426
|
+
return store?.sessionId || null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* 在 Session 上下文中执行函数
|
|
431
|
+
* @param {string} sessionId - 会话 ID
|
|
432
|
+
* @param {Object} options - Session 选项
|
|
433
|
+
* @param {Function} fn - 异步函数
|
|
434
|
+
* @returns {Promise}
|
|
435
|
+
*/
|
|
436
|
+
runInSession(sessionId, options, fn) {
|
|
437
|
+
if (!sessionId) {
|
|
438
|
+
// 无 session,直接执行
|
|
439
|
+
return fn();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const sessionCtx = this.getOrCreateSessionContext(sessionId, options);
|
|
443
|
+
const context = { sessionContext: sessionCtx, sessionId };
|
|
444
|
+
return sessionStorage.run(context, fn);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* 销毁 Session Context
|
|
449
|
+
* @param {string} sessionId
|
|
450
|
+
*/
|
|
451
|
+
destroySessionContext(sessionId) {
|
|
452
|
+
if (this._sessionContexts.has(sessionId)) {
|
|
453
|
+
const ctx = this._sessionContexts.get(sessionId);
|
|
454
|
+
ctx.destroy();
|
|
455
|
+
this._sessionContexts.delete(sessionId);
|
|
456
|
+
|
|
457
|
+
// 从存储中删除
|
|
458
|
+
if (this._sessionStorage) {
|
|
459
|
+
this._sessionStorage.delete(sessionId).catch(() => {});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
this.emit('session:context-destroyed', ctx);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* 列出所有活跃的 Session ID
|
|
468
|
+
* @returns {string[]}
|
|
469
|
+
*/
|
|
470
|
+
listActiveSessions() {
|
|
471
|
+
return Array.from(this._sessionContexts.keys());
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// 分层上下文系统 - Request Context
|
|
476
|
+
// ============================================================================
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* 获取当前 Request 上下文
|
|
480
|
+
* @returns {Object|null}
|
|
481
|
+
*/
|
|
482
|
+
getRequestContext() {
|
|
483
|
+
return requestStorage.getStore() || null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* 在 Request 上下文中执行函数
|
|
488
|
+
* @param {Object} context - Request 上下文
|
|
489
|
+
* @param {Function} fn - 异步函数
|
|
490
|
+
* @returns {Promise}
|
|
491
|
+
*/
|
|
492
|
+
runWithRequestContext(context, fn) {
|
|
493
|
+
return requestStorage.run(context, fn);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ============================================================================
|
|
497
|
+
// 分层上下文系统 - Agent Context
|
|
498
|
+
// ============================================================================
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* 获取当前 Agent 上下文
|
|
502
|
+
* @returns {Object|null}
|
|
503
|
+
*/
|
|
504
|
+
getAgentContext() {
|
|
505
|
+
return agentStorage.getStore()?.agentContext || null;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* 在 Agent 上下文中执行函数
|
|
510
|
+
* @param {string} agentId - Agent ID
|
|
511
|
+
* @param {Object} context - Agent 上下文
|
|
512
|
+
* @param {Function} fn - 异步函数
|
|
513
|
+
* @returns {Promise}
|
|
514
|
+
*/
|
|
515
|
+
runWithAgentContext(agentId, context, fn) {
|
|
516
|
+
return agentStorage.run({ agentId, ...context }, fn);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// 组合上下文
|
|
521
|
+
// ============================================================================
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* 在完整上下文中执行(Request + Session)
|
|
525
|
+
* @param {Object} requestOptions - Request 选项
|
|
526
|
+
* @param {string} sessionId - Session ID
|
|
527
|
+
* @param {Function} fn - 异步函数
|
|
528
|
+
* @returns {Promise}
|
|
529
|
+
*/
|
|
530
|
+
async runInContext(requestOptions, sessionId, fn) {
|
|
531
|
+
const sessionCtx = sessionId ? this.getOrCreateSessionContext(sessionId) : null;
|
|
532
|
+
|
|
533
|
+
return requestStorage.run(requestOptions, () => {
|
|
534
|
+
if (sessionCtx) {
|
|
535
|
+
return sessionStorage.run({ sessionContext: sessionCtx, sessionId }, fn);
|
|
536
|
+
}
|
|
537
|
+
return fn();
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
286
541
|
/**
|
|
287
542
|
* 创建 Agent
|
|
288
543
|
* @param {Object} config - Agent 配置
|
|
@@ -484,10 +739,16 @@ class Framework extends EventEmitter {
|
|
|
484
739
|
}
|
|
485
740
|
|
|
486
741
|
/**
|
|
487
|
-
*
|
|
742
|
+
* 销毁框架
|
|
488
743
|
*/
|
|
489
744
|
async destroy() {
|
|
490
|
-
//
|
|
745
|
+
// 刷新所有 Session 存储
|
|
746
|
+
if (this._sessionStorage) {
|
|
747
|
+
await this._sessionStorage.flush();
|
|
748
|
+
await this._sessionStorage.destroy();
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// 卸载所有插件
|
|
491
752
|
const plugins = this.pluginManager.getAll();
|
|
492
753
|
for (const { name } of plugins) {
|
|
493
754
|
await this.pluginManager.unload(name);
|
|
@@ -215,6 +215,13 @@ class PluginManager {
|
|
|
215
215
|
instance: pluginInstance,
|
|
216
216
|
status: 'registered',
|
|
217
217
|
enabled,
|
|
218
|
+
// 记录插件来源路径(用于热重载)
|
|
219
|
+
// 尝试从实例、prototype 或原始 plugin 对象获取
|
|
220
|
+
sourcePath:
|
|
221
|
+
pluginInstance._sourcePath ||
|
|
222
|
+
(plugin.prototype && plugin.prototype._sourcePath) ||
|
|
223
|
+
plugin._sourcePath ||
|
|
224
|
+
null,
|
|
218
225
|
});
|
|
219
226
|
|
|
220
227
|
this.framework.emit('plugin:registered', pluginInstance);
|
|
@@ -284,6 +291,11 @@ class PluginManager {
|
|
|
284
291
|
return pluginInstance;
|
|
285
292
|
}
|
|
286
293
|
|
|
294
|
+
// 如果 entry 没有 sourcePath,尝试从 plugin prototype 获取(loadPlugin 直接传入类的情况)
|
|
295
|
+
if (!entry.sourcePath && typeof plugin === 'function' && plugin.prototype) {
|
|
296
|
+
entry.sourcePath = plugin.prototype._sourcePath || null;
|
|
297
|
+
}
|
|
298
|
+
|
|
287
299
|
// 调用 install
|
|
288
300
|
try {
|
|
289
301
|
await entry.instance.install(this.framework);
|
|
@@ -476,6 +488,19 @@ class PluginManager {
|
|
|
476
488
|
plugin = pluginModule;
|
|
477
489
|
}
|
|
478
490
|
|
|
491
|
+
// 记录插件源路径(用于热重载)
|
|
492
|
+
let sourcePathSet = false;
|
|
493
|
+
if (typeof plugin === 'function' && plugin.prototype) {
|
|
494
|
+
plugin.prototype._sourcePath = pluginPath;
|
|
495
|
+
sourcePathSet = true;
|
|
496
|
+
} else if (typeof plugin === 'function') {
|
|
497
|
+
plugin._sourcePath = pluginPath;
|
|
498
|
+
sourcePathSet = true;
|
|
499
|
+
}
|
|
500
|
+
if (sourcePathSet) {
|
|
501
|
+
this._log.debug(`Set _sourcePath for plugin ${pluginName}: ${pluginPath}`);
|
|
502
|
+
}
|
|
503
|
+
|
|
479
504
|
// 获取插件名称
|
|
480
505
|
let resolvedPluginName;
|
|
481
506
|
try {
|
|
@@ -639,8 +664,60 @@ class PluginManager {
|
|
|
639
664
|
await entry.instance.stopBot();
|
|
640
665
|
}
|
|
641
666
|
}
|
|
642
|
-
|
|
643
|
-
|
|
667
|
+
|
|
668
|
+
// 如果有 sourcePath,重新 require 文件获取最新代码
|
|
669
|
+
if (entry.sourcePath) {
|
|
670
|
+
this._log.info(`Re-requiring plugin '${name}' from ${entry.sourcePath}`);
|
|
671
|
+
// 清除 require 缓存
|
|
672
|
+
delete require.cache[require.resolve(entry.sourcePath)];
|
|
673
|
+
const pluginModule = require(entry.sourcePath);
|
|
674
|
+
|
|
675
|
+
let NewPluginClass = pluginModule;
|
|
676
|
+
if (pluginModule.default) {
|
|
677
|
+
NewPluginClass = pluginModule.default;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// 创建新实例
|
|
681
|
+
let newInstance;
|
|
682
|
+
if (typeof NewPluginClass === 'function') {
|
|
683
|
+
if (NewPluginClass.prototype instanceof require('./plugin-base')) {
|
|
684
|
+
newInstance = new NewPluginClass();
|
|
685
|
+
} else {
|
|
686
|
+
newInstance = NewPluginClass();
|
|
687
|
+
}
|
|
688
|
+
} else {
|
|
689
|
+
newInstance = NewPluginClass;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// 复制 sourcePath 到新实例(prototype 上的属性不会自动继承)
|
|
693
|
+
if (entry.sourcePath) {
|
|
694
|
+
newInstance._sourcePath = entry.sourcePath;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// 复制 config 到新实例(用户配置需要保留)
|
|
698
|
+
if (entry.instance && entry.instance.config) {
|
|
699
|
+
newInstance.config = { ...entry.instance.config };
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// 替换旧实例
|
|
703
|
+
entry.instance = newInstance;
|
|
704
|
+
|
|
705
|
+
// 调用 install
|
|
706
|
+
await newInstance.install(this.framework);
|
|
707
|
+
|
|
708
|
+
// 调用 start
|
|
709
|
+
await newInstance.start(this.framework);
|
|
710
|
+
newInstance._started = true;
|
|
711
|
+
|
|
712
|
+
// 通知监听器(如 extension-executor-plugin)重新扫描
|
|
713
|
+
this.framework.emit('plugin:reloaded', newInstance);
|
|
714
|
+
|
|
715
|
+
this._log.info(`Plugin '${name}' re-required from ${entry.sourcePath}`);
|
|
716
|
+
} else {
|
|
717
|
+
this._log.info(`No sourcePath for plugin '${name}', calling reload() only`);
|
|
718
|
+
// 没有 sourcePath,只调用 reload
|
|
719
|
+
await this.reload(name);
|
|
720
|
+
}
|
|
644
721
|
} catch (err) {
|
|
645
722
|
this._log.error(`Enable/reload failed for '${name}':`, err.message);
|
|
646
723
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RequestContext - Request 级别的上下文封装
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 追踪请求链路(requestId, traceId)
|
|
6
|
+
* 2. 管理请求级超时
|
|
7
|
+
* 3. 传递请求元数据
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { uuid } = require('../utils/id');
|
|
11
|
+
|
|
12
|
+
class RequestContext {
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} options - 配置选项
|
|
15
|
+
* @param {string} [options.requestId] - 请求 ID,默认自动生成
|
|
16
|
+
* @param {string} [options.traceId] - 追踪 ID,默认自动生成
|
|
17
|
+
* @param {string} [options.parentSpanId] - 父 span ID
|
|
18
|
+
* @param {number} [options.timeout] - 超时时间(毫秒),默认 120000
|
|
19
|
+
* @param {boolean} [options.isStream] - 是否为流式请求
|
|
20
|
+
* @param {string} [options.userId] - 用户标识
|
|
21
|
+
*/
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.requestId = options.requestId || `req_${uuid()}`;
|
|
24
|
+
this.traceId = options.traceId || `trace_${uuid()}`;
|
|
25
|
+
this.traceId = options.traceId || generateId();
|
|
26
|
+
this.parentSpanId = options.parentSpanId || null;
|
|
27
|
+
|
|
28
|
+
this.timeout = options.timeout || 120000; // 默认 2 分钟
|
|
29
|
+
this.startTime = options.startTime || Date.now();
|
|
30
|
+
|
|
31
|
+
this.isStream = options.isStream || false;
|
|
32
|
+
this.userId = options.userId || null;
|
|
33
|
+
|
|
34
|
+
// 请求级状态
|
|
35
|
+
this.cancelled = false;
|
|
36
|
+
this.abortController = null;
|
|
37
|
+
|
|
38
|
+
// 元数据
|
|
39
|
+
this.metadata = options.metadata || {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 创建 AbortController(延迟初始化)
|
|
44
|
+
* @returns {AbortController}
|
|
45
|
+
*/
|
|
46
|
+
getAbortController() {
|
|
47
|
+
if (!this.abortController) {
|
|
48
|
+
this.abortController = new AbortController();
|
|
49
|
+
}
|
|
50
|
+
return this.abortController;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 检查是否超时
|
|
55
|
+
* @returns {boolean}
|
|
56
|
+
*/
|
|
57
|
+
isTimeout() {
|
|
58
|
+
return Date.now() - this.startTime > this.timeout;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 取消请求
|
|
63
|
+
*/
|
|
64
|
+
cancel() {
|
|
65
|
+
this.cancelled = true;
|
|
66
|
+
if (this.abortController) {
|
|
67
|
+
this.abortController.abort();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 获取请求耗时(毫秒)
|
|
73
|
+
* @returns {number}
|
|
74
|
+
*/
|
|
75
|
+
getElapsed() {
|
|
76
|
+
return Date.now() - this.startTime;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 获取请求摘要
|
|
81
|
+
* @returns {Object}
|
|
82
|
+
*/
|
|
83
|
+
toJSON() {
|
|
84
|
+
return {
|
|
85
|
+
requestId: this.requestId,
|
|
86
|
+
traceId: this.traceId,
|
|
87
|
+
parentSpanId: this.parentSpanId,
|
|
88
|
+
timeout: this.timeout,
|
|
89
|
+
startTime: this.startTime,
|
|
90
|
+
elapsed: this.getElapsed(),
|
|
91
|
+
isStream: this.isStream,
|
|
92
|
+
userId: this.userId,
|
|
93
|
+
cancelled: this.cancelled,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { RequestContext };
|