foliko 1.0.84 → 1.0.86
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/code-assistant.json +14 -0
- package/.agent/agents/email-assistant.json +14 -0
- package/.agent/agents/file-assistant.json +15 -0
- package/.agent/agents/system-assistant.json +15 -0
- package/.agent/agents/web-assistant.json +12 -0
- package/.agent/data/ambient/goals.json +50 -0
- package/.agent/data/ambient/memories.json +7 -0
- package/.agent/data/default.json +4156 -244
- package/.agent/data/plugins-state.json +162 -174
- package/.agent/data/scheduler/tasks.json +1 -0
- package/.agent/data/weixin.json +6 -0
- package/.agent/mcp_config.json +1 -0
- package/.agent/package.json +8 -0
- package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
- package/.agent/plugins/daytona/README.md +89 -0
- package/.agent/plugins/daytona/index.js +377 -0
- package/.agent/plugins/daytona/package.json +12 -0
- package/.agent/plugins/marknative/README.md +134 -0
- package/.agent/plugins/marknative/index.js +233 -0
- package/.agent/plugins/marknative/package.json +12 -0
- package/.agent/plugins/marknative/update-readme.js +134 -0
- package/.agent/plugins/system-info/index.js +387 -0
- package/.agent/plugins/system-info/package.json +4 -0
- package/.agent/plugins/system-info/test.js +40 -0
- package/.agent/plugins/temp-repo/LICENSE +201 -0
- package/.agent/plugins/{puppeteer-plugin → temp-repo/puppeteer-plugin}/index.js +101 -3
- package/.agent/plugins/test_plugin.py +304 -0
- package/.agent/plugins.json +14 -5
- package/.agent/python-scripts/test_sample.py +24 -0
- package/.agent/skills/agent-browser/SKILL.md +311 -0
- package/.agent/skills/agent-browser/TEST_PLAN.md +200 -0
- package/.agent/skills/sysinfo/SKILL.md +38 -0
- package/.agent/skills/sysinfo/system-info.sh +130 -0
- package/.agent/skills/workflow/SKILL.md +324 -0
- package/.agent/workflows/email-digest.json +50 -0
- package/.agent/workflows/file-backup.json +21 -0
- package/.agent/workflows/get-ip-notify.json +32 -0
- package/.agent/workflows/news-aggregator.json +93 -0
- package/.agent/workflows/news-dashboard-v2.json +94 -0
- package/.agent/workflows/notification-batch.json +32 -0
- package/.claude/settings.local.json +171 -178
- package/.env.example +56 -56
- package/README.md +441 -441
- package/package.json +2 -2
- package/plugins/ambient-agent/EventWatcher.js +4 -4
- package/plugins/extension-executor-plugin.js +52 -1
- package/plugins/file-system-plugin.js +44 -5
- package/plugins/session-plugin.js +3 -3
- package/plugins/weixin-plugin.js +278 -29
- package/skills/find-skills/AGENTS.md +162 -162
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/foliko-dev/SKILL.md +67 -0
- package/skills/python-plugin-dev/SKILL.md +238 -238
- package/src/core/agent-chat.js +11 -21
- package/.agent/.shared/ui-ux-pro-max/data/charts.csv +0 -26
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +0 -58
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +0 -258
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +0 -106
- package/.agent/ARCHITECTURE.md +0 -288
- package/.agent/agents/ambient-agent.md +0 -57
- package/.agent/agents/debugger.md +0 -55
- package/.agent/agents/email-assistant.md +0 -49
- package/.agent/agents/file-manager.md +0 -42
- package/.agent/agents/python-developer.md +0 -60
- package/.agent/agents/scheduler.md +0 -59
- package/.agent/agents/web-developer.md +0 -45
- package/.agent/data/puppeteer-sessions/undefined.json +0 -6
- package/.agent/mcp_config_updated.json +0 -12
- package/.agent/rules/GEMINI.md +0 -273
- package/.agent/rules/allow-rule.md +0 -77
- package/.agent/rules/log-rule.md +0 -83
- package/.agent/rules/security-rule.md +0 -93
- package/.agent/scripts/auto_preview.py +0 -148
- package/.agent/scripts/checklist.py +0 -217
- package/.agent/scripts/session_manager.py +0 -120
- package/.agent/scripts/verify_all.py +0 -327
- package/.agent/skills/api-patterns/SKILL.md +0 -81
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/scripts/api_validator.py +0 -211
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/SKILL.md +0 -75
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/app-builder/templates/SKILL.md +0 -39
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
- package/.agent/skills/architecture/SKILL.md +0 -55
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/clean-code/SKILL.md +0 -201
- package/.agent/skills/doc.md +0 -177
- package/.agent/skills/frontend-design/SKILL.md +0 -418
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -311
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +0 -183
- package/.agent/skills/frontend-design/scripts/ux_audit.py +0 -722
- package/.agent/skills/frontend-design/typography-system.md +0 -345
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/i18n-localization/SKILL.md +0 -154
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +0 -241
- package/.agent/skills/mcp-builder/SKILL.md +0 -176
- package/.agent/skills/web-design-guidelines/SKILL.md +0 -57
- package/.agent/workflows/brainstorm.md +0 -113
- package/.agent/workflows/create.md +0 -59
- package/.agent/workflows/debug.md +0 -103
- package/.agent/workflows/deploy.md +0 -176
- package/.agent/workflows/enhance.md +0 -63
- package/.agent/workflows/orchestrate.md +0 -237
- package/.agent/workflows/plan.md +0 -89
- package/.agent/workflows/preview.md +0 -81
- package/.agent/workflows/simple-test.md +0 -42
- package/.agent/workflows/status.md +0 -86
- package/.agent/workflows/structured-orchestrate.md +0 -180
- package/.agent/workflows/test.md +0 -144
- package/.agent/workflows/ui-ux-pro-max.md +0 -296
- /package/.agent/plugins/{puppeteer-plugin → temp-repo/puppeteer-plugin}/README.md +0 -0
- /package/.agent/plugins/{puppeteer-plugin → temp-repo/puppeteer-plugin}/package.json +0 -0
|
@@ -1,238 +1,238 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: python-plugin-dev
|
|
3
|
-
description: Python 插件开发指南。当用户说"创建 Python 插件"、"用 Python 写插件"时立即调用此 skill。
|
|
4
|
-
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Python 插件开发
|
|
8
|
-
|
|
9
|
-
## 概述
|
|
10
|
-
|
|
11
|
-
Python 插件允许用 Python 语言开发工具,插件代码运行在 Python 环境中,可以调用所有 Python 库。
|
|
12
|
-
|
|
13
|
-
## 插件存放位置
|
|
14
|
-
|
|
15
|
-
`.agent/plugins/*.py`
|
|
16
|
-
|
|
17
|
-
## 插件结构
|
|
18
|
-
|
|
19
|
-
```python
|
|
20
|
-
# .agent/plugins/my-plugin.py
|
|
21
|
-
|
|
22
|
-
PLUGIN = {
|
|
23
|
-
"name": "my-plugin",
|
|
24
|
-
"version": "1.0.0",
|
|
25
|
-
"description": "我的 Python 插件"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
TOOLS = [
|
|
29
|
-
{
|
|
30
|
-
"name": "hello",
|
|
31
|
-
"description": "问候工具",
|
|
32
|
-
"params": {"name": "string"}
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"name": "calc",
|
|
36
|
-
"description": "计算器工具",
|
|
37
|
-
"params": {"a": "number", "b": "number", "op": "string"}
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
# === 工具实现 ===
|
|
42
|
-
|
|
43
|
-
def hello(params):
|
|
44
|
-
"""问候工具"""
|
|
45
|
-
name = params.get("name", "World")
|
|
46
|
-
return {"success": True, "result": f"Hello, {name}!"}
|
|
47
|
-
|
|
48
|
-
def calc(params):
|
|
49
|
-
"""计算器工具"""
|
|
50
|
-
a = params.get("a", 0)
|
|
51
|
-
b = params.get("b", 0)
|
|
52
|
-
op = params.get("op", "add")
|
|
53
|
-
|
|
54
|
-
if op == "add":
|
|
55
|
-
result = a + b
|
|
56
|
-
elif op == "sub":
|
|
57
|
-
result = a - b
|
|
58
|
-
elif op == "mul":
|
|
59
|
-
result = a * b
|
|
60
|
-
elif op == "div":
|
|
61
|
-
if b == 0:
|
|
62
|
-
return {"success": False, "error": "Division by zero"}
|
|
63
|
-
result = a / b
|
|
64
|
-
else:
|
|
65
|
-
return {"success": False, "error": f"Unknown operation: {op}"}
|
|
66
|
-
|
|
67
|
-
return {"success": True, "result": result}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**重要**:`tools` 字段定义了插件提供的所有工具。框架会自动:
|
|
71
|
-
|
|
72
|
-
1. 将这些工具注册到 ExtensionExecutor
|
|
73
|
-
2. 附加到系统提示词【Extensions 扩展工具】部分
|
|
74
|
-
3. 可通过 `ext_call` 调用
|
|
75
|
-
|
|
76
|
-
## 工具函数规范
|
|
77
|
-
|
|
78
|
-
| 规范 | 说明 |
|
|
79
|
-
| ------------ | -------------------- |
|
|
80
|
-
| 返回 dict | 必须是 Python 字典 |
|
|
81
|
-
| success 字段 | `true` 或 `false` |
|
|
82
|
-
| result 字段 | 成功时返回的结果 |
|
|
83
|
-
| error 字段 | 失败时返回的错误信息 |
|
|
84
|
-
|
|
85
|
-
## 返回值格式
|
|
86
|
-
|
|
87
|
-
```python
|
|
88
|
-
# 成功
|
|
89
|
-
{"success": True, "result": "返回值"}
|
|
90
|
-
|
|
91
|
-
# 失败
|
|
92
|
-
{"success": False, "error": "错误信息"}
|
|
93
|
-
|
|
94
|
-
# 返回复杂数据
|
|
95
|
-
{"success": True, "result": {"key": "value", "list": [1, 2, 3]}}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## 使用方式
|
|
99
|
-
|
|
100
|
-
通过 `ext_call` 调用:
|
|
101
|
-
|
|
102
|
-
```javascript
|
|
103
|
-
ext_call({
|
|
104
|
-
plugin: 'my-plugin', // 插件名称
|
|
105
|
-
tool: 'hello', // 工具名称
|
|
106
|
-
args: { name: 'Foliko' }, // 工具参数
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
工具会自动出现在系统提示词的【Extensions 扩展工具】部分。
|
|
111
|
-
|
|
112
|
-
## 示例:天气查询插件
|
|
113
|
-
|
|
114
|
-
```python
|
|
115
|
-
# .agent/plugins/weather.py
|
|
116
|
-
|
|
117
|
-
PLUGIN = {
|
|
118
|
-
"name": "weather",
|
|
119
|
-
"version": "1.0.0",
|
|
120
|
-
"description": "天气查询插件"
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
TOOLS = [
|
|
124
|
-
{
|
|
125
|
-
"name": "get_weather",
|
|
126
|
-
"description": "查询天气",
|
|
127
|
-
"params": {"city": "string"}
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
|
|
131
|
-
def get_weather(params):
|
|
132
|
-
import requests
|
|
133
|
-
|
|
134
|
-
city = params.get("city", "北京")
|
|
135
|
-
|
|
136
|
-
try:
|
|
137
|
-
response = requests.get(
|
|
138
|
-
f"https://wttr.in/{city}?format=j1",
|
|
139
|
-
timeout=5
|
|
140
|
-
)
|
|
141
|
-
data = response.json()
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
"success": True,
|
|
145
|
-
"result": {
|
|
146
|
-
"city": city,
|
|
147
|
-
"temperature": data["current_condition"][0]["temp_C"],
|
|
148
|
-
"weather": data["current_condition"][0]["weatherDesc"][0]["value"]
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
except Exception as e:
|
|
152
|
-
return {"success": False, "error": str(e)}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## 示例:文件处理插件
|
|
156
|
-
|
|
157
|
-
```python
|
|
158
|
-
# .agent/plugins/file_processor.py
|
|
159
|
-
|
|
160
|
-
PLUGIN = {
|
|
161
|
-
"name": "file_processor",
|
|
162
|
-
"version": "1.0.0",
|
|
163
|
-
"description": "文件处理插件"
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
TOOLS = [
|
|
167
|
-
{
|
|
168
|
-
"name": "read_file",
|
|
169
|
-
"description": "读取文件",
|
|
170
|
-
"params": {"path": "string"}
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
"name": "write_file",
|
|
174
|
-
"description": "写入文件",
|
|
175
|
-
"params": {"path": "string", "content": "string"}
|
|
176
|
-
}
|
|
177
|
-
]
|
|
178
|
-
|
|
179
|
-
def read_file(params):
|
|
180
|
-
import os
|
|
181
|
-
|
|
182
|
-
filepath = params.get("path")
|
|
183
|
-
if not filepath:
|
|
184
|
-
return {"success": False, "error": "path is required"}
|
|
185
|
-
|
|
186
|
-
try:
|
|
187
|
-
with open(filepath, "r", encoding="utf-8") as f:
|
|
188
|
-
content = f.read()
|
|
189
|
-
return {"success": True, "result": content}
|
|
190
|
-
except Exception as e:
|
|
191
|
-
return {"success": False, "error": str(e)}
|
|
192
|
-
|
|
193
|
-
def write_file(params):
|
|
194
|
-
import os
|
|
195
|
-
|
|
196
|
-
filepath = params.get("path")
|
|
197
|
-
content = params.get("content", "")
|
|
198
|
-
|
|
199
|
-
if not filepath:
|
|
200
|
-
return {"success": False, "error": "path is required"}
|
|
201
|
-
|
|
202
|
-
try:
|
|
203
|
-
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
204
|
-
with open(filepath, "w", encoding="utf-8") as f:
|
|
205
|
-
f.write(content)
|
|
206
|
-
return {"success": True, "result": f"Written to {filepath}"}
|
|
207
|
-
except Exception as e:
|
|
208
|
-
return {"success": False, "error": str(e)}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## 注意事项
|
|
212
|
-
|
|
213
|
-
1. **文件格式** - 必须是单个 `.py` 文件
|
|
214
|
-
2. **必须定义 `PLUGIN`** - 插件元信息
|
|
215
|
-
3. **必须定义 `TOOLS`** - 工具列表
|
|
216
|
-
4. **工具函数名** - 必须与 TOOLS 中定义的 name 一致
|
|
217
|
-
5. **异常处理** - 所有可能出错的地方都要 try-except
|
|
218
|
-
6. **编码** - 文件使用 UTF-8 编码
|
|
219
|
-
|
|
220
|
-
## 开发流程
|
|
221
|
-
|
|
222
|
-
1. **编写插件代码** - 在 `.agent/plugins/` 下创建 `.py` 文件
|
|
223
|
-
2. **自动加载** - 框架启动时自动注册工具
|
|
224
|
-
3. **调试** - 查看返回的 `success` 和 `error` 信息
|
|
225
|
-
|
|
226
|
-
## 常用 Python 库
|
|
227
|
-
|
|
228
|
-
插件中可以使用的常用库:
|
|
229
|
-
|
|
230
|
-
| 库 | 用途 | 导入方式 |
|
|
231
|
-
| -------- | ---------- | ------------------------------- |
|
|
232
|
-
| requests | HTTP 请求 | `import requests` |
|
|
233
|
-
| json | JSON 处理 | `import json` |
|
|
234
|
-
| os | 系统操作 | `import os` |
|
|
235
|
-
| pathlib | 路径处理 | `from pathlib import Path` |
|
|
236
|
-
| datetime | 日期时间 | `from datetime import datetime` |
|
|
237
|
-
| re | 正则表达式 | `import re` |
|
|
238
|
-
| csv | CSV 处理 | `import csv` |
|
|
1
|
+
---
|
|
2
|
+
name: python-plugin-dev
|
|
3
|
+
description: Python 插件开发指南。当用户说"创建 Python 插件"、"用 Python 写插件"时立即调用此 skill。
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Python 插件开发
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
|
|
11
|
+
Python 插件允许用 Python 语言开发工具,插件代码运行在 Python 环境中,可以调用所有 Python 库。
|
|
12
|
+
|
|
13
|
+
## 插件存放位置
|
|
14
|
+
|
|
15
|
+
`.agent/plugins/*.py`
|
|
16
|
+
|
|
17
|
+
## 插件结构
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
# .agent/plugins/my-plugin.py
|
|
21
|
+
|
|
22
|
+
PLUGIN = {
|
|
23
|
+
"name": "my-plugin",
|
|
24
|
+
"version": "1.0.0",
|
|
25
|
+
"description": "我的 Python 插件"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
TOOLS = [
|
|
29
|
+
{
|
|
30
|
+
"name": "hello",
|
|
31
|
+
"description": "问候工具",
|
|
32
|
+
"params": {"name": "string"}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "calc",
|
|
36
|
+
"description": "计算器工具",
|
|
37
|
+
"params": {"a": "number", "b": "number", "op": "string"}
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# === 工具实现 ===
|
|
42
|
+
|
|
43
|
+
def hello(params):
|
|
44
|
+
"""问候工具"""
|
|
45
|
+
name = params.get("name", "World")
|
|
46
|
+
return {"success": True, "result": f"Hello, {name}!"}
|
|
47
|
+
|
|
48
|
+
def calc(params):
|
|
49
|
+
"""计算器工具"""
|
|
50
|
+
a = params.get("a", 0)
|
|
51
|
+
b = params.get("b", 0)
|
|
52
|
+
op = params.get("op", "add")
|
|
53
|
+
|
|
54
|
+
if op == "add":
|
|
55
|
+
result = a + b
|
|
56
|
+
elif op == "sub":
|
|
57
|
+
result = a - b
|
|
58
|
+
elif op == "mul":
|
|
59
|
+
result = a * b
|
|
60
|
+
elif op == "div":
|
|
61
|
+
if b == 0:
|
|
62
|
+
return {"success": False, "error": "Division by zero"}
|
|
63
|
+
result = a / b
|
|
64
|
+
else:
|
|
65
|
+
return {"success": False, "error": f"Unknown operation: {op}"}
|
|
66
|
+
|
|
67
|
+
return {"success": True, "result": result}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**重要**:`tools` 字段定义了插件提供的所有工具。框架会自动:
|
|
71
|
+
|
|
72
|
+
1. 将这些工具注册到 ExtensionExecutor
|
|
73
|
+
2. 附加到系统提示词【Extensions 扩展工具】部分
|
|
74
|
+
3. 可通过 `ext_call` 调用
|
|
75
|
+
|
|
76
|
+
## 工具函数规范
|
|
77
|
+
|
|
78
|
+
| 规范 | 说明 |
|
|
79
|
+
| ------------ | -------------------- |
|
|
80
|
+
| 返回 dict | 必须是 Python 字典 |
|
|
81
|
+
| success 字段 | `true` 或 `false` |
|
|
82
|
+
| result 字段 | 成功时返回的结果 |
|
|
83
|
+
| error 字段 | 失败时返回的错误信息 |
|
|
84
|
+
|
|
85
|
+
## 返回值格式
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# 成功
|
|
89
|
+
{"success": True, "result": "返回值"}
|
|
90
|
+
|
|
91
|
+
# 失败
|
|
92
|
+
{"success": False, "error": "错误信息"}
|
|
93
|
+
|
|
94
|
+
# 返回复杂数据
|
|
95
|
+
{"success": True, "result": {"key": "value", "list": [1, 2, 3]}}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 使用方式
|
|
99
|
+
|
|
100
|
+
通过 `ext_call` 调用:
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
ext_call({
|
|
104
|
+
plugin: 'my-plugin', // 插件名称
|
|
105
|
+
tool: 'hello', // 工具名称
|
|
106
|
+
args: { name: 'Foliko' }, // 工具参数
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
工具会自动出现在系统提示词的【Extensions 扩展工具】部分。
|
|
111
|
+
|
|
112
|
+
## 示例:天气查询插件
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# .agent/plugins/weather.py
|
|
116
|
+
|
|
117
|
+
PLUGIN = {
|
|
118
|
+
"name": "weather",
|
|
119
|
+
"version": "1.0.0",
|
|
120
|
+
"description": "天气查询插件"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
TOOLS = [
|
|
124
|
+
{
|
|
125
|
+
"name": "get_weather",
|
|
126
|
+
"description": "查询天气",
|
|
127
|
+
"params": {"city": "string"}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
def get_weather(params):
|
|
132
|
+
import requests
|
|
133
|
+
|
|
134
|
+
city = params.get("city", "北京")
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
response = requests.get(
|
|
138
|
+
f"https://wttr.in/{city}?format=j1",
|
|
139
|
+
timeout=5
|
|
140
|
+
)
|
|
141
|
+
data = response.json()
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
"success": True,
|
|
145
|
+
"result": {
|
|
146
|
+
"city": city,
|
|
147
|
+
"temperature": data["current_condition"][0]["temp_C"],
|
|
148
|
+
"weather": data["current_condition"][0]["weatherDesc"][0]["value"]
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
except Exception as e:
|
|
152
|
+
return {"success": False, "error": str(e)}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 示例:文件处理插件
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# .agent/plugins/file_processor.py
|
|
159
|
+
|
|
160
|
+
PLUGIN = {
|
|
161
|
+
"name": "file_processor",
|
|
162
|
+
"version": "1.0.0",
|
|
163
|
+
"description": "文件处理插件"
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
TOOLS = [
|
|
167
|
+
{
|
|
168
|
+
"name": "read_file",
|
|
169
|
+
"description": "读取文件",
|
|
170
|
+
"params": {"path": "string"}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "write_file",
|
|
174
|
+
"description": "写入文件",
|
|
175
|
+
"params": {"path": "string", "content": "string"}
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
def read_file(params):
|
|
180
|
+
import os
|
|
181
|
+
|
|
182
|
+
filepath = params.get("path")
|
|
183
|
+
if not filepath:
|
|
184
|
+
return {"success": False, "error": "path is required"}
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
188
|
+
content = f.read()
|
|
189
|
+
return {"success": True, "result": content}
|
|
190
|
+
except Exception as e:
|
|
191
|
+
return {"success": False, "error": str(e)}
|
|
192
|
+
|
|
193
|
+
def write_file(params):
|
|
194
|
+
import os
|
|
195
|
+
|
|
196
|
+
filepath = params.get("path")
|
|
197
|
+
content = params.get("content", "")
|
|
198
|
+
|
|
199
|
+
if not filepath:
|
|
200
|
+
return {"success": False, "error": "path is required"}
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
|
204
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
205
|
+
f.write(content)
|
|
206
|
+
return {"success": True, "result": f"Written to {filepath}"}
|
|
207
|
+
except Exception as e:
|
|
208
|
+
return {"success": False, "error": str(e)}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 注意事项
|
|
212
|
+
|
|
213
|
+
1. **文件格式** - 必须是单个 `.py` 文件
|
|
214
|
+
2. **必须定义 `PLUGIN`** - 插件元信息
|
|
215
|
+
3. **必须定义 `TOOLS`** - 工具列表
|
|
216
|
+
4. **工具函数名** - 必须与 TOOLS 中定义的 name 一致
|
|
217
|
+
5. **异常处理** - 所有可能出错的地方都要 try-except
|
|
218
|
+
6. **编码** - 文件使用 UTF-8 编码
|
|
219
|
+
|
|
220
|
+
## 开发流程
|
|
221
|
+
|
|
222
|
+
1. **编写插件代码** - 在 `.agent/plugins/` 下创建 `.py` 文件
|
|
223
|
+
2. **自动加载** - 框架启动时自动注册工具
|
|
224
|
+
3. **调试** - 查看返回的 `success` 和 `error` 信息
|
|
225
|
+
|
|
226
|
+
## 常用 Python 库
|
|
227
|
+
|
|
228
|
+
插件中可以使用的常用库:
|
|
229
|
+
|
|
230
|
+
| 库 | 用途 | 导入方式 |
|
|
231
|
+
| -------- | ---------- | ------------------------------- |
|
|
232
|
+
| requests | HTTP 请求 | `import requests` |
|
|
233
|
+
| json | JSON 处理 | `import json` |
|
|
234
|
+
| os | 系统操作 | `import os` |
|
|
235
|
+
| pathlib | 路径处理 | `from pathlib import Path` |
|
|
236
|
+
| datetime | 日期时间 | `from datetime import datetime` |
|
|
237
|
+
| re | 正则表达式 | `import re` |
|
|
238
|
+
| csv | CSV 处理 | `import csv` |
|
package/src/core/agent-chat.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { EventEmitter } = require('../utils/event-emitter');
|
|
7
7
|
const { logger } = require('../utils/logger');
|
|
8
|
-
const { generateText,
|
|
8
|
+
const { generateText, stepCountIs } = require('ai');
|
|
9
9
|
const { prepareMessagesForAPI } = require('../utils');
|
|
10
10
|
|
|
11
11
|
// 模型上下文限制表(留 15-20% 余量给 system prompt 和输出)
|
|
@@ -697,8 +697,6 @@ ${truncatedContent}${truncatedNote}
|
|
|
697
697
|
);
|
|
698
698
|
// 使用带超时控制的压缩
|
|
699
699
|
await this._compressContext();
|
|
700
|
-
} else {
|
|
701
|
-
logger.info(`Context OK: ${totalTokens}/${this._maxContextTokens} tokens`);
|
|
702
700
|
}
|
|
703
701
|
|
|
704
702
|
const maxSteps = options.maxSteps || this._maxSteps;
|
|
@@ -708,24 +706,20 @@ ${truncatedContent}${truncatedNote}
|
|
|
708
706
|
throw new Error('AI client not configured.');
|
|
709
707
|
}
|
|
710
708
|
|
|
711
|
-
// 准备传给 agent
|
|
712
|
-
|
|
713
|
-
messages: this._messages,
|
|
714
|
-
reasoning: 'all',
|
|
715
|
-
toolCalls: 'none',
|
|
716
|
-
});
|
|
717
|
-
|
|
709
|
+
// 准备传给 agent 的消息
|
|
710
|
+
// ToolLoopAgent 会自动处理消息格式,不需要手动 prune
|
|
718
711
|
const agent = new ToolLoopAgent({
|
|
719
712
|
model: this._aiClient,
|
|
720
713
|
instructions: this._systemPrompt,
|
|
721
714
|
tools: tools,
|
|
715
|
+
//stopWhen: stepCountIs(maxSteps),
|
|
722
716
|
prepareStep: async ({ stepNumber, messages }) =>
|
|
723
717
|
this._prepareStepForPruning(stepNumber, messages),
|
|
724
718
|
});
|
|
725
719
|
|
|
726
720
|
// 使用 runWithContext 让工具执行时能获取 sessionId
|
|
727
721
|
const result = await framework.runWithContext(context, async () => {
|
|
728
|
-
return agent.generate({ messages:
|
|
722
|
+
return agent.generate({ messages: this._messages, ...this.providerOptions });
|
|
729
723
|
});
|
|
730
724
|
|
|
731
725
|
this._messages.push(...result.response.messages);
|
|
@@ -790,6 +784,7 @@ ${truncatedContent}${truncatedNote}
|
|
|
790
784
|
const systemPromptTokens = this._countTokens(this._systemPrompt);
|
|
791
785
|
const totalTokens = messagesTokens + toolsTokens + systemPromptTokens;
|
|
792
786
|
const limit = this._maxContextTokens * 0.7; // 降低到 70%
|
|
787
|
+
//console.log(messagesTokens,toolsTokens,systemPromptTokens,totalTokens,this._maxContextTokens)
|
|
793
788
|
// 对于流式调用,如果上下文太大,先压缩再开始
|
|
794
789
|
if (totalTokens > limit) {
|
|
795
790
|
logger.info(
|
|
@@ -805,18 +800,13 @@ ${truncatedContent}${truncatedNote}
|
|
|
805
800
|
throw new Error('AI client not configured.');
|
|
806
801
|
}
|
|
807
802
|
|
|
808
|
-
// 准备传给 agent
|
|
809
|
-
//
|
|
810
|
-
const messagesForAgent = pruneMessages({
|
|
811
|
-
messages: this._messages,
|
|
812
|
-
reasoning: 'all',
|
|
813
|
-
toolCalls: 'none', // 保留所有 tool calls,避免丢失工具执行历史
|
|
814
|
-
});
|
|
815
|
-
|
|
803
|
+
// 准备传给 agent 的消息
|
|
804
|
+
// ToolLoopAgent 会自动处理消息格式,不需要手动 prune
|
|
816
805
|
const agent = new ToolLoopAgent({
|
|
817
806
|
model: this._aiClient,
|
|
818
807
|
instructions: this._systemPrompt,
|
|
819
808
|
tools: tools,
|
|
809
|
+
//stopWhen: stepCountIs(maxSteps),
|
|
820
810
|
prepareStep: async ({ stepNumber, messages }) =>
|
|
821
811
|
this._prepareStepForPruning(stepNumber, messages),
|
|
822
812
|
});
|
|
@@ -824,7 +814,7 @@ ${truncatedContent}${truncatedNote}
|
|
|
824
814
|
// 使用 runWithContext 让工具执行时能获取 sessionId(支持并行)
|
|
825
815
|
const result = await framework.runWithContext(context, async () => {
|
|
826
816
|
return agent.stream({
|
|
827
|
-
messages:
|
|
817
|
+
messages: this._messages,
|
|
828
818
|
...this.providerOptions,
|
|
829
819
|
});
|
|
830
820
|
});
|
|
@@ -872,7 +862,7 @@ ${truncatedContent}${truncatedNote}
|
|
|
872
862
|
* @private
|
|
873
863
|
*/
|
|
874
864
|
_prepareStepForPruning(stepNumber, messages) {
|
|
875
|
-
if (messages.length <=
|
|
865
|
+
if (messages.length <= 50) {
|
|
876
866
|
return {};
|
|
877
867
|
}
|
|
878
868
|
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
No,Data Type,Keywords,Best Chart Type,Secondary Options,Color Guidance,Performance Impact,Accessibility Notes,Library Recommendation,Interactive Level
|
|
2
|
-
1,Trend Over Time,"trend, time-series, line, growth, timeline, progress",Line Chart,"Area Chart, Smooth Area",Primary: #0080FF. Multiple series: use distinct colors. Fill: 20% opacity,⚡ Excellent (optimized),✓ Clear line patterns for colorblind users. Add pattern overlays.,"Chart.js, Recharts, ApexCharts",Hover + Zoom
|
|
3
|
-
2,Compare Categories,"compare, categories, bar, comparison, ranking",Bar Chart (Horizontal or Vertical),"Column Chart, Grouped Bar",Each bar: distinct color. Category: grouped same color. Sorted: descending order,⚡ Excellent,✓ Easy to compare. Add value labels on bars for clarity.,"Chart.js, Recharts, D3.js",Hover + Sort
|
|
4
|
-
3,Part-to-Whole,"part-to-whole, pie, donut, percentage, proportion, share",Pie Chart or Donut,"Stacked Bar, Treemap",Colors: 5-6 max. Contrasting palette. Large slices first. Use labels.,⚡ Good (limit 6 slices),⚠ Hard for accessibility. Better: Stacked bar with legend. Avoid pie if >5 items.,"Chart.js, Recharts, D3.js",Hover + Drill
|
|
5
|
-
4,Correlation/Distribution,"correlation, distribution, scatter, relationship, pattern",Scatter Plot or Bubble Chart,"Heat Map, Matrix",Color axis: gradient (blue-red). Size: relative. Opacity: 0.6-0.8 to show density,⚠ Moderate (many points),⚠ Provide data table alternative. Use pattern + color distinction.,"D3.js, Plotly, Recharts",Hover + Brush
|
|
6
|
-
5,Heatmap/Intensity,"heatmap, heat-map, intensity, density, matrix",Heat Map or Choropleth,"Grid Heat Map, Bubble Heat",Gradient: Cool (blue) to Hot (red). Scale: clear legend. Divergent for ±data,⚡ Excellent (color CSS),⚠ Colorblind: Use pattern overlay. Provide numerical legend.,"D3.js, Plotly, ApexCharts",Hover + Zoom
|
|
7
|
-
6,Geographic Data,"geographic, map, location, region, geo, spatial","Choropleth Map, Bubble Map",Geographic Heat Map,Regional: single color gradient or categorized colors. Legend: clear scale,⚠ Moderate (rendering),⚠ Include text labels for regions. Provide data table alternative.,"D3.js, Mapbox, Leaflet",Pan + Zoom + Drill
|
|
8
|
-
7,Funnel/Flow,funnel/flow,"Funnel Chart, Sankey",Waterfall (for flows),Stages: gradient (starting color → ending color). Show conversion %,⚡ Good,✓ Clear stage labels + percentages. Good for accessibility if labeled.,"D3.js, Recharts, Custom SVG",Hover + Drill
|
|
9
|
-
8,Performance vs Target,performance-vs-target,Gauge Chart or Bullet Chart,"Dial, Thermometer",Performance: Red→Yellow→Green gradient. Target: marker line. Threshold colors,⚡ Good,✓ Add numerical value + percentage label beside gauge.,"D3.js, ApexCharts, Custom SVG",Hover
|
|
10
|
-
9,Time-Series Forecast,time-series-forecast,Line with Confidence Band,Ribbon Chart,Actual: solid line #0080FF. Forecast: dashed #FF9500. Band: light shading,⚡ Good,✓ Clearly distinguish actual vs forecast. Add legend.,"Chart.js, ApexCharts, Plotly",Hover + Toggle
|
|
11
|
-
10,Anomaly Detection,anomaly-detection,Line Chart with Highlights,Scatter with Alert,Normal: blue #0080FF. Anomaly: red #FF0000 circle/square marker + alert,⚡ Good,✓ Circle/marker for anomalies. Add text alert annotation.,"D3.js, Plotly, ApexCharts",Hover + Alert
|
|
12
|
-
11,Hierarchical/Nested Data,hierarchical/nested-data,Treemap,"Sunburst, Nested Donut, Icicle",Parent: distinct hues. Children: lighter shades. White borders 2-3px.,⚠ Moderate,⚠ Poor - provide table alternative. Label large areas.,"D3.js, Recharts, ApexCharts",Hover + Drilldown
|
|
13
|
-
12,Flow/Process Data,flow/process-data,Sankey Diagram,"Alluvial, Chord Diagram",Gradient from source to target. Opacity 0.4-0.6 for flows.,⚠ Moderate,⚠ Poor - provide flow table alternative.,"D3.js (d3-sankey), Plotly",Hover + Drilldown
|
|
14
|
-
13,Cumulative Changes,cumulative-changes,Waterfall Chart,"Stacked Bar, Cascade",Increases: #4CAF50. Decreases: #F44336. Start: #2196F3. End: #0D47A1.,⚡ Good,✓ Good - clear directional colors with labels.,"ApexCharts, Highcharts, Plotly",Hover
|
|
15
|
-
14,Multi-Variable Comparison,multi-variable-comparison,Radar/Spider Chart,"Parallel Coordinates, Grouped Bar",Single: #0080FF 20% fill. Multiple: distinct colors per dataset.,⚡ Good,⚠ Moderate - limit 5-8 axes. Add data table.,"Chart.js, Recharts, ApexCharts",Hover + Toggle
|
|
16
|
-
15,Stock/Trading OHLC,stock/trading-ohlc,Candlestick Chart,"OHLC Bar, Heikin-Ashi",Bullish: #26A69A. Bearish: #EF5350. Volume: 40% opacity below.,⚡ Good,⚠ Moderate - provide OHLC data table.,"Lightweight Charts (TradingView), ApexCharts",Real-time + Hover + Zoom
|
|
17
|
-
16,Relationship/Connection Data,relationship/connection-data,Network Graph,"Hierarchical Tree, Adjacency Matrix",Node types: categorical colors. Edges: #90A4AE 60% opacity.,❌ Poor (500+ nodes struggles),❌ Very Poor - provide adjacency list alternative.,"D3.js (d3-force), Vis.js, Cytoscape.js",Drilldown + Hover + Drag
|
|
18
|
-
17,Distribution/Statistical,distribution/statistical,Box Plot,"Violin Plot, Beeswarm",Box: #BBDEFB. Border: #1976D2. Median: #D32F2F. Outliers: #F44336.,⚡ Excellent,"✓ Good - include stats table (min, Q1, median, Q3, max).","Plotly, D3.js, Chart.js (plugin)",Hover
|
|
19
|
-
18,Performance vs Target (Compact),performance-vs-target-(compact),Bullet Chart,"Gauge, Progress Bar","Ranges: #FFCDD2, #FFF9C4, #C8E6C9. Performance: #1976D2. Target: black 3px.",⚡ Excellent,✓ Excellent - compact with clear values.,"D3.js, Plotly, Custom SVG",Hover
|
|
20
|
-
19,Proportional/Percentage,proportional/percentage,Waffle Chart,"Pictogram, Stacked Bar 100%",10x10 grid. 3-5 categories max. 2-3px spacing between squares.,⚡ Good,✓ Good - better than pie for accessibility.,"D3.js, React-Waffle, Custom CSS Grid",Hover
|
|
21
|
-
20,Hierarchical Proportional,hierarchical-proportional,Sunburst Chart,"Treemap, Icicle, Circle Packing",Center to outer: darker to lighter. 15-20% lighter per level.,⚠ Moderate,⚠ Poor - provide hierarchy table alternative.,"D3.js (d3-hierarchy), Recharts, ApexCharts",Drilldown + Hover
|
|
22
|
-
21,Root Cause Analysis,"root cause, decomposition, tree, hierarchy, drill-down, ai-split",Decomposition Tree,"Decision Tree, Flow Chart",Nodes: #2563EB (Primary) vs #EF4444 (Negative impact). Connectors: Neutral grey.,⚠ Moderate (calculation heavy),✓ clear hierarchy. Allow keyboard navigation for nodes.,"Power BI (native), React-Flow, Custom D3.js",Drill + Expand
|
|
23
|
-
22,3D Spatial Data,"3d, spatial, immersive, terrain, molecular, volumetric",3D Scatter/Surface Plot,"Volumetric Rendering, Point Cloud",Depth cues: lighting/shading. Z-axis: color gradient (cool to warm).,❌ Heavy (WebGL required),❌ Poor - requires alternative 2D view or data table.,"Three.js, Deck.gl, Plotly 3D",Rotate + Zoom + VR
|
|
24
|
-
23,Real-Time Streaming,"streaming, real-time, ticker, live, velocity, pulse",Streaming Area Chart,"Ticker Tape, Moving Gauge",Current: Bright Pulse (#00FF00). History: Fading opacity. Grid: Dark.,⚡ Optimized (canvas/webgl),⚠ Flashing elements - provide pause button. High contrast.,Smoothed D3.js, CanvasJS, SciChart,Real-time + Pause
|
|
25
|
-
24,Sentiment/Emotion,"sentiment, emotion, nlp, opinion, feeling",Word Cloud with Sentiment,"Sentiment Arc, Radar Chart",Positive: #22C55E. Negative: #EF4444. Neutral: #94A3B8. Size = Frequency.,⚡ Good,⚠ Word clouds poor for screen readers. Use list view.,"D3-cloud, Highcharts, Nivo",Hover + Filter
|
|
26
|
-
25,Process Mining,"process, mining, variants, path, bottleneck, log",Process Map / Graph,"Directed Acyclic Graph (DAG), Petri Net",Happy path: #10B981 (Thick). Deviations: #F59E0B (Thin). Bottlenecks: #EF4444.,⚠ Moderate to Heavy,⚠ Complex graphs hard to navigate. Provide path summary.,"React-Flow, Cytoscape.js, Recharts",Drag + Node-Click
|