foliko 1.1.73 → 1.1.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.
- package/.claude/settings.local.json +5 -1
- package/.dockerignore +45 -45
- package/.env.example +56 -56
- package/cli/src/ui/chat-ui.js +56 -126
- package/cli/src/ui/components/agent-mention-provider.js +175 -0
- package/cli/src/ui/components/chained-autocomplete-provider.js +64 -0
- package/cli/src/ui/{footer-bar.js → components/footer-bar.js} +2 -2
- package/docker-compose.yml +33 -33
- package/docs/features.md +120 -120
- package/docs/quick-reference.md +160 -160
- package/package.json +1 -1
- package/plugins/ai-plugin.js +3 -3
- package/plugins/ambient-agent/ExplorerLoop.js +17 -17
- package/plugins/ambient-agent/index.js +2 -2
- package/plugins/data-splitter-plugin.js +9 -9
- package/plugins/default-plugins.js +7 -8
- package/plugins/extension-executor-plugin.js +2 -2
- package/plugins/feishu-plugin.js +5 -5
- package/plugins/install-plugin.js +4 -4
- package/plugins/memory-plugin.js +1 -1
- package/plugins/plugin-manager-plugin.js +9 -8
- package/plugins/python-plugin-loader.js +2 -2
- package/plugins/qq-plugin.js +4 -4
- package/plugins/rules-plugin.js +2 -2
- package/plugins/scheduler-plugin.js +13 -13
- package/plugins/session-plugin.js +2 -2
- package/plugins/subagent-plugin.js +1 -1
- package/plugins/telegram-plugin.js +6 -6
- package/plugins/think-plugin.js +4 -4
- package/plugins/tools-plugin.js +1 -1
- package/plugins/web-plugin.js +16 -16
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/foliko-dev/AGENTS.md +236 -236
- package/skills/mcp-usage/SKILL.md +200 -200
- package/skills/subagent-guide/SKILL.md +237 -237
- package/skills/workflow-guide/SKILL.md +646 -646
- package/src/capabilities/skill-manager.js +6 -5
- package/src/capabilities/workflow-engine.js +5 -5
- package/src/core/agent-chat.js +8 -8
- package/src/core/agent.js +80 -5
- package/src/core/branch-summary-auto.js +4 -4
- package/src/core/chat-session.js +1 -0
- package/src/core/session-entry.js +14 -6
- package/src/core/session-manager.js +15 -3
- package/src/executors/mcp-executor.js +21 -25
- package/src/utils/data-splitter.js +3 -3
- package/src/utils/message-validator.js +1 -1
- package/website_v2/styles/animations.css +7 -7
- package/.cli_default_systemPrompt.md +0 -242
- /package/cli/src/ui/{message-bubble.js → components/message-bubble.js} +0 -0
- /package/cli/src/ui/{status-bar.js → components/status-bar.js} +0 -0
|
@@ -247,6 +247,7 @@ class Skill {
|
|
|
247
247
|
sessionId: framework?._currentSessionId || 'unknown',
|
|
248
248
|
agent: null,
|
|
249
249
|
framework: framework,
|
|
250
|
+
cwd: process.cwd(), // 工作目录,用于路径解析
|
|
250
251
|
};
|
|
251
252
|
// 支持 argumentParser 先解析参数
|
|
252
253
|
let parsedArgs = toolArgs.args || '';
|
|
@@ -267,7 +268,7 @@ class Skill {
|
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
if (this._commands.length > 0) {
|
|
270
|
-
log.info(`[${skillName}] Registered ${this._commands.length} commands: ${this._commands.join(', ')}`);
|
|
271
|
+
// log.info(`[${skillName}] Registered ${this._commands.length} commands: ${this._commands.join(', ')}`);
|
|
271
272
|
}
|
|
272
273
|
} catch (err) {
|
|
273
274
|
log.warn(`Failed to load commands from ${indexPath}:`, err.message);
|
|
@@ -558,7 +559,7 @@ class SkillManagerPlugin extends Plugin {
|
|
|
558
559
|
// 2. 扫描插件目录下的 SKILL.md
|
|
559
560
|
this._loadSkillsFromPlugins();
|
|
560
561
|
|
|
561
|
-
log.info(` Loaded ${this._skills.size} skills`);
|
|
562
|
+
// log.info(` Loaded ${this._skills.size} skills`);
|
|
562
563
|
this._loaded = true;
|
|
563
564
|
}
|
|
564
565
|
|
|
@@ -603,7 +604,7 @@ class SkillManagerPlugin extends Plugin {
|
|
|
603
604
|
|
|
604
605
|
try {
|
|
605
606
|
this._loadSkillFromFile(skillName, skillMdPath, pluginDir);
|
|
606
|
-
log.info(` Loaded skill from plugin '${pluginName}': ${skillName}`);
|
|
607
|
+
// log.info(` Loaded skill from plugin '${pluginName}': ${skillName}`);
|
|
607
608
|
} catch (err) {
|
|
608
609
|
log.warn(` Failed to load skill from plugin '${pluginName}':`, err.message);
|
|
609
610
|
}
|
|
@@ -748,7 +749,7 @@ class SkillManagerPlugin extends Plugin {
|
|
|
748
749
|
|
|
749
750
|
const refsInfo = references.size > 0 ? `, ${references.size} refs` : '';
|
|
750
751
|
const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : '';
|
|
751
|
-
|
|
752
|
+
//// log.info(` Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
|
|
752
753
|
}
|
|
753
754
|
|
|
754
755
|
/**
|
|
@@ -921,7 +922,7 @@ class SkillManagerPlugin extends Plugin {
|
|
|
921
922
|
}
|
|
922
923
|
|
|
923
924
|
reload(framework) {
|
|
924
|
-
log.info(' Reloading...');
|
|
925
|
+
// log.info(' Reloading...');
|
|
925
926
|
this._skills.clear();
|
|
926
927
|
this._loaded = false;
|
|
927
928
|
this._framework = framework;
|
|
@@ -884,7 +884,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
884
884
|
const dir = path.resolve(process.cwd(), this._workflowsDir);
|
|
885
885
|
if (!fs.existsSync(dir)) {
|
|
886
886
|
fs.mkdirSync(dir, { recursive: true });
|
|
887
|
-
log.info(` Created workflows directory: ${dir}`);
|
|
887
|
+
// log.info(` Created workflows directory: ${dir}`);
|
|
888
888
|
return;
|
|
889
889
|
}
|
|
890
890
|
try {
|
|
@@ -911,7 +911,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
911
911
|
}
|
|
912
912
|
if (workflowDef && workflowDef.steps) {
|
|
913
913
|
this._workflows.set(workflowName, workflowDef);
|
|
914
|
-
|
|
914
|
+
//// log.info(` Loaded: ${workflowName}`)
|
|
915
915
|
}
|
|
916
916
|
} catch (err) {
|
|
917
917
|
log.error(` Failed to load ${file}:`, err.message);
|
|
@@ -946,7 +946,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
946
946
|
},
|
|
947
947
|
});
|
|
948
948
|
this._workflowTools.set(name, toolName);
|
|
949
|
-
log.info(` Registered tool: ${toolName}`);
|
|
949
|
+
// log.info(` Registered tool: ${toolName}`);
|
|
950
950
|
}
|
|
951
951
|
}
|
|
952
952
|
/**
|
|
@@ -958,7 +958,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
958
958
|
if (require.cache[modulePath]) {
|
|
959
959
|
delete require.cache[modulePath];
|
|
960
960
|
}
|
|
961
|
-
log.info(' Reloading...');
|
|
961
|
+
// log.info(' Reloading...');
|
|
962
962
|
this._framework = framework;
|
|
963
963
|
// 重新创建 engine(确保使用最新代码)
|
|
964
964
|
this._engine = new (require('./src/capabilities/workflow-engine').WorkflowEngine)(framework);
|
|
@@ -1012,7 +1012,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
1012
1012
|
// 重新加载
|
|
1013
1013
|
this._loadWorkflows();
|
|
1014
1014
|
this._registerWorkflowTools();
|
|
1015
|
-
log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
|
|
1015
|
+
// log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
|
|
1016
1016
|
}
|
|
1017
1017
|
/**
|
|
1018
1018
|
* 执行工作流
|
package/src/core/agent-chat.js
CHANGED
|
@@ -753,12 +753,12 @@ class AgentChatHandler extends EventEmitter {
|
|
|
753
753
|
const totalTokens = cachedMsgTokens + toolsTokens + systemPromptTokens;
|
|
754
754
|
const limit = this._maxContextTokens * 0.5;
|
|
755
755
|
|
|
756
|
-
logger.info(`BEFORE: messages=${messages.length}, tokens=${totalTokens}/${limit}`);
|
|
756
|
+
// logger.info(`BEFORE: messages=${messages.length}, tokens=${totalTokens}/${limit}`);
|
|
757
757
|
|
|
758
758
|
if (totalTokens > limit || messages.length > 100) {
|
|
759
|
-
logger.info(
|
|
760
|
-
|
|
761
|
-
);
|
|
759
|
+
// logger.info(
|
|
760
|
+
// `Context large (${messages.length} msgs, ${totalTokens}/${this._maxContextTokens} tokens), compressing...`
|
|
761
|
+
// );
|
|
762
762
|
await this._compressContext(sessionId, messages, messageStore);
|
|
763
763
|
// 压缩后消息被截断/替换,缓存已失效,下次 _getCachedMessageTokens 会重新计算
|
|
764
764
|
this._invalidateMessageTokensCache(messageStore);
|
|
@@ -863,7 +863,7 @@ class AgentChatHandler extends EventEmitter {
|
|
|
863
863
|
|
|
864
864
|
// 执行工具
|
|
865
865
|
this.emit('tool-call', { name: toolName, args: cleanedArgs });
|
|
866
|
-
logger.info(`[Tool] Call: ${toolName}`);
|
|
866
|
+
// logger.info(`[Tool] Call: ${toolName}`);
|
|
867
867
|
try {
|
|
868
868
|
const result = await toolDef.execute(cleanedArgs, this.agent.framework);
|
|
869
869
|
|
|
@@ -874,9 +874,9 @@ class AgentChatHandler extends EventEmitter {
|
|
|
874
874
|
const splitCheck = await autoSplitToolResult(toolName, result, this.agent.framework);
|
|
875
875
|
if (splitCheck.wasSplit && splitCheck.result) {
|
|
876
876
|
finalResult = splitCheck.result;
|
|
877
|
-
logger.info(
|
|
878
|
-
|
|
879
|
-
);
|
|
877
|
+
// logger.info(
|
|
878
|
+
// `[AutoSplit] 工具 "${toolName}" 结果过大,已自动分拆处理`
|
|
879
|
+
// );
|
|
880
880
|
}
|
|
881
881
|
} catch (splitErr) {
|
|
882
882
|
// 分拆失败不阻断主流程,继续使用原始结果
|
package/src/core/agent.js
CHANGED
|
@@ -674,13 +674,88 @@ class Agent extends EventEmitter {
|
|
|
674
674
|
}
|
|
675
675
|
|
|
676
676
|
/**
|
|
677
|
-
*
|
|
677
|
+
* 清空对话历史(所有存储层)
|
|
678
|
+
* @param {string} sessionId
|
|
678
679
|
*/
|
|
679
|
-
|
|
680
|
-
if (this._chatHandler)
|
|
681
|
-
|
|
680
|
+
clearContext(sessionId) {
|
|
681
|
+
if (!sessionId || !this._chatHandler) return;
|
|
682
|
+
|
|
683
|
+
this._chatHandler._chatSession?.clearSessionMessages(sessionId, true);
|
|
684
|
+
|
|
685
|
+
const sessionCtx = this.framework?.getSessionContext(sessionId);
|
|
686
|
+
if (sessionCtx) {
|
|
687
|
+
sessionCtx.clearMessages();
|
|
688
|
+
if (sessionCtx.compressionState) sessionCtx.compressionState.count = 0;
|
|
689
|
+
if (sessionCtx.metadata) sessionCtx.metadata.compressionCount = 0;
|
|
682
690
|
}
|
|
683
|
-
|
|
691
|
+
|
|
692
|
+
// 持久化 CLEAR 标记到 SessionManager
|
|
693
|
+
const sessionManager = this.framework?._sessionContexts?.get(sessionId);
|
|
694
|
+
if (sessionManager) {
|
|
695
|
+
const { generateEntryId, EntryTypes } = require('./session-entry');
|
|
696
|
+
sessionManager._appendEntry({
|
|
697
|
+
id: generateEntryId(sessionManager.byId),
|
|
698
|
+
type: EntryTypes.SESSION_INFO,
|
|
699
|
+
info: 'context_cleared',
|
|
700
|
+
timestamp: Date.now(),
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* 压缩上下文(委托给 AgentChatHandler.ContextCompressor)
|
|
707
|
+
* @param {string} sessionId
|
|
708
|
+
* @returns {Promise<{before: number, after: number}>}
|
|
709
|
+
*/
|
|
710
|
+
async compressContext(sessionId) {
|
|
711
|
+
if (!sessionId || !this._chatHandler) {
|
|
712
|
+
throw new Error('AgentChatHandler not available');
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const chatHandler = this._chatHandler;
|
|
716
|
+
const messageStore = chatHandler._chatSession?.getSessionMessageStore(sessionId);
|
|
717
|
+
if (!messageStore) throw new Error('MessageStore not available');
|
|
718
|
+
|
|
719
|
+
messageStore.historyLoaded = false;
|
|
720
|
+
chatHandler._chatSession?.loadHistory(sessionId);
|
|
721
|
+
|
|
722
|
+
let messages = messageStore.messages;
|
|
723
|
+
const sessionCtx = this.framework?.getSessionContext(sessionId);
|
|
724
|
+
if (!messages?.length && sessionCtx) {
|
|
725
|
+
messages = sessionCtx.getMessages();
|
|
726
|
+
messageStore.messages = messages;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (!messages?.length) {
|
|
730
|
+
throw new Error('No messages to compress');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (!chatHandler._contextCompressor) {
|
|
734
|
+
throw new Error('ContextCompressor not available');
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const before = messages.length;
|
|
738
|
+
await chatHandler._contextCompressor.compress(sessionId, messages, messageStore);
|
|
739
|
+
const after = messages.length;
|
|
740
|
+
|
|
741
|
+
if (sessionCtx) sessionCtx.replaceMessages(messages);
|
|
742
|
+
|
|
743
|
+
// 持久化 COMPACTION 条目到 SessionManager
|
|
744
|
+
const sessionManager = this.framework?._sessionContexts?.get(sessionId);
|
|
745
|
+
if (sessionManager) {
|
|
746
|
+
const { generateEntryId, EntryTypes } = require('./session-entry');
|
|
747
|
+
const compactionEntry = {
|
|
748
|
+
id: generateEntryId(sessionManager.byId),
|
|
749
|
+
type: EntryTypes.COMPACTION,
|
|
750
|
+
summary: messages.find(m => m.role === 'assistant' && m.content?.startsWith('['))?.content || '',
|
|
751
|
+
firstKeptEntryId: null,
|
|
752
|
+
tokensBefore: before,
|
|
753
|
+
timestamp: Date.now(),
|
|
754
|
+
};
|
|
755
|
+
sessionManager._appendEntry(compactionEntry);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return { before, after, keepRecent: chatHandler._contextCompressor._keepRecentMessages };
|
|
684
759
|
}
|
|
685
760
|
|
|
686
761
|
/**
|
|
@@ -54,7 +54,7 @@ class BranchSummaryAuto {
|
|
|
54
54
|
return originalBranchWithSummary(branchFromId, summary, details, true);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// log.info('[BranchSummaryAuto] Attached to SessionManager');
|
|
58
58
|
return this;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -65,7 +65,7 @@ class BranchSummaryAuto {
|
|
|
65
65
|
if (this._sessionManager) {
|
|
66
66
|
// 恢复原始方法需要保存引用,但为了简单,这里只是标记
|
|
67
67
|
this._sessionManager = null;
|
|
68
|
-
|
|
68
|
+
// log.info('[BranchSummaryAuto] Detached from SessionManager');
|
|
69
69
|
}
|
|
70
70
|
return this;
|
|
71
71
|
}
|
|
@@ -142,7 +142,7 @@ class BranchSummaryAuto {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
// log.info(`[BranchSummaryAuto] Summary generated (${entries.length} entries, ${prep.totalTokens} tokens)`);
|
|
146
146
|
}
|
|
147
147
|
} catch (err) {
|
|
148
148
|
logger.error('[BranchSummaryAuto] Failed to generate summary:', err.message);
|
|
@@ -191,7 +191,7 @@ class BranchSummaryAuto {
|
|
|
191
191
|
*/
|
|
192
192
|
setEnabled(enabled) {
|
|
193
193
|
this._autoSummaryEnabled = enabled;
|
|
194
|
-
|
|
194
|
+
// log.info(`[BranchSummaryAuto] Auto summary ${enabled ? 'enabled' : 'disabled'}`);
|
|
195
195
|
return this;
|
|
196
196
|
}
|
|
197
197
|
|
package/src/core/chat-session.js
CHANGED
|
@@ -54,6 +54,8 @@ function createSessionId() {
|
|
|
54
54
|
return uuidv7();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
const MAX_SESSION_ENTRIES = 50000; // Hard limit to prevent memory issues
|
|
58
|
+
|
|
57
59
|
/**
|
|
58
60
|
* Build session context from tree path entries (for LLM)
|
|
59
61
|
*/
|
|
@@ -62,7 +64,13 @@ function buildSessionContext(pathEntries) {
|
|
|
62
64
|
let model = null;
|
|
63
65
|
let compaction = null;
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
// Guard against corrupted files with excessive entries
|
|
68
|
+
let entries = pathEntries;
|
|
69
|
+
if (pathEntries.length > MAX_SESSION_ENTRIES) {
|
|
70
|
+
entries = pathEntries.slice(-MAX_SESSION_ENTRIES);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const entry of entries) {
|
|
66
74
|
if (entry.type === EntryTypes.THINKING_LEVEL_CHANGE) {
|
|
67
75
|
thinkingLevel = entry.thinkingLevel;
|
|
68
76
|
} else if (entry.type === EntryTypes.MODEL_CHANGE) {
|
|
@@ -87,18 +95,18 @@ function buildSessionContext(pathEntries) {
|
|
|
87
95
|
|
|
88
96
|
if (compaction) {
|
|
89
97
|
messages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));
|
|
90
|
-
const compactionIdx =
|
|
98
|
+
const compactionIdx = entries.findIndex(e => e.type === EntryTypes.COMPACTION && e.id === compaction.id);
|
|
91
99
|
let foundFirstKept = false;
|
|
92
100
|
for (let i = 0; i < compactionIdx; i++) {
|
|
93
|
-
const entry =
|
|
101
|
+
const entry = entries[i];
|
|
94
102
|
if (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;
|
|
95
103
|
if (foundFirstKept) appendMessage(entry);
|
|
96
104
|
}
|
|
97
|
-
for (let i = compactionIdx + 1; i <
|
|
98
|
-
appendMessage(
|
|
105
|
+
for (let i = compactionIdx + 1; i < entries.length; i++) {
|
|
106
|
+
appendMessage(entries[i]);
|
|
99
107
|
}
|
|
100
108
|
} else {
|
|
101
|
-
for (const entry of
|
|
109
|
+
for (const entry of entries) {
|
|
102
110
|
appendMessage(entry);
|
|
103
111
|
}
|
|
104
112
|
}
|
|
@@ -125,11 +125,18 @@ class SessionManager {
|
|
|
125
125
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
126
126
|
const entries = [];
|
|
127
127
|
const lines = content.trim().split('\n');
|
|
128
|
+
const seenIds = new Set();
|
|
128
129
|
|
|
129
130
|
for (const line of lines) {
|
|
130
131
|
if (!line.trim()) continue;
|
|
131
132
|
try {
|
|
132
|
-
|
|
133
|
+
const entry = JSON.parse(line);
|
|
134
|
+
// Skip malformed entries
|
|
135
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
136
|
+
// Skip duplicate entries (same id = corrupted file)
|
|
137
|
+
if (entry.id && seenIds.has(entry.id)) continue;
|
|
138
|
+
if (entry.id) seenIds.add(entry.id);
|
|
139
|
+
entries.push(entry);
|
|
133
140
|
} catch {
|
|
134
141
|
// Skip malformed lines
|
|
135
142
|
}
|
|
@@ -409,9 +416,14 @@ class SessionManager {
|
|
|
409
416
|
|
|
410
417
|
/**
|
|
411
418
|
* Get messages (alias for buildSessionContext().messages)
|
|
419
|
+
* @param {number} [limit] - Optional limit to only return the last N messages
|
|
412
420
|
*/
|
|
413
|
-
getMessages() {
|
|
414
|
-
|
|
421
|
+
getMessages(limit) {
|
|
422
|
+
const ctx = this.buildSessionContext();
|
|
423
|
+
if (limit && limit > 0) {
|
|
424
|
+
return ctx.messages.slice(-limit);
|
|
425
|
+
}
|
|
426
|
+
return ctx.messages;
|
|
415
427
|
}
|
|
416
428
|
|
|
417
429
|
/**
|
|
@@ -90,7 +90,7 @@ class MCPClientWrapper {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
this.connected = true;
|
|
93
|
-
log.info(` Connected to ${this.serverName} with ${this.tools.length} tools`);
|
|
93
|
+
// log.info(` Connected to ${this.serverName} with ${this.tools.length} tools`);
|
|
94
94
|
} catch (err) {
|
|
95
95
|
if (controller.signal.aborted) {
|
|
96
96
|
log.error(` Connection timeout (${timeoutMs}ms) for ${this.serverName}`);
|
|
@@ -233,7 +233,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
233
233
|
if (this._config.servers) {
|
|
234
234
|
for (const serverConfig of this._config.servers) {
|
|
235
235
|
if (serverConfig.enabled === false) {
|
|
236
|
-
log.info(` Skipping disabled server: ${serverConfig.name}`);
|
|
236
|
+
// log.info(` Skipping disabled server: ${serverConfig.name}`);
|
|
237
237
|
// 保存完整配置,以便后续动态启用
|
|
238
238
|
this._serverConfigs.set(serverConfig.name, { ...serverConfig });
|
|
239
239
|
continue;
|
|
@@ -347,7 +347,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
347
347
|
}),
|
|
348
348
|
execute: async (args) => {
|
|
349
349
|
const { server, tool, args_json } = args;
|
|
350
|
-
log.info(` mcp_call: server=${server}, tool=${tool}, args_json=${args_json}`);
|
|
350
|
+
// log.info(` mcp_call: server=${server}, tool=${tool}, args_json=${args_json}`);
|
|
351
351
|
|
|
352
352
|
const clientInfo = this._clients.get(server);
|
|
353
353
|
if (!clientInfo) {
|
|
@@ -464,23 +464,23 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
464
464
|
'重新加载 MCP 服务器配置。当配置文件 .foliko/mcp_config.json 修改后使用此工具重载配置',
|
|
465
465
|
inputSchema: z.object({}),
|
|
466
466
|
execute: async () => {
|
|
467
|
-
log.info(' mcp_reload called');
|
|
467
|
+
// log.info(' mcp_reload called');
|
|
468
468
|
try {
|
|
469
469
|
const fs = require('fs');
|
|
470
470
|
const path = require('path');
|
|
471
471
|
const configPath = path.resolve('.foliko/mcp_config.json');
|
|
472
472
|
|
|
473
|
-
log.info(' Reading config from:', configPath);
|
|
473
|
+
// log.info(' Reading config from:', configPath);
|
|
474
474
|
if (!fs.existsSync(configPath)) {
|
|
475
475
|
return { success: false, error: `配置文件不存在: ${configPath}` };
|
|
476
476
|
}
|
|
477
477
|
|
|
478
478
|
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
479
479
|
const config = JSON.parse(configContent);
|
|
480
|
-
log.info(' Config loaded, reloading...');
|
|
480
|
+
// log.info(' Config loaded, reloading...');
|
|
481
481
|
|
|
482
482
|
await this.reloadConfig(config);
|
|
483
|
-
log.info(' Reload complete');
|
|
483
|
+
// log.info(' Reload complete');
|
|
484
484
|
|
|
485
485
|
return {
|
|
486
486
|
success: true,
|
|
@@ -518,13 +518,11 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
518
518
|
if (!clientInfo && serverConfig && serverConfig.enabled === false) {
|
|
519
519
|
// 服务器是被禁用的,可以尝试启用
|
|
520
520
|
}
|
|
521
|
-
log.info(
|
|
522
|
-
`[MCP] Enabling server: ${server}, clientInfo=${!!clientInfo}, serverConfig.enabled=${serverConfig?.enabled}`
|
|
523
|
-
);
|
|
521
|
+
// log.info(`[MCP] Enabling server: ${server}, clientInfo=${!!clientInfo}, serverConfig.enabled=${serverConfig?.enabled}`);
|
|
524
522
|
try {
|
|
525
523
|
if (serverConfig) {
|
|
526
524
|
const result = await this.addServer({ ...serverConfig, enabled: true });
|
|
527
|
-
log.info(`[MCP] addServer result:`, JSON.stringify(result));
|
|
525
|
+
// log.info(`[MCP] addServer result:`, JSON.stringify(result));
|
|
528
526
|
if (!result || result.success === false) {
|
|
529
527
|
this._refreshAllAgentsMCPPrompt(this._framework);
|
|
530
528
|
return result;
|
|
@@ -545,7 +543,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
545
543
|
if (!clientInfo) {
|
|
546
544
|
return { success: false, error: `MCP server '${server}' not found` };
|
|
547
545
|
}
|
|
548
|
-
log.info(` Disabling MCP server: ${server}`);
|
|
546
|
+
// log.info(` Disabling MCP server: ${server}`);
|
|
549
547
|
try {
|
|
550
548
|
clientInfo.client.close?.();
|
|
551
549
|
} catch (e) {}
|
|
@@ -1042,9 +1040,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1042
1040
|
authProvider,
|
|
1043
1041
|
enabled,
|
|
1044
1042
|
} = config;
|
|
1045
|
-
log.
|
|
1046
|
-
`[MCP] addServer called: ${name}, enabled=${enabled}, hasClient=${this._clients.has(name)}`
|
|
1047
|
-
);
|
|
1043
|
+
log.debug(`[MCP] addServer called: ${name}, enabled=${enabled}, hasClient=${this._clients.has(name)}`);
|
|
1048
1044
|
|
|
1049
1045
|
if (this._clients.has(name)) {
|
|
1050
1046
|
log.warn(` Server '${name}' already exists, skipping`);
|
|
@@ -1053,7 +1049,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1053
1049
|
|
|
1054
1050
|
// 如果 enabled === false,跳过连接(用于 mcp_set_enabled 禁用后再开启的场景)
|
|
1055
1051
|
if (enabled === false) {
|
|
1056
|
-
log.info(` Server '${name}' is disabled, skipping connection`);
|
|
1052
|
+
// log.info(` Server '${name}' is disabled, skipping connection`);
|
|
1057
1053
|
return { success: false, error: `Server '${name}' is disabled` };
|
|
1058
1054
|
}
|
|
1059
1055
|
|
|
@@ -1069,7 +1065,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1069
1065
|
authProvider,
|
|
1070
1066
|
enabled,
|
|
1071
1067
|
});
|
|
1072
|
-
log.info(` Connecting to ${name}...`);
|
|
1068
|
+
// log.info(` Connecting to ${name}...`);
|
|
1073
1069
|
let client;
|
|
1074
1070
|
try {
|
|
1075
1071
|
if (['sse', 'http'].includes(type)) {
|
|
@@ -1154,7 +1150,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1154
1150
|
enabled: config.enabled !== false,
|
|
1155
1151
|
});
|
|
1156
1152
|
|
|
1157
|
-
log.
|
|
1153
|
+
log.debug(
|
|
1158
1154
|
` Added server '${name}' with ${toolsInfo.length} tools (ext_call names: ${Object.keys(
|
|
1159
1155
|
this.tools
|
|
1160
1156
|
)
|
|
@@ -1206,7 +1202,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1206
1202
|
}
|
|
1207
1203
|
|
|
1208
1204
|
reload(framework) {
|
|
1209
|
-
log.info(' Reloading...');
|
|
1205
|
+
// log.info(' Reloading...');
|
|
1210
1206
|
this._framework = framework;
|
|
1211
1207
|
}
|
|
1212
1208
|
|
|
@@ -1215,11 +1211,11 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1215
1211
|
* @param {Object} config - 新的配置对象,包含 mcpServers
|
|
1216
1212
|
*/
|
|
1217
1213
|
async reloadConfig(config) {
|
|
1218
|
-
log.info(' reloadConfig start');
|
|
1214
|
+
// log.info(' reloadConfig start');
|
|
1219
1215
|
const newServers = config?.mcpServers || {};
|
|
1220
1216
|
|
|
1221
1217
|
// 1. 先快速清理所有旧服务器(不等待 close 完成)
|
|
1222
|
-
log.info(' Clearing old servers...');
|
|
1218
|
+
// log.info(' Clearing old servers...');
|
|
1223
1219
|
for (const [name, clientInfo] of this._clients) {
|
|
1224
1220
|
try {
|
|
1225
1221
|
// 不等待 close,直接删除
|
|
@@ -1231,10 +1227,10 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1231
1227
|
this._serverConfigs.clear();
|
|
1232
1228
|
|
|
1233
1229
|
// 2. 并行添加新服务器
|
|
1234
|
-
log.info(' Adding new servers...');
|
|
1230
|
+
// log.info(' Adding new servers...');
|
|
1235
1231
|
const addPromises = Object.entries(newServers).map(async ([name, serverConfig]) => {
|
|
1236
1232
|
if (serverConfig.enabled === false) {
|
|
1237
|
-
log.info(` Skipping disabled server: ${name}`);
|
|
1233
|
+
// log.info(` Skipping disabled server: ${name}`);
|
|
1238
1234
|
// 仍保存配置,以便后续动态启用
|
|
1239
1235
|
this._serverConfigs.set(name, { name, ...serverConfig });
|
|
1240
1236
|
return;
|
|
@@ -1254,7 +1250,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1254
1250
|
});
|
|
1255
1251
|
|
|
1256
1252
|
await Promise.all(addPromises);
|
|
1257
|
-
log.info(' reloadConfig complete');
|
|
1253
|
+
// log.info(' reloadConfig complete');
|
|
1258
1254
|
|
|
1259
1255
|
// 3. 刷新所有 agent 的 MCP 提示词
|
|
1260
1256
|
if (this._framework) {
|
|
@@ -1286,7 +1282,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
1286
1282
|
|
|
1287
1283
|
config.mcpServers[serverName].enabled = enabled;
|
|
1288
1284
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
1289
|
-
log.info(` Saved enabled=${enabled} for server '${serverName}' to config`);
|
|
1285
|
+
// log.info(` Saved enabled=${enabled} for server '${serverName}' to config`);
|
|
1290
1286
|
return true;
|
|
1291
1287
|
} catch (err) {
|
|
1292
1288
|
log.error(` Failed to save MCP config:`, err.message);
|
|
@@ -157,7 +157,7 @@ class DataSplitter {
|
|
|
157
157
|
const results = [];
|
|
158
158
|
const errors = [];
|
|
159
159
|
|
|
160
|
-
logger.
|
|
160
|
+
logger.debug(
|
|
161
161
|
`[DataSplitter] 开始分拆处理: ${totalChunks} 块, 任务="${taskDescription.slice(0, 50)}..."`
|
|
162
162
|
);
|
|
163
163
|
|
|
@@ -246,7 +246,7 @@ ${chunk.content}
|
|
|
246
246
|
// 生成汇总摘要
|
|
247
247
|
const summary = this._buildSummary(results, errors, taskDescription);
|
|
248
248
|
|
|
249
|
-
logger.
|
|
249
|
+
logger.debug(
|
|
250
250
|
`[DataSplitter] 分拆处理完成: ` +
|
|
251
251
|
`${results.filter((r) => r.success).length}/${totalChunks} 块成功, ` +
|
|
252
252
|
`${errors.length} 个错误`
|
|
@@ -277,7 +277,7 @@ ${chunk.content}
|
|
|
277
277
|
const stats = this.getContentStats(content);
|
|
278
278
|
const chunkSize = options.chunkSize || this.chunkSize;
|
|
279
279
|
|
|
280
|
-
logger.
|
|
280
|
+
logger.debug(
|
|
281
281
|
`[DataSplitter] 自动分拆: ${stats.chars} 字符, ` +
|
|
282
282
|
`约 ${stats.estimatedTokens} tokens, ` +
|
|
283
283
|
`分 ${stats.chunks} 块处理`
|
|
@@ -152,7 +152,7 @@ function validateToolCalls(messages, options = {}) {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
if (shouldLog && fixedCount > 0) {
|
|
155
|
-
logger.info(`[validateToolCalls] Fixed ${fixedCount} incomplete tool calls/results`);
|
|
155
|
+
// logger.info(`[validateToolCalls] Fixed ${fixedCount} incomplete tool calls/results`);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
return fixedCount;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/* Foliko v2 - Animations */
|
|
2
|
-
@keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
|
|
3
|
-
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
4
|
-
@keyframes glow { 0%, 100% { opacity: 0.4; transform: translateX(-50%) scale(1); } 50% { opacity: 0.7; transform: translateX(-50%) scale(1.1); } }
|
|
5
|
-
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.2); } }
|
|
6
|
-
.reveal { opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
7
|
-
.reveal.visible { opacity: 1; transform: translateY(0); }
|
|
1
|
+
/* Foliko v2 - Animations */
|
|
2
|
+
@keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
|
|
3
|
+
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
4
|
+
@keyframes glow { 0%, 100% { opacity: 0.4; transform: translateX(-50%) scale(1); } 50% { opacity: 0.7; transform: translateX(-50%) scale(1.1); } }
|
|
5
|
+
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.2); } }
|
|
6
|
+
.reveal { opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
7
|
+
.reveal.visible { opacity: 1; transform: translateY(0); }
|
|
8
8
|
|