foliko 1.1.7 → 1.1.9
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/agents/poster-expert.md +228 -0
- package/.agent/data/default.json +10 -0
- package/.agent/data/plugins-state.json +1 -1
- package/.agent/mcp_config.json +0 -6
- package/.agent/plugins/test-plugin.py +15 -0
- package/.agent/plugins/test_nested_plugin.py +85 -0
- package/.agent/sessions/cli_default.json +83 -803
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +189 -0
- package/.claude/settings.local.json +8 -1
- package/cli/src/ui/chat-ui.js +32 -21
- package/foliko_poster.png +0 -0
- package/output/business_poster_final.png +0 -0
- package/output/emoji_test_v2.png +0 -0
- package/output/foliko-ai-launch-poster.png +0 -0
- package/output/foliko-poster.png +0 -0
- package/output/muji_style_poster.png +0 -0
- package/output/new_product_launch.png +0 -0
- package/output/news_poster_625yi_subsidy.png +0 -0
- package/output/tech_future_2026.png +0 -0
- package/output/tech_future_poster.png +0 -0
- package/package.json +2 -2
- package/plugins/default-plugins.js +60 -7
- package/plugins/extension-executor-plugin.js +32 -22
- package/plugins/feishu-plugin.js +2 -2
- package/plugins/python-plugin-loader.js +461 -40
- package/plugins/python-plugin-loader.js.bak +856 -0
- package/plugins/subagent-plugin.js +0 -121
- package/plugins/telegram-plugin.js +2 -2
- package/plugins/weixin-plugin.js +40 -31
- package/poster.png +0 -0
- package/skills/foliko-dev/SKILL.md +6 -0
- package/skills/python-plugin-dev/SKILL.md +124 -2
- package/src/core/agent-chat.js +220 -281
- package/src/core/agent.js +127 -29
- package/src/executors/mcp-executor.js +282 -26
- package/src/utils/plugin-helpers.js +22 -4
- package/system.md +362 -109
- package/test-scan.js +18 -0
- package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +0 -15
- package/.agent/memory/feedback/mnt88ja3-al4fuy.md +0 -9
- package/.agent/plugins/poster-plugin/README.md +0 -304
- package/.agent/plugins/poster-plugin/emojis/rocket.png +0 -1
- package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.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 +0 -13
- package/.agent/plugins/poster-plugin/package.json +0 -29
- package/.agent/plugins/poster-plugin/src/canvas.js +0 -224
- package/.agent/plugins/poster-plugin/src/components/arrow.js +0 -84
- package/.agent/plugins/poster-plugin/src/components/avatar.js +0 -71
- package/.agent/plugins/poster-plugin/src/components/badge.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/barcode.js +0 -120
- package/.agent/plugins/poster-plugin/src/components/bubble.js +0 -153
- package/.agent/plugins/poster-plugin/src/components/button.js +0 -124
- package/.agent/plugins/poster-plugin/src/components/card.js +0 -88
- package/.agent/plugins/poster-plugin/src/components/chart.js +0 -127
- package/.agent/plugins/poster-plugin/src/components/chip.js +0 -88
- package/.agent/plugins/poster-plugin/src/components/columns.js +0 -107
- package/.agent/plugins/poster-plugin/src/components/cta.js +0 -87
- package/.agent/plugins/poster-plugin/src/components/divider.js +0 -55
- package/.agent/plugins/poster-plugin/src/components/feature.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/featureGrid.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/frame.js +0 -230
- package/.agent/plugins/poster-plugin/src/components/grid.js +0 -118
- package/.agent/plugins/poster-plugin/src/components/highlightText.js +0 -144
- package/.agent/plugins/poster-plugin/src/components/icon.js +0 -94
- package/.agent/plugins/poster-plugin/src/components/imageFrame.js +0 -155
- package/.agent/plugins/poster-plugin/src/components/index.js +0 -81
- package/.agent/plugins/poster-plugin/src/components/listItem.js +0 -147
- package/.agent/plugins/poster-plugin/src/components/notification.js +0 -123
- package/.agent/plugins/poster-plugin/src/components/progress.js +0 -79
- package/.agent/plugins/poster-plugin/src/components/progressCircle.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/qrcode.js +0 -74
- package/.agent/plugins/poster-plugin/src/components/quote.js +0 -97
- package/.agent/plugins/poster-plugin/src/components/rating.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/ribbon.js +0 -193
- package/.agent/plugins/poster-plugin/src/components/seal.js +0 -146
- package/.agent/plugins/poster-plugin/src/components/star.js +0 -70
- package/.agent/plugins/poster-plugin/src/components/statCard.js +0 -105
- package/.agent/plugins/poster-plugin/src/components/stepper.js +0 -118
- package/.agent/plugins/poster-plugin/src/components/table.js +0 -167
- package/.agent/plugins/poster-plugin/src/components/tagCloud.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/timeline.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/watermark.js +0 -52
- package/.agent/plugins/poster-plugin/src/composer.js +0 -2146
- package/.agent/plugins/poster-plugin/src/elements/artText.js +0 -60
- package/.agent/plugins/poster-plugin/src/elements/background.js +0 -84
- package/.agent/plugins/poster-plugin/src/elements/circle.js +0 -31
- package/.agent/plugins/poster-plugin/src/elements/image.js +0 -28
- package/.agent/plugins/poster-plugin/src/elements/index.js +0 -28
- package/.agent/plugins/poster-plugin/src/elements/line.js +0 -23
- package/.agent/plugins/poster-plugin/src/elements/polygon.js +0 -63
- package/.agent/plugins/poster-plugin/src/elements/rectangle.js +0 -32
- package/.agent/plugins/poster-plugin/src/elements/richText.js +0 -230
- package/.agent/plugins/poster-plugin/src/elements/svg.js +0 -108
- package/.agent/plugins/poster-plugin/src/elements/text.js +0 -109
- package/.agent/plugins/poster-plugin/src/fonts.js +0 -243
- package/.agent/plugins/poster-plugin/src/index.js +0 -2081
- package/.agent/plugins/poster-plugin/src/presets.js +0 -36
- package/.agent/plugins/poster-plugin/src/templates/business.js +0 -60
- package/.agent/plugins/poster-plugin/src/templates/gradient.js +0 -64
- package/.agent/plugins/poster-plugin/src/templates/index.js +0 -43
- package/.agent/plugins/poster-plugin/src/templates/modern.js +0 -69
- package/.agent/plugins/poster-plugin/src/templates/simple.js +0 -58
- package/.agent/plugins/poster-plugin/src/templates/social.js +0 -62
- package/.agent/plugins/poster-plugin/src/templates/tech.js +0 -84
- package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +0 -84
- package/.agent/plugins/poster-plugin/test-background.svg +0 -1
- package/.agent/plugins/poster-plugin/test-full-poster.svg +0 -2
- package/.agent/plugins/poster-plugin/test-image.png +0 -0
- package/.agent/plugins/poster-plugin/yarn.lock +0 -1007
- package/output/zen_silence.png +0 -0
|
@@ -387,8 +387,6 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
387
387
|
|
|
388
388
|
this._framework = null
|
|
389
389
|
this._subAgents = new Map()
|
|
390
|
-
this._fileWatcher = null
|
|
391
|
-
this._lastFileStates = new Map() // 记录文件状态用于检测变化
|
|
392
390
|
}
|
|
393
391
|
|
|
394
392
|
install(framework) {
|
|
@@ -423,9 +421,6 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
423
421
|
}
|
|
424
422
|
})
|
|
425
423
|
|
|
426
|
-
// 启动文件监控
|
|
427
|
-
this._startFileWatcher()
|
|
428
|
-
|
|
429
424
|
return this
|
|
430
425
|
}
|
|
431
426
|
|
|
@@ -688,110 +683,6 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
688
683
|
return result
|
|
689
684
|
}
|
|
690
685
|
|
|
691
|
-
/**
|
|
692
|
-
* 启动文件监控
|
|
693
|
-
*/
|
|
694
|
-
_startFileWatcher() {
|
|
695
|
-
const agentsDir = this.config.agentsDir
|
|
696
|
-
if (!agentsDir || !fs.existsSync(agentsDir)) {
|
|
697
|
-
return
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// 记录初始文件状态
|
|
701
|
-
this._updateFileStates()
|
|
702
|
-
|
|
703
|
-
// 使用 fs.watch 监控目录变化
|
|
704
|
-
this._fileWatcher = fs.watch(agentsDir, { recursive: false }, (eventType, filename) => {
|
|
705
|
-
if (filename && (filename.endsWith('.js') || filename.endsWith('.json') || filename.endsWith('.md'))) {
|
|
706
|
-
//console.log(`[SubAgentManager] Detected change in agents dir: ${eventType} - ${filename}`)
|
|
707
|
-
|
|
708
|
-
// 防抖:延迟处理,等文件操作完成
|
|
709
|
-
setTimeout(() => {
|
|
710
|
-
this._checkAndReload()
|
|
711
|
-
}, 500)
|
|
712
|
-
}
|
|
713
|
-
})
|
|
714
|
-
|
|
715
|
-
//console.log(`[SubAgentManager] Watching agents dir for changes: ${agentsDir}`)
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
/**
|
|
719
|
-
* 更新文件状态
|
|
720
|
-
*/
|
|
721
|
-
_updateFileStates() {
|
|
722
|
-
const agentsDir = this.config.agentsDir
|
|
723
|
-
if (!agentsDir || !fs.existsSync(agentsDir)) {
|
|
724
|
-
return
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
this._lastFileStates.clear()
|
|
728
|
-
const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
|
|
729
|
-
|
|
730
|
-
for (const entry of entries) {
|
|
731
|
-
if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
|
|
732
|
-
const filePath = path.join(agentsDir, entry.name)
|
|
733
|
-
try {
|
|
734
|
-
const stat = fs.statSync(filePath)
|
|
735
|
-
this._lastFileStates.set(entry.name, {
|
|
736
|
-
mtime: stat.mtime.getTime(),
|
|
737
|
-
size: stat.size
|
|
738
|
-
})
|
|
739
|
-
} catch (err) {
|
|
740
|
-
// 忽略
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/**
|
|
747
|
-
* 检查并重载(如果有变化)
|
|
748
|
-
*/
|
|
749
|
-
_checkAndReload() {
|
|
750
|
-
const agentsDir = this.config.agentsDir
|
|
751
|
-
if (!agentsDir || !fs.existsSync(agentsDir)) {
|
|
752
|
-
return
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
const currentStates = new Map()
|
|
756
|
-
const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
|
|
757
|
-
let hasChanges = false
|
|
758
|
-
|
|
759
|
-
// 检查当前文件
|
|
760
|
-
for (const entry of entries) {
|
|
761
|
-
if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
|
|
762
|
-
const filePath = path.join(agentsDir, entry.name)
|
|
763
|
-
try {
|
|
764
|
-
const stat = fs.statSync(filePath)
|
|
765
|
-
currentStates.set(entry.name, {
|
|
766
|
-
mtime: stat.mtime.getTime(),
|
|
767
|
-
size: stat.size
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
const lastState = this._lastFileStates.get(entry.name)
|
|
771
|
-
if (!lastState || lastState.mtime !== stat.mtime.getTime() || lastState.size !== stat.size) {
|
|
772
|
-
hasChanges = true
|
|
773
|
-
}
|
|
774
|
-
} catch (err) {
|
|
775
|
-
// 忽略
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// 检查删除的文件
|
|
781
|
-
for (const [name] of this._lastFileStates) {
|
|
782
|
-
if (!currentStates.has(name)) {
|
|
783
|
-
hasChanges = true
|
|
784
|
-
break
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
if (hasChanges) {
|
|
789
|
-
//log.info(' File changes detected, reloading...')
|
|
790
|
-
this._updateFileStates()
|
|
791
|
-
this.reload(this._framework)
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
|
|
795
686
|
/**
|
|
796
687
|
* 获取子Agent
|
|
797
688
|
*/
|
|
@@ -801,12 +692,6 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
801
692
|
}
|
|
802
693
|
|
|
803
694
|
reload(framework) {
|
|
804
|
-
// 停止文件监控
|
|
805
|
-
if (this._fileWatcher) {
|
|
806
|
-
this._fileWatcher.close()
|
|
807
|
-
this._fileWatcher = null
|
|
808
|
-
}
|
|
809
|
-
|
|
810
695
|
// 销毁旧的子Agent
|
|
811
696
|
for (const plugin of this._subAgents.values()) {
|
|
812
697
|
plugin.uninstall(framework)
|
|
@@ -826,12 +711,6 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
826
711
|
}
|
|
827
712
|
|
|
828
713
|
uninstall(framework) {
|
|
829
|
-
// 停止文件监控
|
|
830
|
-
if (this._fileWatcher) {
|
|
831
|
-
this._fileWatcher.close()
|
|
832
|
-
this._fileWatcher = null
|
|
833
|
-
}
|
|
834
|
-
|
|
835
714
|
for (const plugin of this._subAgents.values()) {
|
|
836
715
|
plugin.uninstall(framework)
|
|
837
716
|
}
|
|
@@ -126,7 +126,7 @@ class TelegramPlugin extends Plugin {
|
|
|
126
126
|
* 处理统一通知
|
|
127
127
|
*/
|
|
128
128
|
async _handleNotification(data) {
|
|
129
|
-
const { title, message, source, level } = data
|
|
129
|
+
const { title, message, source = '系统消息', level } = data
|
|
130
130
|
|
|
131
131
|
if (!this._bot) {
|
|
132
132
|
log.warn(' Bot not ready, cannot send notification')
|
|
@@ -170,7 +170,7 @@ class TelegramPlugin extends Plugin {
|
|
|
170
170
|
error: '❌'
|
|
171
171
|
}
|
|
172
172
|
const emoji = levelEmoji[level] || 'ℹ️'
|
|
173
|
-
const notificationText = `${emoji} [${source}] ${title}\n\n${message}`
|
|
173
|
+
const notificationText = `${emoji} [${source}] ${title || '通知'}\n\n${message || ''}`
|
|
174
174
|
|
|
175
175
|
try {
|
|
176
176
|
await this._bot.sendMessage(chatId, notificationText)
|
package/plugins/weixin-plugin.js
CHANGED
|
@@ -467,19 +467,27 @@ class WeixinPlugin extends Plugin {
|
|
|
467
467
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
468
468
|
|
|
469
469
|
try {
|
|
470
|
-
// 使用
|
|
471
|
-
|
|
470
|
+
// 使用 continue 获取流式响应
|
|
472
471
|
let fullResponse = '';
|
|
473
|
-
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
474
|
-
if (chunk.type === 'text') {
|
|
475
|
-
fullResponse += chunk.text;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
const response = cleanResponse(fullResponse);
|
|
479
472
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
473
|
+
await agent.continue(text, sessionId, {
|
|
474
|
+
onChunk: (text, full) => {
|
|
475
|
+
if (text) fullResponse += text;
|
|
476
|
+
},
|
|
477
|
+
onComplete: async (full, ctx) => {
|
|
478
|
+
const response = cleanResponse(full);
|
|
479
|
+
if (response) {
|
|
480
|
+
await this._sendMessageBatch(originalMsg, userId, response, true)
|
|
481
|
+
} else {
|
|
482
|
+
// 响应为空,压入继续消息
|
|
483
|
+
ctx.push('请继续完成任务', { sessionId });
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
onError: async (err, ctx) => {
|
|
487
|
+
log.error(' Media chat error:', err.message);
|
|
488
|
+
await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
|
|
489
|
+
}
|
|
490
|
+
});
|
|
483
491
|
} catch (err) {
|
|
484
492
|
log.error(' Media chat error:', err)
|
|
485
493
|
await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
|
|
@@ -498,11 +506,6 @@ class WeixinPlugin extends Plugin {
|
|
|
498
506
|
|
|
499
507
|
const { agent, sessionId } = sessionInfo
|
|
500
508
|
|
|
501
|
-
// 使用 SessionPlugin 添加用户消息到历史
|
|
502
|
-
// if (this._sessionPlugin) {
|
|
503
|
-
// this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
|
|
504
|
-
// }
|
|
505
|
-
|
|
506
509
|
// 发送正在输入状态
|
|
507
510
|
try {
|
|
508
511
|
await this._bot.sendTyping(userId)
|
|
@@ -511,21 +514,27 @@ class WeixinPlugin extends Plugin {
|
|
|
511
514
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
512
515
|
|
|
513
516
|
try {
|
|
514
|
-
// 使用
|
|
517
|
+
// 使用 continue 获取流式响应
|
|
515
518
|
let fullResponse = '';
|
|
516
|
-
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
517
|
-
if (chunk.type === 'text') {
|
|
518
|
-
fullResponse += chunk.text;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
const response = cleanResponse(fullResponse);
|
|
522
519
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
520
|
+
await agent.continue(text, sessionId, {
|
|
521
|
+
onChunk: (text, full) => {
|
|
522
|
+
if (text) fullResponse += text;
|
|
523
|
+
},
|
|
524
|
+
onComplete: async (full, ctx) => {
|
|
525
|
+
const response = cleanResponse(full);
|
|
526
|
+
if (response) {
|
|
527
|
+
await this._sendMessageBatch(originalMsg, userId, response, true)
|
|
528
|
+
} else {
|
|
529
|
+
// 响应为空,压入继续消息
|
|
530
|
+
ctx.push('请继续完成任务', { sessionId });
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
onError: async (err, ctx) => {
|
|
534
|
+
log.error(' Chat error:', err.message);
|
|
535
|
+
await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
|
|
536
|
+
}
|
|
537
|
+
});
|
|
529
538
|
|
|
530
539
|
} catch (err) {
|
|
531
540
|
log.error(' Chat error:', err.message)
|
|
@@ -673,7 +682,7 @@ class WeixinPlugin extends Plugin {
|
|
|
673
682
|
* 处理统一通知
|
|
674
683
|
*/
|
|
675
684
|
async _handleNotification(data) {
|
|
676
|
-
const { title, message, source, level, sessionId } = data
|
|
685
|
+
const { title, message, source = '系统消息', level, sessionId } = data
|
|
677
686
|
|
|
678
687
|
if (!this._bot) {
|
|
679
688
|
log.warn(' Bot not ready, cannot send notification')
|
|
@@ -717,7 +726,7 @@ class WeixinPlugin extends Plugin {
|
|
|
717
726
|
error: '❌'
|
|
718
727
|
}
|
|
719
728
|
const emoji = levelEmoji[level] || 'ℹ️'
|
|
720
|
-
const notificationText = `${emoji} [${source}] ${title}\n\n${message}`
|
|
729
|
+
const notificationText = `${emoji} [${source}] ${title || '通知'}\n\n${message || ''}`
|
|
721
730
|
|
|
722
731
|
try {
|
|
723
732
|
await this._sendMessageBatch(null, userId, notificationText, false)
|
package/poster.png
ADDED
|
Binary file
|
|
@@ -177,6 +177,12 @@ module.exports = function (Plugin) {
|
|
|
177
177
|
| **文件夹插件** | `.agent/plugins/插件名/node_modules/` | 插件自包含,可独立迁移 |
|
|
178
178
|
| **单文件插件** | `.agent/node_modules/` | 共享依赖 |
|
|
179
179
|
|
|
180
|
+
### 重要依赖版本要求
|
|
181
|
+
|
|
182
|
+
**zod 必须使用 `"zod": "^3.25.76"` 版本**
|
|
183
|
+
|
|
184
|
+
其他依赖版本无特殊要求。
|
|
185
|
+
|
|
180
186
|
### 自动安装工具
|
|
181
187
|
|
|
182
188
|
框架提供了 `install` 工具,支持以下用法:
|
|
@@ -6,6 +6,44 @@ allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
|
6
6
|
|
|
7
7
|
# Python 插件开发
|
|
8
8
|
|
|
9
|
+
## ext_call 调用方式
|
|
10
|
+
|
|
11
|
+
通过 `ext_call` 工具调用 Python 插件:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
ext_call({
|
|
15
|
+
plugin: "插件名", // 插件名称(必须)
|
|
16
|
+
tool: "工具名", // 工具名称(必须)
|
|
17
|
+
args: {...} // 工具参数(必须)
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**注意**:插件下的工具调用时,`tool` 参数格式为:
|
|
22
|
+
|
|
23
|
+
- 如果工具名是 `query_data`,插件名是 `test_nested_plugin`
|
|
24
|
+
- 调用时:`plugin: "python"`, `tool: "test_nested_plugin_query_data"`
|
|
25
|
+
- 即:自动将 `插件名_工具名` 合并为 `tool` 参数
|
|
26
|
+
|
|
27
|
+
**示例**:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
// 插件名: test-plugin, 工具名: hello
|
|
31
|
+
ext_call({
|
|
32
|
+
plugin: 'python',
|
|
33
|
+
tool: 'test-plugin_hello',
|
|
34
|
+
args: { name: 'Foliko' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 插件名: test_nested_plugin, 工具名: query_data
|
|
38
|
+
ext_call({
|
|
39
|
+
plugin: 'python',
|
|
40
|
+
tool: 'test_nested_plugin_query_data',
|
|
41
|
+
args: { filter: { name: 'Alice' } },
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 概述
|
|
46
|
+
|
|
9
47
|
## 概述
|
|
10
48
|
|
|
11
49
|
Python 插件允许用 Python 语言开发工具,插件代码运行在 Python 环境中,可以调用所有 Python 库。
|
|
@@ -101,14 +139,98 @@ def calc(params):
|
|
|
101
139
|
|
|
102
140
|
```javascript
|
|
103
141
|
ext_call({
|
|
104
|
-
plugin: '
|
|
105
|
-
tool: '
|
|
142
|
+
plugin: 'python', // 插件名称
|
|
143
|
+
tool: 'my-plugin_hello', // 工具名称
|
|
106
144
|
args: { name: 'Foliko' }, // 工具参数
|
|
107
145
|
});
|
|
108
146
|
```
|
|
109
147
|
|
|
110
148
|
工具会自动出现在系统提示词的【Extensions 扩展工具】部分。
|
|
111
149
|
|
|
150
|
+
## 嵌套参数支持
|
|
151
|
+
|
|
152
|
+
`ext_call` 的 `args` 参数支持多层嵌套结构,可以传递复杂的数据对象:
|
|
153
|
+
|
|
154
|
+
### 支持的参数类型
|
|
155
|
+
|
|
156
|
+
| 类型 | 示例 | 说明 |
|
|
157
|
+
| -------- | --------------------------------------------------- | -------------- |
|
|
158
|
+
| 字符串 | `{"name": "Alice"}` | 普通字符串参数 |
|
|
159
|
+
| 数字 | `{"age": 25}` | 数值参数 |
|
|
160
|
+
| 布尔值 | `{"enabled": true}` | 布尔参数 |
|
|
161
|
+
| 数组 | `{"tags": ["a", "b"]}` | 数组参数 |
|
|
162
|
+
| 嵌套对象 | `{"filter": {"name": "Alice"}}` | 对象内嵌对象 |
|
|
163
|
+
| 深层嵌套 | `{"address": {"city": "Beijing", "zip": "100000"}}` | 多层嵌套 |
|
|
164
|
+
|
|
165
|
+
### 调用示例
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// 简单参数
|
|
169
|
+
ext_call({
|
|
170
|
+
plugin: 'python',
|
|
171
|
+
tool: 'my-plugin_query',
|
|
172
|
+
args: { table: 'users' },
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// 嵌套 filter
|
|
176
|
+
ext_call({
|
|
177
|
+
plugin: 'python',
|
|
178
|
+
tool: 'my-plugin_query_data',
|
|
179
|
+
args: {
|
|
180
|
+
filter: {
|
|
181
|
+
name: 'Alice',
|
|
182
|
+
age: 25,
|
|
183
|
+
tags: ['developer', 'python'],
|
|
184
|
+
address: {
|
|
185
|
+
city: 'Beijing',
|
|
186
|
+
zip: '100000',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// 带 options 的复杂查询
|
|
193
|
+
ext_call({
|
|
194
|
+
plugin: 'python',
|
|
195
|
+
tool: 'my-plugin_query_data',
|
|
196
|
+
args: {
|
|
197
|
+
filter: { status: 'active' },
|
|
198
|
+
options: {
|
|
199
|
+
limit: 10,
|
|
200
|
+
sort: 'created_at',
|
|
201
|
+
order: 'desc',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Python 端接收
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
def query_data(params):
|
|
211
|
+
# 访问顶层参数
|
|
212
|
+
filter_obj = params.get("filter", {})
|
|
213
|
+
options = params.get("options", {})
|
|
214
|
+
|
|
215
|
+
# 访问嵌套参数
|
|
216
|
+
name = filter_obj.get("name")
|
|
217
|
+
tags = filter_obj.get("tags", [])
|
|
218
|
+
city = filter_obj.get("address", {}).get("city")
|
|
219
|
+
|
|
220
|
+
# 访问深层嵌套
|
|
221
|
+
limit = options.get("limit", 100)
|
|
222
|
+
sort = options.get("sort", "id")
|
|
223
|
+
|
|
224
|
+
return {"success": True, "result": {...}}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 注意事项
|
|
228
|
+
|
|
229
|
+
1. **参数名简写**:`ext_call` 会将 `my-plugin_tool` 自动简写为 `my-plugin_xxx`
|
|
230
|
+
2. **嵌套深度**:支持任意深度的嵌套对象
|
|
231
|
+
3. **空值处理**:使用 `.get()` 方法并提供默认值,避免 KeyError
|
|
232
|
+
4. **数组对象**:支持数组和嵌套对象的任意组合
|
|
233
|
+
|
|
112
234
|
## 示例:天气查询插件
|
|
113
235
|
|
|
114
236
|
```python
|