foliko 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/docs/public-api.md +91 -0
- package/docs/system-prompt.md +219 -0
- package/docs/usage.md +6 -6
- package/package.json +1 -1
- package/plugins/ambient/ExplorerLoop.js +1 -0
- package/plugins/ambient/index.js +1 -0
- package/plugins/core/coordinator/index.js +10 -5
- package/plugins/core/default/bootstrap.js +21 -3
- package/plugins/core/default/config.js +12 -3
- package/plugins/core/python-loader/index.js +3 -3
- package/plugins/core/scheduler/index.js +26 -2
- package/plugins/core/skill-manager/index.js +198 -151
- package/plugins/core/sub-agent/index.js +34 -15
- package/plugins/core/think/index.js +1 -0
- package/plugins/core/workflow/index.js +5 -4
- package/plugins/executors/data-splitter/index.js +14 -1
- package/plugins/executors/extension/index.js +52 -38
- package/plugins/executors/python/index.js +3 -3
- package/plugins/executors/shell/index.js +6 -4
- package/plugins/io/web/index.js +2 -1
- package/plugins/memory/index.js +29 -74
- package/plugins/messaging/email/handlers.js +1 -19
- package/plugins/messaging/email/monitor.js +2 -17
- package/plugins/messaging/email/reply.js +2 -1
- package/plugins/messaging/email/utils.js +20 -1
- package/plugins/messaging/feishu/index.js +1 -1
- package/plugins/messaging/qq/index.js +1 -1
- package/plugins/messaging/telegram/index.js +1 -1
- package/plugins/messaging/weixin/index.js +1 -1
- package/plugins/plugin-manager/index.js +1 -33
- package/plugins/tools/index.js +14 -1
- package/skills/plugins/SKILL.md +316 -0
- package/skills/skill-guide/SKILL.md +5 -5
- package/skills/{subagent-guide → subagents}/SKILL.md +1 -1
- package/skills/{workflow-guide → workflows}/SKILL.md +3 -3
- package/skills/{workflow-troubleshooting → workflows/workflow-troubleshooting}/DEBUGGING.md +197 -197
- package/skills/{workflow-troubleshooting → workflows/workflow-troubleshooting}/SKILL.md +391 -391
- package/src/agent/base.js +5 -20
- package/src/agent/chat.js +67 -5
- package/src/agent/index.js +20 -8
- package/src/agent/main.js +100 -23
- package/src/agent/prompt-registry.js +296 -0
- package/src/agent/sub-config.js +1 -78
- package/src/agent/sub.js +20 -25
- package/src/cli/commands/plugin.js +1 -60
- package/src/cli/ui/chat-ui-old.js +1 -1
- package/src/cli/ui/chat-ui.js +21 -17
- package/src/cli/ui/components/agent-mention-provider.js +1 -1
- package/src/common/constants.js +42 -0
- package/src/common/id.js +13 -0
- package/src/common/queue.js +3 -3
- package/src/context/compressor.js +17 -9
- package/src/framework/framework.js +218 -0
- package/src/framework/index.js +1 -2
- package/src/framework/lifecycle.js +102 -1
- package/src/framework/loader.js +1 -55
- package/src/index.js +11 -2
- package/src/plugin/base.js +69 -55
- package/src/plugin/loader.js +1 -57
- package/src/session/chat.js +1 -1
- package/src/session/entry.js +1 -11
- package/src/storage/manager.js +1 -12
- package/src/tool/executor.js +3 -2
- package/src/tool/router.js +5 -5
- package/src/utils/data-splitter.js +2 -1
- package/src/utils/index.js +150 -0
- package/src/utils/message-validator.js +21 -17
- package/src/utils/plugin-helpers.js +19 -5
- package/subagent.md +2 -2
- package/tests/core/plugin-prompts.test.js +219 -0
- package/tests/core/prompt-registry.test.js +209 -0
- package/src/cli/utils/plugin-config.js +0 -50
- package/src/config/plugin-config.js +0 -50
- /package/skills/{ambient-agent → ambient}/SKILL.md +0 -0
- /package/skills/{foliko-dev → foliko}/AGENTS.md +0 -0
- /package/skills/{foliko-dev → foliko}/SKILL.md +0 -0
- /package/skills/{mcp-usage → mcp}/SKILL.md +0 -0
- /package/skills/{plugin-guide → plugins-guide}/SKILL.md +0 -0
- /package/skills/{python-plugin-dev → python}/SKILL.md +0 -0
package/src/agent/base.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* BaseAgent - 所有 Agent 类型的公共基类
|
|
5
|
-
* 提供事件、状态、prompt
|
|
5
|
+
* 提供事件、状态、prompt 等公共功能
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const { EventEmitter } = require('../common/events');
|
|
9
|
-
const {
|
|
9
|
+
const { PromptRegistry } = require('./prompt-registry');
|
|
10
10
|
|
|
11
11
|
class BaseAgent extends EventEmitter {
|
|
12
12
|
constructor(framework, config = {}) {
|
|
@@ -15,7 +15,9 @@ class BaseAgent extends EventEmitter {
|
|
|
15
15
|
this.config = config;
|
|
16
16
|
this.name = config.name || 'Agent';
|
|
17
17
|
this._status = 'idle';
|
|
18
|
-
|
|
18
|
+
// Agent 私有的 prompt 注册表(新 API)
|
|
19
|
+
this._promptRegistry = new PromptRegistry();
|
|
20
|
+
this.promptRegistry = this._promptRegistry;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
// === Status ===
|
|
@@ -28,23 +30,6 @@ class BaseAgent extends EventEmitter {
|
|
|
28
30
|
return this;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
// === Prompt Parts ===
|
|
32
|
-
|
|
33
|
-
registerPromptPart(name, priority, provider) {
|
|
34
|
-
this._promptBuilder.register(name, priority, provider);
|
|
35
|
-
return this;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
unregisterPromptPart(name) {
|
|
39
|
-
this._promptBuilder.unregister(name);
|
|
40
|
-
return this;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
invalidatePromptPart(name) {
|
|
44
|
-
this._promptBuilder.invalidate(name);
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
33
|
// === Destroy ===
|
|
49
34
|
|
|
50
35
|
destroy() {
|
package/src/agent/chat.js
CHANGED
|
@@ -473,7 +473,7 @@ class AgentChatHandler extends EventEmitter {
|
|
|
473
473
|
const { messageStore, messages } = await this._prepareSession(message, sessionId);
|
|
474
474
|
|
|
475
475
|
if (!this._aiClient) {
|
|
476
|
-
throw new Error('AI
|
|
476
|
+
throw new Error('AI 客户端未配置');
|
|
477
477
|
}
|
|
478
478
|
this._validateToolCalls(messages);
|
|
479
479
|
const systemPrompt = framework.getSystemPrompt();
|
|
@@ -497,7 +497,12 @@ class AgentChatHandler extends EventEmitter {
|
|
|
497
497
|
let reasoningContent = '';
|
|
498
498
|
|
|
499
499
|
const result = await framework.runInSession(sessionId, {}, async () => {
|
|
500
|
-
return agent.stream({
|
|
500
|
+
return agent.stream({
|
|
501
|
+
messages,
|
|
502
|
+
...this.providerOptions,
|
|
503
|
+
onError: handleSDKError,
|
|
504
|
+
abortSignal: framework.getAbortSignal?.(),
|
|
505
|
+
});
|
|
501
506
|
});
|
|
502
507
|
|
|
503
508
|
const stream = result.fullStream;
|
|
@@ -595,7 +600,10 @@ class AgentChatHandler extends EventEmitter {
|
|
|
595
600
|
// 统一错误处理:提取简洁消息并通过 yield 传递
|
|
596
601
|
const friendlyMessage = err?.message?.split('\n')[0] || '未知错误';
|
|
597
602
|
|
|
598
|
-
|
|
603
|
+
// 用户主动中断(framework.stop())不上报 message:error,避免与上游重复
|
|
604
|
+
if (err.name !== 'AbortError') {
|
|
605
|
+
this.emit('message:error', { sessionId, error: friendlyMessage, originalError: err });
|
|
606
|
+
}
|
|
599
607
|
yield { type: 'error', error: friendlyMessage };
|
|
600
608
|
} finally {
|
|
601
609
|
const messageStore = this._getSessionMessageStore(sessionId);
|
|
@@ -648,7 +656,7 @@ class AgentChatHandler extends EventEmitter {
|
|
|
648
656
|
const { messageStore, messages } = await this._prepareSession(message, sessionId);
|
|
649
657
|
|
|
650
658
|
if (!this._aiClient) {
|
|
651
|
-
throw new Error('AI
|
|
659
|
+
throw new Error('AI 客户端未配置');
|
|
652
660
|
}
|
|
653
661
|
this._validateToolCalls(messages);
|
|
654
662
|
const systemPrompt = framework.getSystemPrompt();
|
|
@@ -669,7 +677,7 @@ class AgentChatHandler extends EventEmitter {
|
|
|
669
677
|
});
|
|
670
678
|
|
|
671
679
|
const result = await framework.runInSession(sessionId, {}, async () => {
|
|
672
|
-
return agent.generate({ messages, ...apiOptions });
|
|
680
|
+
return agent.generate({ messages, ...apiOptions, abortSignal: framework.getAbortSignal?.() });
|
|
673
681
|
});
|
|
674
682
|
|
|
675
683
|
if (result.usage && (result.usage.promptTokens > 0 || result.usage.completionTokens > 0)) {
|
|
@@ -780,6 +788,9 @@ class AgentChatHandler extends EventEmitter {
|
|
|
780
788
|
messages.push(userMessage);
|
|
781
789
|
this._validateToolCalls(messages);
|
|
782
790
|
|
|
791
|
+
// 最终兜底:暴力清理所有 orphaned tool 消息,确保 AI SDK 不报错
|
|
792
|
+
this._stripOrphanedToolMessages(messages);
|
|
793
|
+
|
|
783
794
|
return { messageStore, messages };
|
|
784
795
|
}
|
|
785
796
|
|
|
@@ -832,6 +843,57 @@ class AgentChatHandler extends EventEmitter {
|
|
|
832
843
|
messageStore._cacheMessageCount = messageStore.messages.length;
|
|
833
844
|
}
|
|
834
845
|
|
|
846
|
+
/**
|
|
847
|
+
* 最终兜底:暴力清理所有 orphaned tool 消息
|
|
848
|
+
* 遍历所有 tool 角色消息,删除没有对应 tool-call 的
|
|
849
|
+
* 处理数组格式(AI SDK)、字符串格式(OpenAI 兼容)、tool_call_id 格式
|
|
850
|
+
*/
|
|
851
|
+
_stripOrphanedToolMessages(messages) {
|
|
852
|
+
const validIds = new Set();
|
|
853
|
+
for (const msg of messages) {
|
|
854
|
+
if (msg.role !== 'assistant') continue;
|
|
855
|
+
if (Array.isArray(msg.content)) {
|
|
856
|
+
for (const item of msg.content) {
|
|
857
|
+
if ((item.type === 'tool-call' || item.type === 'tool-use') && item.toolCallId) validIds.add(item.toolCallId);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
if (Array.isArray(msg.tool_calls)) {
|
|
861
|
+
for (const tc of msg.tool_calls) { if (tc.id) validIds.add(tc.id); }
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
let removed = 0;
|
|
866
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
867
|
+
const msg = messages[i];
|
|
868
|
+
if (msg.role !== 'tool') continue;
|
|
869
|
+
|
|
870
|
+
let isOrphaned = false;
|
|
871
|
+
if (Array.isArray(msg.content)) {
|
|
872
|
+
msg.content = msg.content.filter(item => {
|
|
873
|
+
if (item && (item.type === 'tool-result' || item.type === 'tool_result') && item.toolCallId && !validIds.has(item.toolCallId)) {
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
return true;
|
|
877
|
+
});
|
|
878
|
+
if (msg.content.length === 0) isOrphaned = true;
|
|
879
|
+
} else if (msg.tool_call_id && !validIds.has(msg.tool_call_id)) {
|
|
880
|
+
isOrphaned = true;
|
|
881
|
+
} else if (!msg.tool_call_id && validIds.size === 0) {
|
|
882
|
+
// 没有任何 tool-call,所有 tool 消息都是 orphaned
|
|
883
|
+
isOrphaned = true;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (isOrphaned) {
|
|
887
|
+
messages.splice(i, 1);
|
|
888
|
+
removed++;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
if (removed > 0) {
|
|
893
|
+
logger.debug(`[_stripOrphanedToolMessages] removed ${removed} orphaned tool message(s)`);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
835
897
|
/**
|
|
836
898
|
* 计算工具列表缓存 key
|
|
837
899
|
* @private
|
package/src/agent/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const { MainAgent } = require('./main');
|
|
|
5
5
|
const { SubAgent } = require('./sub');
|
|
6
6
|
const { WorkerAgent } = require('./worker');
|
|
7
7
|
const { SystemPromptBuilder } = require('./prompt');
|
|
8
|
+
const { PromptRegistry } = require('./prompt-registry');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Create a MainAgent instance
|
|
@@ -51,6 +52,7 @@ function createSubAgent(framework, config = {}) {
|
|
|
51
52
|
framework,
|
|
52
53
|
maxRetries: config.maxRetries,
|
|
53
54
|
disableTools: config.disableTools,
|
|
55
|
+
hidden: config.hidden,
|
|
54
56
|
});
|
|
55
57
|
_syncPromptParts(framework, subagent);
|
|
56
58
|
framework._agents.push(subagent);
|
|
@@ -84,16 +86,25 @@ function _mergeAIConfig(framework, target) {
|
|
|
84
86
|
|
|
85
87
|
/**
|
|
86
88
|
* Sync main agent prompt parts to subagent
|
|
89
|
+
* 从 framework.promptRegistry 同步到 subagent.promptRegistry
|
|
87
90
|
*/
|
|
88
91
|
function _syncPromptParts(framework, subagent) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
for (const
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
const reg = framework?.promptRegistry;
|
|
93
|
+
if (!reg || reg.count() === 0) return;
|
|
94
|
+
const subReg = subagent?.promptRegistry || subagent?._promptRegistry;
|
|
95
|
+
for (const part of reg.list()) {
|
|
96
|
+
// 跳过主 Agent 私有的 5 个内置 part
|
|
97
|
+
if (part.owner === '_main' && ['original-prompt', 'shared-prompt', 'datetime', 'metadata', 'capabilities'].includes(part.name)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// 已同步过则跳过
|
|
101
|
+
if (subReg && subReg.has(part.owner, part.name)) continue;
|
|
102
|
+
if (subReg) {
|
|
103
|
+
subReg.register(part.owner, part.name, part.provider, {
|
|
104
|
+
slot: part.slot,
|
|
105
|
+
order: part.order,
|
|
106
|
+
description: part.description,
|
|
107
|
+
});
|
|
97
108
|
}
|
|
98
109
|
}
|
|
99
110
|
}
|
|
@@ -104,6 +115,7 @@ module.exports = {
|
|
|
104
115
|
SubAgent,
|
|
105
116
|
WorkerAgent,
|
|
106
117
|
SystemPromptBuilder,
|
|
118
|
+
PromptRegistry,
|
|
107
119
|
createAgent,
|
|
108
120
|
createSubAgent,
|
|
109
121
|
createSessionAgent,
|
package/src/agent/main.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const { BaseAgent } = require('./base');
|
|
9
9
|
const { Logger, LOG_LEVELS } = require('../common/logger');
|
|
10
|
-
const { PROMPT_PRIORITY, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_TEMPERATURE } = require('../common/constants');
|
|
10
|
+
const { PROMPT_PRIORITY, PROMPT_PRIORITY_TO_SLOT, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_TEMPERATURE } = require('../common/constants');
|
|
11
11
|
const { SystemPromptBuilder } = require('./prompt');
|
|
12
12
|
const os = require('os');
|
|
13
13
|
|
|
@@ -44,6 +44,10 @@ class MainAgent extends BaseAgent {
|
|
|
44
44
|
this._skipSyncTools = config.skipSyncTools || false;
|
|
45
45
|
this._subAgents = new Map();
|
|
46
46
|
this._systemPromptBuilder = new SystemPromptBuilder();
|
|
47
|
+
this._systemPromptCache = null; // 确保首次调用 _buildSystemPrompt 不走早期返回
|
|
48
|
+
this._systemPromptDirty = true;
|
|
49
|
+
// 新注册表:默认 part 注册到 framework.promptRegistry(带 slot)
|
|
50
|
+
// _systemPromptBuilder 保留为降级兜底
|
|
47
51
|
this._registerDefaultPromptParts();
|
|
48
52
|
this.systemPrompt = this._buildSystemPrompt();
|
|
49
53
|
|
|
@@ -54,25 +58,48 @@ class MainAgent extends BaseAgent {
|
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
_registerDefaultPromptParts() {
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
// 优先注册到 framework.promptRegistry(带 slot 的新路径)
|
|
62
|
+
// 同时保留 _systemPromptBuilder 的旧路径以兼容老 Plugin.registerPromptPart
|
|
63
|
+
const reg = this.framework?.promptRegistry;
|
|
64
|
+
const MAIN = '_main';
|
|
65
|
+
|
|
66
|
+
const registerBoth = (name, priority, provider, slot) => {
|
|
67
|
+
// 旧路径(降级兜底)
|
|
68
|
+
this._systemPromptBuilder.register(name, priority, provider);
|
|
69
|
+
// 新路径(slot 排序)
|
|
70
|
+
// original-prompt 是 per-Agent 的,不走全局注册表(由 _buildSystemPrompt 直接注入)
|
|
71
|
+
if (name === 'original-prompt') return;
|
|
72
|
+
if (reg && !reg.has(MAIN, name)) {
|
|
73
|
+
reg.register(MAIN, name, provider, {
|
|
74
|
+
slot: slot || PROMPT_PRIORITY_TO_SLOT[name] || 'CUSTOM',
|
|
75
|
+
order: priority,
|
|
76
|
+
description: `内置 part: ${name}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
registerBoth('original-prompt', PROMPT_PRIORITY.ORIGINAL_PROMPT, () => this._originalPrompt, 'IDENTITY');
|
|
82
|
+
registerBoth('shared-prompt', PROMPT_PRIORITY.SHARED_PROMPT, () => {
|
|
59
83
|
return this._sharedPrompt ? this._replacePlaceholders(this._sharedPrompt) : null;
|
|
60
|
-
});
|
|
61
|
-
|
|
84
|
+
}, 'USER');
|
|
85
|
+
registerBoth('metadata', PROMPT_PRIORITY.METADATA, () => {
|
|
62
86
|
const now = new Date();
|
|
63
87
|
const timeStr = now.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
|
|
64
88
|
const dateStr = now.toLocaleDateString('zh-CN', { timeZone: 'Asia/Shanghai', weekday: 'long' });
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
const metaParts = ['【运行环境】'];
|
|
90
|
+
metaParts.push(`- 当前时间: ${timeStr}(${dateStr})`);
|
|
91
|
+
metaParts.push(`- 工作目录: ${this.framework?.getCwd?.() ?? process.cwd()}`);
|
|
92
|
+
metaParts.push(`- 平台: ${os.platform()} ${os.release()}`);
|
|
93
|
+
metaParts.push(`- 主机: ${os.hostname()}`);
|
|
94
|
+
// 插件显式设置的元数据
|
|
95
|
+
if (this._metadata.size > 0) {
|
|
96
|
+
for (const [key, value] of this._metadata) {
|
|
97
|
+
metaParts.push(`- ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}`);
|
|
98
|
+
}
|
|
72
99
|
}
|
|
73
100
|
return metaParts.join('\n');
|
|
74
|
-
});
|
|
75
|
-
|
|
101
|
+
}, 'USER');
|
|
102
|
+
registerBoth('capabilities', PROMPT_PRIORITY.CAPABILITIES, () => this._buildCapabilitiesDescription(), 'CAPABILITY');
|
|
76
103
|
}
|
|
77
104
|
|
|
78
105
|
_getMetadataValue(key) {
|
|
@@ -97,18 +124,59 @@ class MainAgent extends BaseAgent {
|
|
|
97
124
|
if (!plugins || plugins.length === 0) return '';
|
|
98
125
|
const keyPlugins = plugins.filter(p => p.name !== 'defaults' && p.name !== 'agent');
|
|
99
126
|
if (keyPlugins.length === 0) return '';
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
127
|
+
|
|
128
|
+
// 按类别分组,输出紧凑列表(工具列表已在 API 层描述,这里仅给出概览)
|
|
129
|
+
// const categories = {
|
|
130
|
+
// core: [], executor: [], io: [], messaging: [], other: [],
|
|
131
|
+
// };
|
|
132
|
+
// const catMap = {
|
|
133
|
+
// ai: 'core', storage: 'core', 'skill-manager': 'core', 'subagent-manager': 'core',
|
|
134
|
+
// session: 'core', scheduler: 'core', workflow: 'core', rules: 'core', audit: 'core',
|
|
135
|
+
// tools: 'core', 'plugin-manager': 'core', install: 'core', 'python-loader': 'core',
|
|
136
|
+
// 'data-splitter': 'core', coordinator: 'core',
|
|
137
|
+
// shell: 'executor', python: 'executor', extension: 'executor', mcp: 'executor',
|
|
138
|
+
// 'file-system': 'io', web: 'io',
|
|
139
|
+
// telegram: 'messaging', qq: 'messaging', weixin: 'messaging', feishu: 'messaging', email: 'messaging',
|
|
140
|
+
// };
|
|
141
|
+
// for (const p of keyPlugins) {
|
|
142
|
+
// const name = p.instance?.name || p.name || 'unknown';
|
|
143
|
+
// const cat = catMap[name] || 'other';
|
|
144
|
+
// categories[cat].push(name);
|
|
145
|
+
// }
|
|
146
|
+
const lines = [];
|
|
147
|
+
// const lines = ['## 插件概览'];
|
|
148
|
+
// const catLabels = { core: '核心', executor: '执行器', io: '文件/网络', messaging: '消息', other: '其他' };
|
|
149
|
+
// for (const [cat, names] of Object.entries(categories)) {
|
|
150
|
+
// if (names.length === 0) continue;
|
|
151
|
+
// lines.push(`- **${catLabels[cat]}**: ${names.sort().join(', ')}`);
|
|
152
|
+
// }
|
|
106
153
|
return lines.join('\n');
|
|
107
154
|
}
|
|
108
155
|
|
|
109
156
|
_buildSystemPrompt() {
|
|
110
157
|
if (!this._systemPromptDirty && this._systemPromptCache !== null) return this._systemPromptCache;
|
|
111
|
-
|
|
158
|
+
|
|
159
|
+
// 1. Agent 自己的 originalPrompt(per-Agent)
|
|
160
|
+
const parts = [this._originalPrompt];
|
|
161
|
+
|
|
162
|
+
// 2. 全局注册表(skills, tools, extensions 等共享部分,跳过 _main 的 original-prompt)
|
|
163
|
+
const reg = this.framework?.promptRegistry;
|
|
164
|
+
if (reg && reg.count() > 0) {
|
|
165
|
+
try {
|
|
166
|
+
for (const part of reg.list()) {
|
|
167
|
+
if (part.owner === '_main' && part.name === 'original-prompt') continue;
|
|
168
|
+
const content = part.get();
|
|
169
|
+
if (content && content.trim()) parts.push(content.trim());
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
// 注册表 build 失败时降级到旧 builder
|
|
173
|
+
this._systemPromptCache = this._systemPromptBuilder.build();
|
|
174
|
+
this._systemPromptDirty = false;
|
|
175
|
+
return this._systemPromptCache;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this._systemPromptCache = parts.join('\n\n');
|
|
112
180
|
this._systemPromptDirty = false;
|
|
113
181
|
return this._systemPromptCache;
|
|
114
182
|
}
|
|
@@ -116,6 +184,7 @@ class MainAgent extends BaseAgent {
|
|
|
116
184
|
_invalidateSystemPromptCache() {
|
|
117
185
|
this._systemPromptDirty = true;
|
|
118
186
|
this._systemPromptBuilder.invalidateAll();
|
|
187
|
+
this.framework?.promptRegistry?.invalidateAll();
|
|
119
188
|
}
|
|
120
189
|
|
|
121
190
|
_refreshContext() {
|
|
@@ -158,14 +227,22 @@ class MainAgent extends BaseAgent {
|
|
|
158
227
|
}
|
|
159
228
|
|
|
160
229
|
registerPromptPart(name, priority, provider) {
|
|
161
|
-
|
|
230
|
+
// [DEPRECATED] 推荐使用 framework.prompts.register(this.name, ...)
|
|
231
|
+
const reg = this.framework?.promptRegistry;
|
|
232
|
+
if (reg && !reg.has(this.name, name)) {
|
|
233
|
+
reg.register(this.name, name, provider, {
|
|
234
|
+
slot: PROMPT_PRIORITY_TO_SLOT[name] || 'CUSTOM',
|
|
235
|
+
order: priority,
|
|
236
|
+
description: `Legacy registerPromptPart from ${this.name}`,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
162
239
|
this._invalidateSystemPromptCache();
|
|
163
240
|
this._refreshContext();
|
|
164
241
|
return this;
|
|
165
242
|
}
|
|
166
243
|
|
|
167
244
|
unregisterPromptPart(name) {
|
|
168
|
-
this.
|
|
245
|
+
this.framework?.promptRegistry?.unregister(this.name, name);
|
|
169
246
|
this._invalidateSystemPromptCache();
|
|
170
247
|
this._refreshContext();
|
|
171
248
|
return this;
|