foliko 1.1.68 → 1.1.69
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 +19 -10
- package/.dockerignore +45 -45
- package/.env.example +56 -56
- package/CLAUDE.md +2 -2
- package/README.md +13 -13
- package/SPEC.md +3 -3
- package/cli/src/commands/chat.js +2 -20
- package/cli/src/commands/list.js +7 -6
- package/cli/src/commands/plugin.js +3 -2
- package/cli/src/daemon.js +2 -2
- package/cli/src/ui/chat-ui-old.js +15 -4
- package/cli/src/ui/chat-ui.js +152 -38
- package/cli/src/ui/footer-bar.js +13 -14
- package/cli/src/utils/config.js +29 -0
- package/cli/src/utils/plugin-config.js +1 -1
- package/docker-compose.yml +33 -33
- package/docs/features.md +120 -120
- package/docs/quick-reference.md +160 -160
- package/docs/user-manual.md +1391 -1391
- package/examples/ambient-example.js +2 -2
- package/examples/bootstrap.js +3 -3
- package/examples/test-chat.js +1 -1
- package/examples/test-reload.js +1 -1
- package/examples/test-telegram.js +1 -1
- package/examples/test-tg-bot.js +1 -1
- package/examples/test-tg-simple.js +2 -2
- package/examples/test-tg.js +1 -1
- package/examples/test-think.js +1 -1
- package/examples/test-weixin-feishu.js +3 -3
- package/package.json +3 -1
- package/plugins/ambient-agent/index.js +1 -1
- package/plugins/audit-plugin.js +75 -24
- package/plugins/default-plugins.js +21 -11
- package/plugins/email/index.js +1 -1
- package/plugins/extension-executor-plugin.js +85 -7
- package/plugins/feishu-plugin.js +118 -16
- package/plugins/install-plugin.js +4 -4
- package/plugins/memory-plugin.js +1 -1
- package/plugins/plugin-manager-plugin.js +3 -3
- package/plugins/python-executor-plugin.js +1 -1
- package/plugins/python-plugin-loader.js +1 -1
- package/plugins/qq-plugin.js +143 -16
- package/plugins/rules-plugin.js +1 -1
- package/plugins/scheduler-plugin.js +2 -2
- package/plugins/session-plugin.js +309 -393
- package/plugins/storage-plugin.js +235 -176
- package/plugins/subagent-plugin.js +4 -4
- package/plugins/telegram-plugin.js +116 -17
- package/plugins/think-plugin.js +1 -1
- package/plugins/web-plugin.js +2 -2
- package/plugins/weixin-plugin.js +102 -19
- package/skills/find-skills/AGENTS.md +2 -2
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/foliko-dev/AGENTS.md +236 -236
- package/skills/foliko-dev/SKILL.md +19 -19
- package/skills/mcp-usage/SKILL.md +200 -200
- package/skills/plugin-guide/SKILL.md +4 -4
- package/skills/python-plugin-dev/SKILL.md +5 -5
- package/skills/skill-guide/SKILL.md +104 -6
- package/skills/subagent-guide/SKILL.md +237 -237
- package/skills/workflow-guide/SKILL.md +646 -646
- package/src/capabilities/skill-manager.js +101 -2
- package/src/capabilities/workflow-engine.js +1 -1
- package/src/core/agent-chat.js +17 -14
- package/src/core/branch-summary-auto.js +206 -0
- package/src/core/chat-session.js +38 -8
- package/src/core/command-registry.js +200 -0
- package/src/core/constants.js +11 -11
- package/src/core/context-compressor.js +700 -149
- package/src/core/context-manager.js +0 -1
- package/src/core/enhanced-context-compressor.js +210 -0
- package/src/core/framework.js +140 -83
- package/src/core/jsonl-storage.js +253 -0
- package/src/core/plugin-manager.js +15 -10
- package/src/core/provider-registry.js +159 -0
- package/src/core/provider.js +2 -0
- package/src/core/session-entry.js +225 -0
- package/src/core/session-manager.js +701 -0
- package/src/core/storage-manager.js +494 -0
- package/src/core/sub-agent-config.js +1 -1
- package/src/core/token-counter.js +177 -58
- package/src/core/ui-extension-context.js +174 -0
- package/src/executors/mcp-executor.js +15 -6
- package/src/utils/logger.js +152 -180
- package/src/utils/plugin-helpers.js +2 -2
- package/website_v2/docs/api.html +1 -1
- package/website_v2/docs/configuration.html +2 -2
- package/website_v2/docs/plugin-development.html +4 -4
- package/website_v2/docs/project-structure.html +2 -2
- package/website_v2/docs/skill-development.html +2 -2
- package/website_v2/index.html +1 -1
- package/website_v2/styles/animations.css +7 -7
- package/.agent/agents/backend-dev.md +0 -102
- package/.agent/agents/data-analyst.md +0 -117
- package/.agent/agents/devops.md +0 -115
- package/.agent/agents/frontend-dev.md +0 -94
- package/.agent/agents/network-requester.md +0 -44
- package/.agent/agents/poster-designer.md +0 -52
- package/.agent/agents/product-manager.md +0 -85
- package/.agent/agents/qa-engineer.md +0 -100
- package/.agent/agents/security-engineer.md +0 -99
- package/.agent/agents/team-lead.md +0 -137
- package/.agent/agents/ui-designer.md +0 -116
- package/.agent/data/default.json +0 -58
- package/.agent/data/email/processed-emails.json +0 -1
- package/.agent/data/plugins-state.json +0 -207
- package/.agent/data/scheduler/tasks.json +0 -1
- package/.agent/data/web/web-config.json +0 -5
- package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
- package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
- package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
- package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
- package/.agent/data/weixin.json +0 -6
- package/.agent/mcp_config.json +0 -14
- package/.agent/memory/user/mof6gk94-kneeuh.md +0 -9
- package/.agent/package.json +0 -8
- package/.agent/plugins/marknative/README.md +0 -134
- package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/marknative/fonts.zip +0 -0
- package/.agent/plugins/marknative/index.js +0 -256
- package/.agent/plugins/marknative/package.json +0 -12
- package/.agent/plugins/test-plugin.py +0 -99
- package/.agent/plugins.json +0 -14
- package/.agent/python-scripts/test_sample.py +0 -24
- package/.agent/sessions/cli_default.json +0 -4121
- 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/test-agent.js +0 -35
- package/.agent/weixin.json +0 -6
- 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/src/core/session-context.js +0 -346
- package/src/core/session-storage.js +0 -295
package/plugins/feishu-plugin.js
CHANGED
|
@@ -188,18 +188,28 @@ class FeishuPlugin extends Plugin {
|
|
|
188
188
|
const command = parts[0].substring(1)
|
|
189
189
|
const args = parts.slice(1).join(' ')
|
|
190
190
|
|
|
191
|
+
// 检查 skill 命令 (格式: skillname:cmdname)
|
|
192
|
+
if (command.includes(':')) {
|
|
193
|
+
const result = await this._executeSkillCommand(command, args)
|
|
194
|
+
if (result) {
|
|
195
|
+
await this._sendMessage(openId, `✅ ${result.data || result}`, originalMsg)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
191
200
|
switch (command.toLowerCase()) {
|
|
192
201
|
case 'start':
|
|
193
202
|
case 'help':
|
|
194
|
-
await this.
|
|
195
|
-
'👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clean - 清除对话上下文\n/history - 查看历史消息数',
|
|
196
|
-
originalMsg)
|
|
203
|
+
await this._sendMessageHelp(openId, originalMsg)
|
|
197
204
|
break
|
|
198
205
|
case 'clear':
|
|
199
206
|
case 'clean':
|
|
200
207
|
await this._clearSessionContext(openId)
|
|
201
208
|
await this._sendMessage(openId, '✅ 对话上下文已清除', originalMsg)
|
|
202
209
|
break
|
|
210
|
+
case 'compress':
|
|
211
|
+
await this._compressSessionContext(openId)
|
|
212
|
+
break
|
|
203
213
|
case 'history':
|
|
204
214
|
if (this._sessionPlugin) {
|
|
205
215
|
const session = this._sessionPlugin.getSession(`feishu_${openId}`)
|
|
@@ -212,6 +222,26 @@ class FeishuPlugin extends Plugin {
|
|
|
212
222
|
}
|
|
213
223
|
break
|
|
214
224
|
default:
|
|
225
|
+
// 检查是否是 skill 命令 (格式: skillname:cmdname)
|
|
226
|
+
if (text.startsWith('/')) {
|
|
227
|
+
const cmdParts = command.split(':')
|
|
228
|
+
if (cmdParts.length === 2) {
|
|
229
|
+
const skillCmd = `${cmdParts[0]}:${cmdParts[1]}`
|
|
230
|
+
try {
|
|
231
|
+
const result = await this._framework.executeTool('ext_call', {
|
|
232
|
+
plugin: 'skill',
|
|
233
|
+
tool: skillCmd,
|
|
234
|
+
args: { args }
|
|
235
|
+
})
|
|
236
|
+
if (result.success !== false) {
|
|
237
|
+
await this._sendMessage(openId, `✅ ${result.data || result}`, originalMsg)
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
log.warn('Skill command failed:', err.message)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
215
245
|
await this._processChat(openId, text, originalMsg)
|
|
216
246
|
}
|
|
217
247
|
}
|
|
@@ -444,7 +474,7 @@ class FeishuPlugin extends Plugin {
|
|
|
444
474
|
}
|
|
445
475
|
|
|
446
476
|
/**
|
|
447
|
-
*
|
|
477
|
+
* 清除会话上下文(清除消息历史)
|
|
448
478
|
*/
|
|
449
479
|
async _clearSessionContext(openId) {
|
|
450
480
|
const sessionId = `feishu_${openId}`
|
|
@@ -457,21 +487,93 @@ class FeishuPlugin extends Plugin {
|
|
|
457
487
|
agent._chatHandler.clearHistory(sessionId)
|
|
458
488
|
}
|
|
459
489
|
|
|
460
|
-
// 清除
|
|
490
|
+
// 清除 SessionManager 的消息
|
|
461
491
|
if (this._framework) {
|
|
462
|
-
const
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
492
|
+
const manager = this._framework.getSessionContext(sessionId)
|
|
493
|
+
if (manager) {
|
|
494
|
+
manager.clearMessages()
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* 检查并执行 skill 命令
|
|
501
|
+
*/
|
|
502
|
+
async _executeSkillCommand(command, args) {
|
|
503
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
504
|
+
if (!extExecutor || typeof extExecutor.executeSkillCommand !== 'function') return null
|
|
505
|
+
return await extExecutor.executeSkillCommand(command, args)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* 发送帮助信息
|
|
510
|
+
*/
|
|
511
|
+
async _sendMessageHelp(openId, originalMsg) {
|
|
512
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
513
|
+
const skillHelp = extExecutor?.getSkillCommandsHelp?.() || ''
|
|
514
|
+
|
|
515
|
+
let helpText = '👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clean - 清除对话上下文\n/compress - 压缩上下文\n/history - 查看历史消息数'
|
|
516
|
+
|
|
517
|
+
if (skillHelp) {
|
|
518
|
+
helpText += '\n\n【技能命令】\n' + skillHelp.split('\n').map(line => line.replace(/^\//, '/')).join('\n')
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
await this._sendMessage(openId, helpText, originalMsg)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* 压缩会话上下文
|
|
526
|
+
*/
|
|
527
|
+
async _compressSessionContext(openId) {
|
|
528
|
+
const sessionId = `feishu_${openId}`
|
|
529
|
+
|
|
530
|
+
// 获取 sessionAgent
|
|
531
|
+
const { agent } = this._getSessionAgent(openId)
|
|
532
|
+
|
|
533
|
+
if (agent._chatHandler) {
|
|
534
|
+
const chatHandler = agent._chatHandler
|
|
535
|
+
|
|
536
|
+
// 先确保从 SessionContext 加载历史(强制重新加载)
|
|
537
|
+
const messageStore = chatHandler._chatSession.getSessionMessageStore(sessionId)
|
|
538
|
+
messageStore.historyLoaded = false
|
|
539
|
+
chatHandler._chatSession.loadHistory(sessionId)
|
|
540
|
+
|
|
541
|
+
let messages = messageStore.messages
|
|
542
|
+
|
|
543
|
+
// 如果 messageStore.messages 为空,尝试从 SessionContext 获取
|
|
544
|
+
if (!messages || messages.length === 0) {
|
|
545
|
+
if (this._framework) {
|
|
546
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
547
|
+
if (sessionCtx) {
|
|
548
|
+
messages = sessionCtx.getMessages()
|
|
549
|
+
messageStore.messages = messages
|
|
550
|
+
}
|
|
551
|
+
}
|
|
467
552
|
}
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
553
|
+
|
|
554
|
+
const beforeCount = messages ? messages.length : 0
|
|
555
|
+
await this._sendMessage(openId, `📦 开始压缩上下文,当前 ${beforeCount} 条消息...`, null)
|
|
556
|
+
|
|
557
|
+
if (messages && messages.length > 0) {
|
|
558
|
+
if (chatHandler._contextCompressor) {
|
|
559
|
+
await chatHandler._contextCompressor.compress(sessionId, messages, messageStore)
|
|
560
|
+
const afterCount = messages.length
|
|
561
|
+
// 同步回 SessionContext
|
|
562
|
+
if (this._framework) {
|
|
563
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
564
|
+
if (sessionCtx) {
|
|
565
|
+
sessionCtx.replaceMessages(messages)
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
await this._sendMessage(openId, `✅ 压缩完成:${beforeCount} → ${afterCount} 条(保留 ${chatHandler._contextCompressor._keepRecentMessages} 条)`, null)
|
|
569
|
+
} else {
|
|
570
|
+
await this._sendMessage(openId, '❌ 压缩器不可用', null)
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
await this._sendMessage(openId, '❌ 没有消息需要压缩', null)
|
|
474
574
|
}
|
|
575
|
+
} else {
|
|
576
|
+
await this._sendMessage(openId, '❌ ChatHandler 不可用', null)
|
|
475
577
|
}
|
|
476
578
|
}
|
|
477
579
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* InstallPlugin - npm 包安装工具
|
|
3
|
-
* 自动安装缺少的 node 模块到 .
|
|
3
|
+
* 自动安装缺少的 node 模块到 .foliko 目录或指定目录
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const { execSync } = require('child_process')
|
|
@@ -18,7 +18,7 @@ class InstallPlugin extends Plugin {
|
|
|
18
18
|
this.version = '1.0.0'
|
|
19
19
|
this.description = '自动安装 npm 包到指定目录'
|
|
20
20
|
|
|
21
|
-
this._agentDir = config.agentDir || '.
|
|
21
|
+
this._agentDir = config.agentDir || '.foliko' // 默认安装到 .foliko 目录
|
|
22
22
|
this._nodeModulesDir = null
|
|
23
23
|
this.system = true
|
|
24
24
|
}
|
|
@@ -41,7 +41,7 @@ class InstallPlugin extends Plugin {
|
|
|
41
41
|
description: '安装 npm 包到指定目录',
|
|
42
42
|
inputSchema: z.object({
|
|
43
43
|
package: z.string().optional().describe('包名,如 lodash、lodash@4.17.21 或 @scope/package'),
|
|
44
|
-
path: z.string().optional().describe('安装目标目录,如 .
|
|
44
|
+
path: z.string().optional().describe('安装目标目录,如 .foliko/plugins/my-plugin(默认为 .foliko)'),
|
|
45
45
|
file: z.string().optional().describe('本地 package.json 路径,从该文件安装所有依赖')
|
|
46
46
|
}),
|
|
47
47
|
execute: async (args) => {
|
|
@@ -79,7 +79,7 @@ class InstallPlugin extends Plugin {
|
|
|
79
79
|
/**
|
|
80
80
|
* 安装单个包到指定目录
|
|
81
81
|
* @param {string} packageName - 包名
|
|
82
|
-
* @param {string|null} targetPath - 目标目录,默认为 .
|
|
82
|
+
* @param {string|null} targetPath - 目标目录,默认为 .foliko
|
|
83
83
|
*/
|
|
84
84
|
_installPackage(packageName, targetPath = null) {
|
|
85
85
|
try {
|
package/plugins/memory-plugin.js
CHANGED
|
@@ -119,7 +119,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
119
119
|
// 3. plugin_install - 从远程仓库安装插件到本地
|
|
120
120
|
framework.registerTool({
|
|
121
121
|
name: 'plugin_install',
|
|
122
|
-
description: '从远程 Git 仓库安装插件到本地 .
|
|
122
|
+
description: '从远程 Git 仓库安装插件到本地 .foliko/plugins 目录',
|
|
123
123
|
inputSchema: z.object({
|
|
124
124
|
name: z.string().describe('插件名称,如 puppeteer-plugin'),
|
|
125
125
|
repo: z.string().optional().describe('插件仓库 URL'),
|
|
@@ -212,7 +212,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
212
212
|
* 发布插件到远程仓库
|
|
213
213
|
*/
|
|
214
214
|
async _publishPlugin(pluginName, repo) {
|
|
215
|
-
const pluginsDir = path.resolve(process.cwd(), '.
|
|
215
|
+
const pluginsDir = path.resolve(process.cwd(), '.foliko', 'plugins');
|
|
216
216
|
const localPluginsDir = path.resolve(process.cwd(), 'plugins');
|
|
217
217
|
|
|
218
218
|
// 确定插件目录
|
|
@@ -330,7 +330,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
330
330
|
* 从远程仓库安装插件
|
|
331
331
|
*/
|
|
332
332
|
async _installPlugin(pluginName, repo) {
|
|
333
|
-
const localPluginsDir = path.resolve(process.cwd(), '.
|
|
333
|
+
const localPluginsDir = path.resolve(process.cwd(), '.foliko', 'plugins');
|
|
334
334
|
const tmpDir = path.join(require('os').tmpdir(), `foliko-plugin-install-${Date.now()}`);
|
|
335
335
|
|
|
336
336
|
try {
|
|
@@ -23,7 +23,7 @@ class PythonExecutorPlugin extends Plugin {
|
|
|
23
23
|
this.config = {
|
|
24
24
|
pythonPath: config.pythonPath || 'python', // python 或 python3
|
|
25
25
|
timeout: config.timeout || 120000, // 2分钟超时
|
|
26
|
-
baseDir: config.baseDir || '.
|
|
26
|
+
baseDir: config.baseDir || '.foliko/python-scripts',
|
|
27
27
|
pipPath: config.pipPath || null // 可选,自定义 pip 路径
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -59,7 +59,7 @@ class PythonPluginLoader extends Plugin {
|
|
|
59
59
|
this.version = '1.0.0'
|
|
60
60
|
this.description = 'Python 插件加载器,属于Python的插件'
|
|
61
61
|
|
|
62
|
-
this._agentDir = config.agentDir || '.
|
|
62
|
+
this._agentDir = config.agentDir || '.foliko' // 默认从 .foliko 目录加载 Python 插件
|
|
63
63
|
this._pythonPlugins = new Map()
|
|
64
64
|
this._framework = null
|
|
65
65
|
this.system = true
|
package/plugins/qq-plugin.js
CHANGED
|
@@ -26,7 +26,7 @@ class QQPlugin extends Plugin {
|
|
|
26
26
|
this.description = 'QQ 对话插件,使用 QQ 开放平台进行对话'
|
|
27
27
|
this.priority = 80
|
|
28
28
|
this.enabled = false
|
|
29
|
-
this.path = `.
|
|
29
|
+
this.path = `.foliko/data`
|
|
30
30
|
|
|
31
31
|
this.config = {
|
|
32
32
|
appId: config.appId || process.env.QQ_APP_ID,
|
|
@@ -49,7 +49,7 @@ class QQPlugin extends Plugin {
|
|
|
49
49
|
this.agent = null
|
|
50
50
|
this.sessionId = null
|
|
51
51
|
|
|
52
|
-
const saveDir = path.join(process.cwd(), '.
|
|
52
|
+
const saveDir = path.join(process.cwd(), '.foliko', 'data', this.name)
|
|
53
53
|
this.downloader = new FileDownloader({
|
|
54
54
|
retries: 3,
|
|
55
55
|
baseDir: saveDir
|
|
@@ -679,17 +679,28 @@ class QQPlugin extends Plugin {
|
|
|
679
679
|
const command = parts[0].substring(1)
|
|
680
680
|
const args = parts.slice(1).join(' ')
|
|
681
681
|
|
|
682
|
+
// 检查 skill 命令 (格式: skillname:cmdname)
|
|
683
|
+
if (command.includes(':')) {
|
|
684
|
+
const result = await this._executeSkillCommand(command, args)
|
|
685
|
+
if (result) {
|
|
686
|
+
await this._sendMessage(openid, `✅ ${result.data || result}`)
|
|
687
|
+
return
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
682
691
|
switch (command.toLowerCase()) {
|
|
683
692
|
case 'start':
|
|
684
693
|
case 'help':
|
|
685
|
-
await this.
|
|
686
|
-
'👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/clean - 清除对话上下文\n/history - 查看历史消息数')
|
|
694
|
+
await this._sendMessageHelp(openid)
|
|
687
695
|
break
|
|
688
696
|
case 'clean':
|
|
689
697
|
case 'clear':
|
|
690
698
|
await this._clearSessionContext(openid)
|
|
691
699
|
await this._sendMessage(openid, '✅ 对话上下文已清除')
|
|
692
700
|
break
|
|
701
|
+
case 'compress':
|
|
702
|
+
await this._compressSessionContext(openid)
|
|
703
|
+
break
|
|
693
704
|
case 'history':
|
|
694
705
|
const sessionInfo = this._getSessionAgent(openid)
|
|
695
706
|
if (sessionInfo && this._framework) {
|
|
@@ -701,10 +712,55 @@ class QQPlugin extends Plugin {
|
|
|
701
712
|
}
|
|
702
713
|
break
|
|
703
714
|
default:
|
|
715
|
+
// 检查是否是 skill 命令 (格式: skillname:cmdname)
|
|
716
|
+
if (text.startsWith('/')) {
|
|
717
|
+
const cmdParts = command.split(':')
|
|
718
|
+
if (cmdParts.length === 2) {
|
|
719
|
+
const skillCmd = `${cmdParts[0]}:${cmdParts[1]}`
|
|
720
|
+
try {
|
|
721
|
+
const result = await this._framework.executeTool('ext_call', {
|
|
722
|
+
plugin: 'skill',
|
|
723
|
+
tool: skillCmd,
|
|
724
|
+
args: { args }
|
|
725
|
+
})
|
|
726
|
+
if (result.success !== false) {
|
|
727
|
+
await this._sendMessage(openid, `✅ ${result.data || result}`)
|
|
728
|
+
return
|
|
729
|
+
}
|
|
730
|
+
} catch (err) {
|
|
731
|
+
log.warn('Skill command failed:', err.message)
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
704
735
|
await this._processChat(openid, text, originalMsg, 'c2c')
|
|
705
736
|
}
|
|
706
737
|
}
|
|
707
738
|
|
|
739
|
+
/**
|
|
740
|
+
* 检查并执行 skill 命令
|
|
741
|
+
*/
|
|
742
|
+
async _executeSkillCommand(command, args) {
|
|
743
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
744
|
+
if (!extExecutor || typeof extExecutor.executeSkillCommand !== 'function') return null
|
|
745
|
+
return await extExecutor.executeSkillCommand(command, args)
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* 发送帮助信息
|
|
750
|
+
*/
|
|
751
|
+
async _sendMessageHelp(openid) {
|
|
752
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
753
|
+
const skillHelp = extExecutor?.getSkillCommandsHelp?.() || ''
|
|
754
|
+
|
|
755
|
+
let helpText = '👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/clean - 清除对话上下文\n/compress - 压缩上下文\n/history - 查看历史消息数'
|
|
756
|
+
|
|
757
|
+
if (skillHelp) {
|
|
758
|
+
helpText += '\n\n【技能命令】\n' + skillHelp.split('\n').map(line => line.replace(/^\//, '/')).join('\n')
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
await this._sendMessage(openid, helpText)
|
|
762
|
+
}
|
|
763
|
+
|
|
708
764
|
/**
|
|
709
765
|
* 处理群命令
|
|
710
766
|
*/
|
|
@@ -713,17 +769,28 @@ class QQPlugin extends Plugin {
|
|
|
713
769
|
const command = parts[0].substring(1)
|
|
714
770
|
const args = parts.slice(1).join(' ')
|
|
715
771
|
|
|
772
|
+
// 检查 skill 命令 (格式: skillname:cmdname)
|
|
773
|
+
if (command.includes(':')) {
|
|
774
|
+
const result = await this._executeSkillCommand(command, args)
|
|
775
|
+
if (result) {
|
|
776
|
+
await this._sendGroupMessage(groupOpenid, `✅ ${result.data || result}`)
|
|
777
|
+
return
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
716
781
|
switch (command.toLowerCase()) {
|
|
717
782
|
case 'start':
|
|
718
783
|
case 'help':
|
|
719
|
-
await this.
|
|
720
|
-
'👋 欢迎使用 AI 助手!\n\n可用命令:\n/clean - 清除对话上下文\n/history - 查看历史消息数')
|
|
784
|
+
await this._sendGroupMessageHelp(groupOpenid)
|
|
721
785
|
break
|
|
722
786
|
case 'clean':
|
|
723
787
|
case 'clear':
|
|
724
788
|
await this._clearSessionContext(groupOpenid)
|
|
725
789
|
await this._sendGroupMessage(groupOpenid, '✅ 对话上下文已清除')
|
|
726
790
|
break
|
|
791
|
+
case 'compress':
|
|
792
|
+
await this._compressSessionContext(groupOpenid)
|
|
793
|
+
break
|
|
727
794
|
case 'history':
|
|
728
795
|
const sessionInfo = this._getSessionAgent(groupOpenid, 'group')
|
|
729
796
|
if (sessionInfo && this._framework) {
|
|
@@ -739,6 +806,22 @@ class QQPlugin extends Plugin {
|
|
|
739
806
|
}
|
|
740
807
|
}
|
|
741
808
|
|
|
809
|
+
/**
|
|
810
|
+
* 发送群组帮助信息
|
|
811
|
+
*/
|
|
812
|
+
async _sendGroupMessageHelp(groupOpenid) {
|
|
813
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
814
|
+
const skillHelp = extExecutor?.getSkillCommandsHelp?.() || ''
|
|
815
|
+
|
|
816
|
+
let helpText = '👋 欢迎使用 AI 助手!\n\n可用命令:\n/clean - 清除对话上下文\n/compress - 压缩上下文\n/history - 查看历史消息数'
|
|
817
|
+
|
|
818
|
+
if (skillHelp) {
|
|
819
|
+
helpText += '\n\n【技能命令】\n' + skillHelp.split('\n').map(line => line.replace(/^\//, '/')).join('\n')
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
await this._sendGroupMessage(groupOpenid, helpText)
|
|
823
|
+
}
|
|
824
|
+
|
|
742
825
|
/**
|
|
743
826
|
* 清除会话上下文
|
|
744
827
|
*/
|
|
@@ -752,18 +835,62 @@ class QQPlugin extends Plugin {
|
|
|
752
835
|
}
|
|
753
836
|
|
|
754
837
|
if (this._framework) {
|
|
755
|
-
const
|
|
756
|
-
if (
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
838
|
+
const manager = this._framework.getSessionContext(sessionId)
|
|
839
|
+
if (manager) {
|
|
840
|
+
manager.clearMessages()
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* 压缩会话上下文
|
|
847
|
+
*/
|
|
848
|
+
async _compressSessionContext(identifier) {
|
|
849
|
+
const sessionId = `qq_c2c_${identifier}`
|
|
850
|
+
|
|
851
|
+
const { agent } = this._getSessionAgent(identifier)
|
|
852
|
+
|
|
853
|
+
if (agent._chatHandler) {
|
|
854
|
+
const chatHandler = agent._chatHandler
|
|
855
|
+
|
|
856
|
+
const messageStore = chatHandler._chatSession.getSessionMessageStore(sessionId)
|
|
857
|
+
messageStore.historyLoaded = false
|
|
858
|
+
chatHandler._chatSession.loadHistory(sessionId)
|
|
859
|
+
|
|
860
|
+
let messages = messageStore.messages
|
|
861
|
+
|
|
862
|
+
if (!messages || messages.length === 0) {
|
|
863
|
+
if (this._framework) {
|
|
864
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
865
|
+
if (sessionCtx) {
|
|
866
|
+
messages = sessionCtx.getMessages()
|
|
867
|
+
messageStore.messages = messages
|
|
868
|
+
}
|
|
869
|
+
}
|
|
760
870
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
871
|
+
|
|
872
|
+
const beforeCount = messages ? messages.length : 0
|
|
873
|
+
await this._sendMessage(identifier, `📦 开始压缩上下文,当前 ${beforeCount} 条消息...`)
|
|
874
|
+
|
|
875
|
+
if (messages && messages.length > 0) {
|
|
876
|
+
if (chatHandler._contextCompressor) {
|
|
877
|
+
await chatHandler._contextCompressor.compress(sessionId, messages, messageStore)
|
|
878
|
+
const afterCount = messages.length
|
|
879
|
+
if (this._framework) {
|
|
880
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
881
|
+
if (sessionCtx) {
|
|
882
|
+
sessionCtx.replaceMessages(messages)
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
await this._sendMessage(identifier, `✅ 压缩完成:${beforeCount} → ${afterCount} 条(保留 ${chatHandler._contextCompressor._keepRecentMessages} 条)`)
|
|
886
|
+
} else {
|
|
887
|
+
await this._sendMessage(identifier, '❌ 压缩器不可用')
|
|
888
|
+
}
|
|
889
|
+
} else {
|
|
890
|
+
await this._sendMessage(identifier, '❌ 没有消息需要压缩')
|
|
766
891
|
}
|
|
892
|
+
} else {
|
|
893
|
+
await this._sendMessage(identifier, '❌ ChatHandler 不可用')
|
|
767
894
|
}
|
|
768
895
|
}
|
|
769
896
|
|
package/plugins/rules-plugin.js
CHANGED
|
@@ -20,7 +20,7 @@ try {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// ============================================================================
|
|
23
|
-
// TaskStore - 持久化任务到 .
|
|
23
|
+
// TaskStore - 持久化任务到 .foliko/data/scheduler/tasks.json
|
|
24
24
|
// ============================================================================
|
|
25
25
|
class TaskStore {
|
|
26
26
|
constructor(persistencePath) {
|
|
@@ -130,7 +130,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
130
130
|
this.system = true
|
|
131
131
|
this.config = {
|
|
132
132
|
checkInterval: config.checkInterval || 1000, // 每秒检查一次
|
|
133
|
-
persistencePath: config.persistencePath || '.
|
|
133
|
+
persistencePath: config.persistencePath || '.foliko/data/scheduler'
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
this._framework = null
|