foliko 1.0.86 → 1.1.0
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/data/default.json +3 -4310
- package/.agent/data/plugins-state.json +34 -1
- package/.agent/mcp_config.json +0 -1
- package/.agent/memory/core.md +1 -0
- package/.agent/memory/project/mnn93ogy-ypjn27.md +9 -0
- package/.agent/memory/project/mnn98fqy-5nhc1u.md +25 -0
- package/.agent/memory/user/mnm67t9m-x8rekk.md +9 -0
- package/.agent/memory/user/mnn5mmqh-w6aktx.md +11 -0
- package/.agent/memory/user/mnnbfhhn-dk1bd1.md +22 -0
- package/.agent/plugins/__pycache__/file_writer.cpython-312.pyc +0 -0
- package/.agent/plugins/marknative/index.js +2 -7
- package/.agent/plugins/poster-plugin/README.md +304 -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 +32 -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 +38 -0
- package/.agent/plugins/poster-plugin/src/fonts.js +118 -0
- package/.agent/plugins/poster-plugin/src/index.js +1659 -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/sessions/cli_default.json +24265 -0
- package/.agent/weixin.json +6 -0
- package/.claude/settings.local.json +176 -171
- package/CLAUDE.md +144 -108
- package/docs/CONTEXT_DESIGN.md +1596 -0
- package/examples/test-concurrent-chat.js +60 -0
- package/examples/test-long-chat.js +77 -0
- package/examples/test-session-chat.js +93 -0
- package/output/beef-love-poster.png +0 -0
- package/package.json +2 -2
- package/plugins/default-plugins.js +2 -1
- package/plugins/extension-executor-plugin.js +11 -0
- package/plugins/memory-plugin.js +984 -0
- package/plugins/session-plugin.js +78 -1
- package/plugins/weixin-plugin.js +24 -22
- package/skills/poster-guide/SKILL.md +743 -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 +627 -180
- package/src/core/agent-context.js +188 -0
- package/src/core/agent.js +9 -63
- 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//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
- package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
- package/.agent/plugins/temp-repo/LICENSE +0 -201
- package/.agent/plugins/temp-repo/puppeteer-plugin/README.md +0 -147
- package/.agent/plugins/temp-repo/puppeteer-plugin/index.js +0 -1418
- package/.agent/plugins/temp-repo/puppeteer-plugin/package.json +0 -9
- package/.agent/plugins/test_plugin.py +0 -304
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentContext - Agent 级别的上下文封装
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 隔离不同 Agent 实例的状态
|
|
6
|
+
* 2. 管理 Agent 级工具注册
|
|
7
|
+
* 3. 管理 Agent 级技能
|
|
8
|
+
* 4. 管理 Agent 级系统提示词
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
class AgentContext {
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} agentId - Agent ID
|
|
14
|
+
* @param {Agent} agent - Agent 实例引用
|
|
15
|
+
* @param {Object} options - 配置选项
|
|
16
|
+
*/
|
|
17
|
+
constructor(agentId, agent, options = {}) {
|
|
18
|
+
this.agentId = agentId;
|
|
19
|
+
this.agent = agent; // Agent 实例引用
|
|
20
|
+
|
|
21
|
+
this.name = options.name || agent?.name || agentId;
|
|
22
|
+
|
|
23
|
+
// Agent 级工具注册(覆盖全局)
|
|
24
|
+
this.tools = new Map();
|
|
25
|
+
|
|
26
|
+
// Agent 级技能
|
|
27
|
+
this.skills = [];
|
|
28
|
+
|
|
29
|
+
// Agent 级系统提示词
|
|
30
|
+
this.systemPrompt = null;
|
|
31
|
+
|
|
32
|
+
// 自定义数据
|
|
33
|
+
this.customData = new Map();
|
|
34
|
+
|
|
35
|
+
// 元数据
|
|
36
|
+
this.metadata = {
|
|
37
|
+
createdAt: Date.now(),
|
|
38
|
+
lastActive: Date.now(),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ==================== 工具管理 ====================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 注册工具
|
|
46
|
+
* @param {Object} toolDef - 工具定义
|
|
47
|
+
*/
|
|
48
|
+
registerTool(toolDef) {
|
|
49
|
+
this.tools.set(toolDef.name, toolDef);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 批量注册工具
|
|
54
|
+
* @param {Array<Object>} toolDefs - 工具定义数组
|
|
55
|
+
*/
|
|
56
|
+
registerTools(toolDefs) {
|
|
57
|
+
for (const toolDef of toolDefs) {
|
|
58
|
+
this.registerTool(toolDef);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 注销工具
|
|
64
|
+
* @param {string} name - 工具名
|
|
65
|
+
*/
|
|
66
|
+
unregisterTool(name) {
|
|
67
|
+
this.tools.delete(name);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 获取工具
|
|
72
|
+
* @param {string} name - 工具名
|
|
73
|
+
* @returns {Object|null}
|
|
74
|
+
*/
|
|
75
|
+
getTool(name) {
|
|
76
|
+
return this.tools.get(name) || null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 获取所有工具
|
|
81
|
+
* @returns {Array}
|
|
82
|
+
*/
|
|
83
|
+
getAllTools() {
|
|
84
|
+
return Array.from(this.tools.values());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 检查是否有工具
|
|
89
|
+
* @param {string} name - 工具名
|
|
90
|
+
* @returns {boolean}
|
|
91
|
+
*/
|
|
92
|
+
hasTool(name) {
|
|
93
|
+
return this.tools.has(name);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ==================== 技能管理 ====================
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 添加技能
|
|
100
|
+
* @param {Object} skill - 技能对象
|
|
101
|
+
*/
|
|
102
|
+
addSkill(skill) {
|
|
103
|
+
this.skills.push(skill);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 移除技能
|
|
108
|
+
* @param {string} skillName - 技能名
|
|
109
|
+
*/
|
|
110
|
+
removeSkill(skillName) {
|
|
111
|
+
this.skills = this.skills.filter((s) => s.name !== skillName);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 获取所有技能
|
|
116
|
+
* @returns {Array}
|
|
117
|
+
*/
|
|
118
|
+
getAllSkills() {
|
|
119
|
+
return [...this.skills];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ==================== 系统提示词 ====================
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 设置系统提示词
|
|
126
|
+
* @param {string} prompt - 提示词
|
|
127
|
+
*/
|
|
128
|
+
setSystemPrompt(prompt) {
|
|
129
|
+
this.systemPrompt = prompt;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 获取系统提示词
|
|
134
|
+
* @returns {string|null}
|
|
135
|
+
*/
|
|
136
|
+
getSystemPrompt() {
|
|
137
|
+
return this.systemPrompt;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ==================== 自定义数据 ====================
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 设置自定义数据
|
|
144
|
+
* @param {string} key - 键
|
|
145
|
+
* @param {*} value - 值
|
|
146
|
+
*/
|
|
147
|
+
setCustomData(key, value) {
|
|
148
|
+
this.customData.set(key, value);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 获取自定义数据
|
|
153
|
+
* @param {string} key - 键
|
|
154
|
+
* @param {*} defaultValue - 默认值
|
|
155
|
+
* @returns {*}
|
|
156
|
+
*/
|
|
157
|
+
getCustomData(key, defaultValue = undefined) {
|
|
158
|
+
return this.customData.get(key) ?? defaultValue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 删除自定义数据
|
|
163
|
+
* @param {string} key - 键
|
|
164
|
+
*/
|
|
165
|
+
deleteCustomData(key) {
|
|
166
|
+
this.customData.delete(key);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ==================== 生命周期 ====================
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 更新最后活跃时间
|
|
173
|
+
*/
|
|
174
|
+
touch() {
|
|
175
|
+
this.metadata.lastActive = Date.now();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 销毁
|
|
180
|
+
*/
|
|
181
|
+
destroy() {
|
|
182
|
+
this.tools.clear();
|
|
183
|
+
this.skills = [];
|
|
184
|
+
this.customData.clear();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = { AgentContext };
|
package/src/core/agent.js
CHANGED
|
@@ -53,10 +53,6 @@ class Agent extends EventEmitter {
|
|
|
53
53
|
// 子Agent管理
|
|
54
54
|
this._subAgents = new Map();
|
|
55
55
|
|
|
56
|
-
// 消息队列(用于 pushMessage)
|
|
57
|
-
this._messageQueue = [];
|
|
58
|
-
this._isProcessingQueue = false;
|
|
59
|
-
|
|
60
56
|
// System prompt 构建器
|
|
61
57
|
this._systemPromptBuilder = new SystemPromptBuilder();
|
|
62
58
|
this._registerDefaultPromptParts();
|
|
@@ -101,7 +97,7 @@ class Agent extends EventEmitter {
|
|
|
101
97
|
});
|
|
102
98
|
|
|
103
99
|
// 4. 工具列表 (优先级 400)
|
|
104
|
-
this._systemPromptBuilder.register('tools', 400, () => this._buildToolsDescription());
|
|
100
|
+
//this._systemPromptBuilder.register('tools', 400, () => this._buildToolsDescription());
|
|
105
101
|
|
|
106
102
|
// 5. 技能列表 (优先级 500)
|
|
107
103
|
this._systemPromptBuilder.register('skills', 500, () => this._buildSkillsDescription());
|
|
@@ -526,17 +522,21 @@ class Agent extends EventEmitter {
|
|
|
526
522
|
4. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
|
|
527
523
|
5. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
|
|
528
524
|
6. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
|
|
525
|
+
7. **步骤未完成必须提示继续**:如果任务需要多步骤操作,在返回前必须明确告知用户当前进度和下一步操作。如果回复内容为空或不完整,必须说明"步骤进行中,请继续"。
|
|
529
526
|
|
|
530
527
|
|
|
531
528
|
【响应规范】
|
|
532
529
|
- 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
|
|
533
530
|
- 如果工具返回错误,说明错误原因并给出解决建议
|
|
534
531
|
- 如果信息不足,先调用工具获取必要信息,不要假设或猜测
|
|
532
|
+
- **重要:如果任务需要多步骤操作,在回复末尾必须提示用户"请继续"或"是否继续下一步"**
|
|
533
|
+
|
|
535
534
|
|
|
536
535
|
【禁止事项】
|
|
537
536
|
- 不调用工具就直接回答
|
|
538
537
|
- 编造不存在的数据、文件、订单、用户等信息
|
|
539
|
-
-
|
|
538
|
+
- 回复含糊不清,让用户无法确定答案是否正确
|
|
539
|
+
- **多步骤任务未完成就结束,不提示用户继续**`;
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
/**
|
|
@@ -734,10 +734,6 @@ class Agent extends EventEmitter {
|
|
|
734
734
|
* 发送消息
|
|
735
735
|
*/
|
|
736
736
|
async chat(message, options = {}) {
|
|
737
|
-
if (this._status === 'busy') {
|
|
738
|
-
throw new Error('Agent is busy');
|
|
739
|
-
}
|
|
740
|
-
|
|
741
737
|
if (this._status === 'error') {
|
|
742
738
|
this._status = 'idle';
|
|
743
739
|
}
|
|
@@ -755,21 +751,16 @@ class Agent extends EventEmitter {
|
|
|
755
751
|
|
|
756
752
|
this._syncTools();
|
|
757
753
|
|
|
754
|
+
// 通过 handler 的 enqueue 处理(自动排队)
|
|
758
755
|
const result = await this._chatHandler.chat(enhancedMessage, options);
|
|
756
|
+
|
|
759
757
|
this._status = 'idle';
|
|
760
758
|
this.emit('status', { status: 'idle' });
|
|
761
759
|
|
|
762
|
-
// 处理队列中的下一条消息
|
|
763
|
-
setImmediate(() => this._processQueue());
|
|
764
|
-
|
|
765
760
|
return result;
|
|
766
761
|
} catch (err) {
|
|
767
762
|
this._status = 'error';
|
|
768
763
|
this.emit('status', { status: 'error', error: err.message });
|
|
769
|
-
|
|
770
|
-
// 发生错误时也要处理队列
|
|
771
|
-
setImmediate(() => this._processQueue());
|
|
772
|
-
|
|
773
764
|
throw err;
|
|
774
765
|
}
|
|
775
766
|
}
|
|
@@ -789,49 +780,10 @@ class Agent extends EventEmitter {
|
|
|
789
780
|
options.sessionId = ctx.sessionId;
|
|
790
781
|
}
|
|
791
782
|
|
|
792
|
-
//
|
|
793
|
-
if (this._status === 'busy') {
|
|
794
|
-
const queuedItem = { message, options, resolve: null, reject: null };
|
|
795
|
-
const promise = new Promise((resolve, reject) => {
|
|
796
|
-
queuedItem.resolve = resolve;
|
|
797
|
-
queuedItem.reject = reject;
|
|
798
|
-
});
|
|
799
|
-
this._messageQueue.push(queuedItem);
|
|
800
|
-
// Agent busy, message queued
|
|
801
|
-
return promise;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// 空闲则直接处理
|
|
783
|
+
// 直接调用 chat,由 handler 的 enqueue 处理排队
|
|
805
784
|
return this.chat(message, options);
|
|
806
785
|
}
|
|
807
786
|
|
|
808
|
-
/**
|
|
809
|
-
* 处理消息队列
|
|
810
|
-
* @private
|
|
811
|
-
*/
|
|
812
|
-
async _processQueue() {
|
|
813
|
-
if (this._isProcessingQueue || this._messageQueue.length === 0) {
|
|
814
|
-
return;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
this._isProcessingQueue = true;
|
|
818
|
-
|
|
819
|
-
// 强制设置为 idle,确保 this.chat() 能执行
|
|
820
|
-
this._status = 'idle';
|
|
821
|
-
|
|
822
|
-
while (this._messageQueue.length > 0) {
|
|
823
|
-
const item = this._messageQueue.shift();
|
|
824
|
-
try {
|
|
825
|
-
const result = await this.chat(item.message, item.options);
|
|
826
|
-
item.resolve(result);
|
|
827
|
-
} catch (err) {
|
|
828
|
-
item.reject(err);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
this._isProcessingQueue = false;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
787
|
/**
|
|
836
788
|
* 发送消息(流式)
|
|
837
789
|
*/
|
|
@@ -861,16 +813,10 @@ class Agent extends EventEmitter {
|
|
|
861
813
|
yield* this._chatHandler.chatStream(enhancedMessage, options);
|
|
862
814
|
this._status = 'idle';
|
|
863
815
|
this.emit('status', { status: 'idle' });
|
|
864
|
-
|
|
865
|
-
// 处理队列中的下一条消息
|
|
866
|
-
setImmediate(() => this._processQueue());
|
|
867
816
|
} catch (err) {
|
|
868
817
|
this._status = 'error';
|
|
869
818
|
this.emit('status', { status: 'error', error: err.message });
|
|
870
819
|
|
|
871
|
-
// 发生错误时也要处理队列
|
|
872
|
-
setImmediate(() => this._processQueue());
|
|
873
|
-
|
|
874
820
|
throw err;
|
|
875
821
|
}
|
|
876
822
|
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextManager - 上下文管理器
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 统一管理所有 Context 的生命周期
|
|
6
|
+
* 2. 提供上下文查询接口
|
|
7
|
+
* 3. 处理上下文清理和资源释放
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { RequestContext } = require('./request-context');
|
|
11
|
+
const { SessionContext } = require('./session-context');
|
|
12
|
+
const { AgentContext } = require('./agent-context');
|
|
13
|
+
|
|
14
|
+
class ContextManager {
|
|
15
|
+
/**
|
|
16
|
+
* @param {Framework} framework - 框架实例
|
|
17
|
+
*/
|
|
18
|
+
constructor(framework) {
|
|
19
|
+
this.framework = framework;
|
|
20
|
+
|
|
21
|
+
// Context 存储
|
|
22
|
+
this._requestContexts = new Map(); // requestId → RequestContext
|
|
23
|
+
this._sessionContexts = new Map(); // sessionId → SessionContext
|
|
24
|
+
this._agentContexts = new Map(); // agentId → AgentContext
|
|
25
|
+
|
|
26
|
+
// 引用计数(用于自动清理)
|
|
27
|
+
this._refCounts = new Map();
|
|
28
|
+
|
|
29
|
+
// 事件转发
|
|
30
|
+
this._setupEventForwarding();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 设置事件转发
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
_setupEventForwarding() {
|
|
38
|
+
if (this.framework) {
|
|
39
|
+
this.framework.on('session:context-created', (ctx) => {
|
|
40
|
+
// 可以在这里添加日志、监控等
|
|
41
|
+
});
|
|
42
|
+
this.framework.on('session:context-destroyed', (ctx) => {
|
|
43
|
+
// 可以在这里添加清理逻辑
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ==================== Request Context ====================
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 创建 Request Context
|
|
52
|
+
* @param {Object} options - 请求选项
|
|
53
|
+
* @returns {RequestContext}
|
|
54
|
+
*/
|
|
55
|
+
createRequestContext(options = {}) {
|
|
56
|
+
const ctx = new RequestContext(options);
|
|
57
|
+
this._requestContexts.set(ctx.requestId, ctx);
|
|
58
|
+
this._refCounts.set(`request:${ctx.requestId}`, 1);
|
|
59
|
+
return ctx;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 获取 Request Context
|
|
64
|
+
* @param {string} requestId - 请求 ID
|
|
65
|
+
* @returns {RequestContext|null}
|
|
66
|
+
*/
|
|
67
|
+
getRequestContext(requestId) {
|
|
68
|
+
return this._requestContexts.get(requestId) || null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 释放 Request Context
|
|
73
|
+
* @param {string} requestId - 请求 ID
|
|
74
|
+
*/
|
|
75
|
+
releaseRequestContext(requestId) {
|
|
76
|
+
const ctx = this._requestContexts.get(requestId);
|
|
77
|
+
if (ctx) {
|
|
78
|
+
ctx.cancel();
|
|
79
|
+
this._requestContexts.delete(requestId);
|
|
80
|
+
this._refCounts.delete(`request:${requestId}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 增加 Request Context 引用计数
|
|
86
|
+
* @param {string} requestId - 请求 ID
|
|
87
|
+
*/
|
|
88
|
+
retainRequestContext(requestId) {
|
|
89
|
+
const key = `request:${requestId}`;
|
|
90
|
+
this._refCounts.set(key, (this._refCounts.get(key) || 0) + 1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ==================== Session Context ====================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 获取或创建 Session Context
|
|
97
|
+
* @param {string} sessionId - 会话 ID
|
|
98
|
+
* @param {Object} options - 配置选项
|
|
99
|
+
* @returns {SessionContext}
|
|
100
|
+
*/
|
|
101
|
+
getOrCreateSessionContext(sessionId, options = {}) {
|
|
102
|
+
let ctx = this._sessionContexts.get(sessionId);
|
|
103
|
+
if (!ctx) {
|
|
104
|
+
ctx = new SessionContext(sessionId, this.framework, options);
|
|
105
|
+
this._sessionContexts.set(sessionId, ctx);
|
|
106
|
+
this._refCounts.set(`session:${sessionId}`, 1);
|
|
107
|
+
} else {
|
|
108
|
+
// 增加引用计数
|
|
109
|
+
const key = `session:${sessionId}`;
|
|
110
|
+
this._refCounts.set(key, (this._refCounts.get(key) || 0) + 1);
|
|
111
|
+
}
|
|
112
|
+
return ctx;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 获取 Session Context
|
|
117
|
+
* @param {string} sessionId - 会话 ID
|
|
118
|
+
* @returns {SessionContext|null}
|
|
119
|
+
*/
|
|
120
|
+
getSessionContext(sessionId) {
|
|
121
|
+
return this._sessionContexts.get(sessionId) || null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 释放 Session Context(减少引用计数)
|
|
126
|
+
* @param {string} sessionId - 会话 ID
|
|
127
|
+
* @param {boolean} [force=false] - 强制销毁
|
|
128
|
+
*/
|
|
129
|
+
releaseSessionContext(sessionId, force = false) {
|
|
130
|
+
const key = `session:${sessionId}`;
|
|
131
|
+
const count = this._refCounts.get(key) || 0;
|
|
132
|
+
|
|
133
|
+
if (force || count <= 1) {
|
|
134
|
+
const ctx = this._sessionContexts.get(sessionId);
|
|
135
|
+
if (ctx) {
|
|
136
|
+
ctx.destroy();
|
|
137
|
+
this.framework.emit('session:context-destroyed', ctx);
|
|
138
|
+
}
|
|
139
|
+
this._sessionContexts.delete(sessionId);
|
|
140
|
+
this._refCounts.delete(key);
|
|
141
|
+
} else {
|
|
142
|
+
this._refCounts.set(key, count - 1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 增加 Session Context 引用计数
|
|
148
|
+
* @param {string} sessionId - 会话 ID
|
|
149
|
+
*/
|
|
150
|
+
retainSessionContext(sessionId) {
|
|
151
|
+
const key = `session:${sessionId}`;
|
|
152
|
+
this._refCounts.set(key, (this._refCounts.get(key) || 0) + 1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 检查 Session Context 是否存在
|
|
157
|
+
* @param {string} sessionId - 会话 ID
|
|
158
|
+
* @returns {boolean}
|
|
159
|
+
*/
|
|
160
|
+
hasSessionContext(sessionId) {
|
|
161
|
+
return this._sessionContexts.has(sessionId);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ==================== Agent Context ====================
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 获取或创建 Agent Context
|
|
168
|
+
* @param {string} agentId - Agent ID
|
|
169
|
+
* @param {Agent} agent - Agent 实例
|
|
170
|
+
* @param {Object} options - 配置选项
|
|
171
|
+
* @returns {AgentContext}
|
|
172
|
+
*/
|
|
173
|
+
getOrCreateAgentContext(agentId, agent, options = {}) {
|
|
174
|
+
let ctx = this._agentContexts.get(agentId);
|
|
175
|
+
if (!ctx) {
|
|
176
|
+
ctx = new AgentContext(agentId, agent, options);
|
|
177
|
+
this._agentContexts.set(agentId, ctx);
|
|
178
|
+
}
|
|
179
|
+
return ctx;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 获取 Agent Context
|
|
184
|
+
* @param {string} agentId - Agent ID
|
|
185
|
+
* @returns {AgentContext|null}
|
|
186
|
+
*/
|
|
187
|
+
getAgentContext(agentId) {
|
|
188
|
+
return this._agentContexts.get(agentId) || null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 删除 Agent Context
|
|
193
|
+
* @param {string} agentId - Agent ID
|
|
194
|
+
*/
|
|
195
|
+
removeAgentContext(agentId) {
|
|
196
|
+
const ctx = this._agentContexts.get(agentId);
|
|
197
|
+
if (ctx) {
|
|
198
|
+
ctx.destroy();
|
|
199
|
+
this._agentContexts.delete(agentId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ==================== 批量操作 ====================
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 销毁所有 Session Context
|
|
207
|
+
*/
|
|
208
|
+
destroyAllSessionContexts() {
|
|
209
|
+
for (const [sessionId] of this._sessionContexts) {
|
|
210
|
+
this.releaseSessionContext(sessionId, true);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 清理过期的 Request Context
|
|
216
|
+
* @param {number} [maxAge=300000] - 最大存活时间(毫秒),默认 5 分钟
|
|
217
|
+
*/
|
|
218
|
+
cleanupExpiredRequests(maxAge = 300000) {
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
for (const [requestId, ctx] of this._requestContexts) {
|
|
221
|
+
if (now - ctx.startTime > maxAge) {
|
|
222
|
+
this.releaseRequestContext(requestId);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 清理所有 Context
|
|
229
|
+
*/
|
|
230
|
+
destroyAll() {
|
|
231
|
+
// 清理 Request Contexts
|
|
232
|
+
for (const [requestId] of this._requestContexts) {
|
|
233
|
+
this.releaseRequestContext(requestId);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 清理 Session Contexts
|
|
237
|
+
this.destroyAllSessionContexts();
|
|
238
|
+
|
|
239
|
+
// 清理 Agent Contexts
|
|
240
|
+
for (const [agentId] of this._agentContexts) {
|
|
241
|
+
this.removeAgentContext(agentId);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ==================== 统计 ====================
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 获取统计信息
|
|
249
|
+
* @returns {Object}
|
|
250
|
+
*/
|
|
251
|
+
getStats() {
|
|
252
|
+
return {
|
|
253
|
+
activeRequests: this._requestContexts.size,
|
|
254
|
+
activeSessions: this._sessionContexts.size,
|
|
255
|
+
activeAgents: this._agentContexts.size,
|
|
256
|
+
refCounts: Object.fromEntries(this._refCounts),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* 获取内存使用估计
|
|
262
|
+
* @returns {Object}
|
|
263
|
+
*/
|
|
264
|
+
getMemoryUsage() {
|
|
265
|
+
let sessionMessagesSize = 0;
|
|
266
|
+
let sessionVariablesSize = 0;
|
|
267
|
+
|
|
268
|
+
for (const ctx of this._sessionContexts.values()) {
|
|
269
|
+
sessionMessagesSize += ctx.messageStore.messages.length;
|
|
270
|
+
sessionVariablesSize += ctx.variables.size;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
requestContexts: this._requestContexts.size,
|
|
275
|
+
sessionContexts: this._sessionContexts.size,
|
|
276
|
+
agentContexts: this._agentContexts.size,
|
|
277
|
+
totalSessionMessages: sessionMessagesSize,
|
|
278
|
+
totalSessionVariables: sessionVariablesSize,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = { ContextManager };
|