foliko 1.0.87 → 1.1.1

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.
Files changed (259) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +325 -21
  39. package/.agent/data/plugins-state.json +194 -162
  40. package/.agent/data/puppeteer-sessions/undefined.json +6 -0
  41. package/.agent/mcp_config.json +0 -1
  42. package/.agent/mcp_config_updated.json +12 -0
  43. package/.agent/plugins/poster-plugin/README.md +304 -0
  44. package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
  45. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  46. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  47. 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
  48. package/.agent/plugins/poster-plugin/index.js +13 -0
  49. package/.agent/plugins/poster-plugin/package.json +28 -0
  50. package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
  51. package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
  52. package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
  53. package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
  54. package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
  55. package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
  56. package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
  57. package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
  58. package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
  59. package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
  60. package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
  61. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
  62. package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
  63. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
  64. package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
  65. package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
  66. package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
  67. package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
  68. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
  69. package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
  70. package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
  71. package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
  72. package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
  73. package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
  74. package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
  75. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
  76. package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
  77. package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
  78. package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
  79. package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
  80. package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
  81. package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
  82. package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
  83. package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
  84. package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
  85. package/.agent/plugins/poster-plugin/src/elements/polygon.js +63 -0
  86. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
  87. package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
  88. package/.agent/plugins/poster-plugin/src/elements/text.js +107 -0
  89. package/.agent/plugins/poster-plugin/src/fonts.js +233 -0
  90. package/.agent/plugins/poster-plugin/src/index.js +1658 -0
  91. package/.agent/plugins/poster-plugin/src/presets.js +36 -0
  92. package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
  93. package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
  94. package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
  95. package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
  96. package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
  97. package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
  98. package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
  99. package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/index.js +1 -1
  100. package/.agent/plugins.json +5 -11
  101. package/.agent/rules/GEMINI.md +273 -0
  102. package/.agent/rules/allow-rule.md +77 -0
  103. package/.agent/rules/log-rule.md +83 -0
  104. package/.agent/rules/security-rule.md +93 -0
  105. package/.agent/scripts/auto_preview.py +148 -0
  106. package/.agent/scripts/checklist.py +217 -0
  107. package/.agent/scripts/session_manager.py +120 -0
  108. package/.agent/scripts/verify_all.py +327 -0
  109. package/.agent/sessions/cli_default.json +419 -0
  110. package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +2195 -0
  111. package/.agent/skills/api-patterns/SKILL.md +81 -0
  112. package/.agent/skills/api-patterns/api-style.md +42 -0
  113. package/.agent/skills/api-patterns/auth.md +24 -0
  114. package/.agent/skills/api-patterns/documentation.md +26 -0
  115. package/.agent/skills/api-patterns/graphql.md +41 -0
  116. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  117. package/.agent/skills/api-patterns/response.md +37 -0
  118. package/.agent/skills/api-patterns/rest.md +40 -0
  119. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  120. package/.agent/skills/api-patterns/security-testing.md +122 -0
  121. package/.agent/skills/api-patterns/trpc.md +41 -0
  122. package/.agent/skills/api-patterns/versioning.md +22 -0
  123. package/.agent/skills/app-builder/SKILL.md +75 -0
  124. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  125. package/.agent/skills/app-builder/feature-building.md +53 -0
  126. package/.agent/skills/app-builder/project-detection.md +34 -0
  127. package/.agent/skills/app-builder/scaffolding.md +118 -0
  128. package/.agent/skills/app-builder/tech-stack.md +40 -0
  129. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  130. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  131. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  132. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  133. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  134. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  135. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  136. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  137. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  138. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  139. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  140. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  141. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  142. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  143. package/.agent/skills/architecture/SKILL.md +55 -0
  144. package/.agent/skills/architecture/context-discovery.md +43 -0
  145. package/.agent/skills/architecture/examples.md +94 -0
  146. package/.agent/skills/architecture/pattern-selection.md +68 -0
  147. package/.agent/skills/architecture/patterns-reference.md +50 -0
  148. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  149. package/.agent/skills/clean-code/SKILL.md +201 -0
  150. package/.agent/skills/doc.md +177 -0
  151. package/.agent/skills/frontend-design/SKILL.md +418 -0
  152. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  153. package/.agent/skills/frontend-design/color-system.md +311 -0
  154. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  155. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  156. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  157. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  158. package/.agent/skills/frontend-design/typography-system.md +345 -0
  159. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  160. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  161. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  162. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  163. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  164. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  165. package/.agent/workflows/brainstorm.md +113 -0
  166. package/.agent/workflows/create.md +59 -0
  167. package/.agent/workflows/debug.md +103 -0
  168. package/.agent/workflows/deploy.md +176 -0
  169. package/.agent/workflows/enhance.md +63 -0
  170. package/.agent/workflows/orchestrate.md +237 -0
  171. package/.agent/workflows/plan.md +89 -0
  172. package/.agent/workflows/preview.md +81 -0
  173. package/.agent/workflows/simple-test.md +42 -0
  174. package/.agent/workflows/status.md +86 -0
  175. package/.agent/workflows/structured-orchestrate.md +180 -0
  176. package/.agent/workflows/test.md +144 -0
  177. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  178. package/.claude/settings.local.json +20 -8
  179. package/.env.example +56 -56
  180. package/CLAUDE.md +144 -108
  181. package/README.md +441 -441
  182. package/calc_tokens_weixin.js +81 -0
  183. package/cli/src/commands/chat.js +2 -1
  184. package/docs/CONTEXT_DESIGN.md +1596 -0
  185. package/examples/test-concurrent-chat.js +60 -60
  186. package/foliko-creative-3.png +0 -0
  187. package/foliko-creative-4.png +0 -0
  188. package/foliko-creative-5.png +0 -0
  189. package/package.json +2 -2
  190. package/plugins/default-plugins.js +2 -1
  191. package/plugins/extension-executor-plugin.js +91 -2
  192. package/plugins/file-system-plugin.js +2 -2
  193. package/plugins/memory-plugin.js +984 -0
  194. package/plugins/session-plugin.js +57 -1
  195. package/plugins/weixin-plugin.js +33 -23
  196. package/skills/find-skills/AGENTS.md +162 -162
  197. package/skills/find-skills/SKILL.md +133 -133
  198. package/skills/poster-guide/SKILL.md +1059 -0
  199. package/skills/python-plugin-dev/SKILL.md +238 -238
  200. package/skills/skill-guide/SKILL.md +130 -108
  201. package/src/capabilities/skill-manager.js +99 -0
  202. package/src/core/agent-chat.js +620 -141
  203. package/src/core/agent-context.js +188 -0
  204. package/src/core/agent.js +6 -2
  205. package/src/core/context-manager.js +283 -0
  206. package/src/core/framework.js +264 -3
  207. package/src/core/plugin-manager.js +79 -2
  208. package/src/core/request-context.js +98 -0
  209. package/src/core/session-context.js +341 -0
  210. package/src/core/session-storage.js +274 -0
  211. package/src/executors/mcp-executor.js +2 -2
  212. package/src/utils/index.js +239 -67
  213. package/src/utils/plugin-helpers.js +17 -0
  214. package/story-cover-book-v2.png +0 -0
  215. package/story-cover-japanese-1.png +0 -0
  216. package/story-cover-japanese-2.png +0 -0
  217. package/story-cover-japanese-3.png +0 -0
  218. package/story-cover-moran.png +0 -0
  219. package/undefined.png +0 -0
  220. package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
  221. package/.agent/agents/code-assistant.json +0 -14
  222. package/.agent/agents/email-assistant.json +0 -14
  223. package/.agent/agents/file-assistant.json +0 -15
  224. package/.agent/agents/system-assistant.json +0 -15
  225. package/.agent/agents/web-assistant.json +0 -12
  226. package/.agent/data/ambient/goals.json +0 -50
  227. package/.agent/data/ambient/memories.json +0 -7
  228. package/.agent/data/scheduler/tasks.json +0 -1
  229. package/.agent/package.json +0 -8
  230. package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
  231. package/.agent/plugins/daytona/README.md +0 -89
  232. package/.agent/plugins/daytona/index.js +0 -377
  233. package/.agent/plugins/daytona/package.json +0 -12
  234. package/.agent/plugins/marknative/README.md +0 -134
  235. package/.agent/plugins/marknative/index.js +0 -228
  236. package/.agent/plugins/marknative/package.json +0 -12
  237. package/.agent/plugins/marknative/update-readme.js +0 -134
  238. package/.agent/plugins/system-info/index.js +0 -387
  239. package/.agent/plugins/system-info/package.json +0 -4
  240. package/.agent/plugins/system-info/test.js +0 -40
  241. package/.agent/plugins/temp-repo/LICENSE +0 -201
  242. package/.agent/plugins/test_plugin.py +0 -304
  243. package/.agent/python-scripts/test_sample.py +0 -24
  244. package/.agent/skills/agent-browser/SKILL.md +0 -311
  245. package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
  246. package/.agent/skills/sysinfo/SKILL.md +0 -38
  247. package/.agent/skills/sysinfo/system-info.sh +0 -130
  248. package/.agent/skills/workflow/SKILL.md +0 -324
  249. package/.agent/workflows/email-digest.json +0 -50
  250. package/.agent/workflows/file-backup.json +0 -21
  251. package/.agent/workflows/get-ip-notify.json +0 -32
  252. package/.agent/workflows/news-aggregator.json +0 -93
  253. package/.agent/workflows/news-dashboard-v2.json +0 -94
  254. package/.agent/workflows/notification-batch.json +0 -32
  255. package/examples/test-chat-debug.js +0 -102
  256. package/examples/test-chat-result.js +0 -76
  257. package/examples/test-chat-stream-diff.js +0 -63
  258. /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/README.md +0 -0
  259. /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/package.json +0 -0
@@ -161,86 +161,104 @@ async function retry(fn, options = {}) {
161
161
  throw lastError;
162
162
  }
163
163
 
164
- function filterAndCleanMessages(messages) {
165
- // 先配对
166
- const pairedIds = new Set();
167
- const toolCallToAssistant = new Map(); // toolCallId -> assistant index
164
+ /**
165
+ * 安全序列化工具结果,移除循环引用
166
+ * 处理 Error 对象、函数等无法 JSON 序列化的内容
167
+ */
168
+ function sanitizeForJSON(obj) {
169
+ if (obj === null || obj === undefined) {
170
+ return null;
171
+ }
168
172
 
169
- // 收集所有 assistant tool-call
170
- for (let i = 0; i < messages.length; i++) {
171
- const msg = messages[i];
172
- if (msg.role === 'assistant' && msg.content) {
173
- const content = Array.isArray(msg.content) ? msg.content : [msg.content];
174
- for (const item of content) {
175
- if (item.type === 'tool-call' && item.toolCallId) {
176
- toolCallToAssistant.set(item.toolCallId, i);
177
- }
178
- }
179
- }
173
+ if (typeof obj === 'string') {
174
+ return obj;
180
175
  }
181
176
 
182
- // 找出配对的 tool result
183
- for (const msg of messages) {
184
- if (msg.role === 'tool' && msg.toolCallId) {
185
- if (toolCallToAssistant.has(msg.toolCallId)) {
186
- pairedIds.add(msg.toolCallId);
187
- }
188
- }
177
+ if (typeof obj === 'number' || typeof obj === 'boolean') {
178
+ return obj;
189
179
  }
190
180
 
191
- // 过滤并清理消息
192
- const cleaned = [];
193
- for (const msg of messages) {
194
- let shouldKeep = true;
195
- let cleanedMsg = { ...msg };
181
+ if (obj instanceof Error) {
182
+ return `Error: ${obj.message}`;
183
+ }
196
184
 
197
- if (msg.role === 'assistant' && msg.content) {
198
- let content = Array.isArray(msg.content) ? msg.content : [msg.content];
185
+ if (typeof obj === 'function' || typeof obj === 'symbol') {
186
+ return '[Unserializable]';
187
+ }
199
188
 
200
- // 过滤掉未配对的 tool-call
201
- const filteredContent = content.filter((item) => {
202
- if (item.type === 'tool-call') {
203
- return pairedIds.has(item.toolCallId);
204
- }
205
- return true; // 保留 text 类型
206
- });
189
+ if (Array.isArray(obj)) {
190
+ return obj.map((item) => sanitizeForJSON(item));
191
+ }
207
192
 
208
- // 检查过滤后是否还有有效内容
209
- if (filteredContent.length === 0) {
210
- shouldKeep = false; // 丢弃空消息
211
- } else {
212
- cleanedMsg.content = filteredContent;
193
+ if (typeof obj === 'object') {
194
+ // 检测并处理循环引用
195
+ const seen = new WeakSet();
196
+ const result = {};
197
+
198
+ for (const [key, value] of Object.entries(obj)) {
199
+ if (value === obj) continue; // 跳过自身引用
200
+ if (seen.has(value)) {
201
+ result[key] = '[Circular]';
202
+ continue;
203
+ }
204
+ if (typeof value === 'object' && value !== null) {
205
+ seen.add(value);
206
+ }
207
+ try {
208
+ result[key] = sanitizeForJSON(value);
209
+ } catch (e) {
210
+ result[key] = '[Unserializable]';
213
211
  }
214
212
  }
213
+ return result;
214
+ }
215
215
 
216
- if (msg.role === 'tool') {
217
- shouldKeep = pairedIds.has(msg.toolCallId);
218
- }
216
+ return String(obj);
217
+ }
219
218
 
220
- if (shouldKeep && cleanedMsg.content) {
221
- // 确保 content 不为空
222
- if (Array.isArray(cleanedMsg.content) && cleanedMsg.content.length > 0) {
223
- cleaned.push(cleanedMsg);
224
- } else if (typeof cleanedMsg.content === 'string' && cleanedMsg.content.trim()) {
225
- cleaned.push(cleanedMsg);
226
- } else if (
227
- cleanedMsg.content &&
228
- typeof cleanedMsg.content !== 'string' &&
229
- !Array.isArray(cleanedMsg.content)
230
- ) {
231
- // 处理其他类型的 content
232
- cleaned.push(cleanedMsg);
233
- }
234
- // 否则跳过空消息
235
- }
219
+ /**
220
+ * 清理工具结果内容,确保可安全序列化
221
+ */
222
+ function sanitizeToolResult(result) {
223
+ if (result === null || result === undefined) {
224
+ return null;
225
+ }
226
+
227
+ // 如果已经是字符串,直接返回
228
+ if (typeof result === 'string') {
229
+ return result.substring(0, 50000); // 限制长度
230
+ }
231
+
232
+ // 如果是纯数据对象,直接序列化
233
+ if (typeof result === 'number' || typeof result === 'boolean') {
234
+ return result;
236
235
  }
237
236
 
238
- return cleaned;
237
+ // 尝试安全序列化
238
+ try {
239
+ const sanitized = sanitizeForJSON(result);
240
+ const str = JSON.stringify(sanitized);
241
+ // 验证可以再次解析
242
+ JSON.parse(str);
243
+ return sanitized;
244
+ } catch (e) {
245
+ // 序列化失败,转换为字符串
246
+ return String(result).substring(0, 50000);
247
+ }
239
248
  }
240
249
 
241
250
  // 更激进的方法:确保所有消息都有有效的 content
242
- function validateAndFixMessages(messages) {
251
+ // 接收 pairedIds 参数用于过滤未配对的 tool 消息
252
+ function validateAndFixMessages(messages, pairedIds = null) {
243
253
  return messages.filter((msg) => {
254
+ // 如果提供了 pairedIds,检查 tool 消息是否配对
255
+ if (pairedIds && msg.role === 'tool' && msg.toolCallId) {
256
+ if (!pairedIds.has(msg.toolCallId)) {
257
+ console.log(`丢弃消息: role=tool, toolCallId=${msg.toolCallId} 未配对`);
258
+ return false;
259
+ }
260
+ }
261
+
244
262
  // 检查 content 是否存在且非空
245
263
  if (!msg.content) {
246
264
  console.log(`丢弃消息: role=${msg.role}, 无 content`);
@@ -286,11 +304,166 @@ function validateAndFixMessages(messages) {
286
304
 
287
305
  // 完整处理流程
288
306
  function prepareMessagesForAPI(rawMessages) {
289
- // 1. 先配对
290
- const paired = filterAndCleanMessages(rawMessages);
307
+ // 辅助函数:从消息中提取 toolCallId(兼容两种格式)
308
+ // 格式1: msg.toolCallId (旧格式)
309
+ // 格式2: msg.content[0].toolCallId (AI SDK CoreMessage 格式)
310
+ function extractToolCallId(msg) {
311
+ if (msg.toolCallId) return msg.toolCallId;
312
+ if (Array.isArray(msg.content) && msg.content.length > 0) {
313
+ const firstContent = msg.content[0];
314
+ if (firstContent && firstContent.toolCallId) return firstContent.toolCallId;
315
+ }
316
+ return null;
317
+ }
318
+
319
+ // 1. 先配对,收集配对的 toolCallId
320
+ const pairedIds = new Set();
321
+ const toolCallToAssistant = new Map();
322
+ const orphanedToolResults = []; // 用于调试:记录孤立的 tool results
323
+
324
+ // 收集所有 assistant 的 tool-call
325
+ for (let i = 0; i < rawMessages.length; i++) {
326
+ const msg = rawMessages[i];
327
+ if (msg.role === 'assistant' && msg.content) {
328
+ const content = Array.isArray(msg.content) ? msg.content : [msg.content];
329
+ for (const item of content) {
330
+ if (item.type === 'tool-call' && item.toolCallId) {
331
+ toolCallToAssistant.set(item.toolCallId, i);
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ // 找出配对的 tool result(兼容两种格式)
338
+ for (const msg of rawMessages) {
339
+ if (msg.role === 'tool') {
340
+ const toolCallId = extractToolCallId(msg);
341
+ if (toolCallId && toolCallToAssistant.has(toolCallId)) {
342
+ pairedIds.add(toolCallId);
343
+ } else if (toolCallId) {
344
+ // 记录孤立的 tool result(调试用)
345
+ orphanedToolResults.push({
346
+ toolCallId,
347
+ hasAssistantMessage: toolCallToAssistant.has(toolCallId),
348
+ });
349
+ }
350
+ }
351
+ }
352
+
353
+ // 调试:输出孤立 tool result 的信息(仅在有孤立结果时)
354
+ if (orphanedToolResults.length > 0 && pairedIds.size > 0) {
355
+ console.log(
356
+ `[prepareMessagesForAPI] Warning: ${orphanedToolResults.length} orphaned tool results detected:`
357
+ );
358
+ for (const orphan of orphanedToolResults) {
359
+ console.log(
360
+ ` - toolCallId=${orphan.toolCallId}, hasAssistantMessage=${orphan.hasAssistantMessage}`
361
+ );
362
+ }
363
+ console.log(` Paired IDs: ${Array.from(pairedIds).join(', ')}`);
364
+ console.log(` Assistant tool-call IDs: ${Array.from(toolCallToAssistant.keys()).join(', ')}`);
365
+ }
366
+
367
+ // 2. 过滤并清理空消息,同时过滤未配对的 tool 消息
368
+ const cleaned = [];
369
+ for (const msg of rawMessages) {
370
+ let shouldKeep = true;
371
+
372
+ if (msg.role === 'assistant' && msg.content) {
373
+ // 如果 content 是字符串(普通文本消息),保持不变
374
+ if (typeof msg.content === 'string') {
375
+ // 字符串内容不需要处理
376
+ } else if (Array.isArray(msg.content)) {
377
+ // content 是数组(包含 tool-call 等),进行过滤和清理
378
+ // 过滤:保留有 tool result 的 tool-call,保留 text 类型
379
+ const filteredContent = msg.content.filter((item) => {
380
+ if (item.type === 'tool-call') {
381
+ // 只保留有对应 tool result 的 tool call
382
+ return pairedIds.has(item.toolCallId);
383
+ }
384
+ return true; // 保留 text 类型
385
+ });
386
+
387
+ // 检查过滤后是否还有有效内容
388
+ if (filteredContent.length === 0) {
389
+ shouldKeep = false;
390
+ } else {
391
+ // 清理 tool-result 内容项(assistant 消息中不应该有 tool-result,但以防万一)
392
+ msg.content = filteredContent.map((item) => {
393
+ if (item && item.type === 'tool-result' && item.result !== undefined) {
394
+ return {
395
+ ...item,
396
+ result: sanitizeToolResult(item.result),
397
+ };
398
+ }
399
+ return item;
400
+ });
401
+ }
402
+ }
403
+ }
404
+
405
+ if (msg.role === 'tool') {
406
+ // 检查 tool message 是否有配对的 tool call
407
+ // 注意:一个 tool message 可能包含多个 tool-results,需要逐个检查
408
+ if (Array.isArray(msg.content)) {
409
+ // 过滤出有配对的 tool-results
410
+ const pairedResults = msg.content.filter((item) => {
411
+ if (item && item.type === 'tool-result' && item.toolCallId) {
412
+ return pairedIds.has(item.toolCallId);
413
+ }
414
+ // 保留非 tool-result 类型的内容(如 text)
415
+ return item && item.type !== 'tool-result';
416
+ });
417
+
418
+ // 检查是否有有效的 tool-results
419
+ const hasPairedResults = pairedResults.some(
420
+ (item) =>
421
+ item && item.type === 'tool-result' && item.toolCallId && pairedIds.has(item.toolCallId)
422
+ );
423
+
424
+ if (!hasPairedResults) {
425
+ // 所有 tool-results 都是orphaned,跳过整个消息
426
+ console.log(
427
+ `[prepareMessagesForAPI] Dropping tool message: all ${msg.content.length} tool-results are orphaned`
428
+ );
429
+ shouldKeep = false;
430
+ } else {
431
+ // 保留有配对的 tool-results,清理内容
432
+ msg.content = pairedResults.map((item) => {
433
+ if (item && item.type === 'tool-result' && item.result !== undefined) {
434
+ return {
435
+ ...item,
436
+ result: sanitizeToolResult(item.result),
437
+ };
438
+ }
439
+ return item;
440
+ });
441
+ }
442
+ } else {
443
+ // 非数组格式的 tool message(如旧格式)
444
+ const toolCallId = extractToolCallId(msg);
445
+ shouldKeep = toolCallId && pairedIds.has(toolCallId);
446
+ if (shouldKeep && msg.content) {
447
+ msg.content = sanitizeToolResult(msg.content);
448
+ }
449
+ }
450
+ }
291
451
 
292
- // 2. 验证并清理空消息
293
- const cleaned = validateAndFixMessages(paired);
452
+ // 验证 content 有效性
453
+ if (shouldKeep) {
454
+ if (!msg.content) {
455
+ shouldKeep = false;
456
+ } else if (Array.isArray(msg.content) && msg.content.length === 0) {
457
+ shouldKeep = false;
458
+ } else if (typeof msg.content === 'string' && !msg.content.trim()) {
459
+ shouldKeep = false;
460
+ }
461
+ }
462
+
463
+ if (shouldKeep) {
464
+ cleaned.push(msg);
465
+ }
466
+ }
294
467
 
295
468
  // 3. 确保消息交替顺序正确(user/assistant/tool)
296
469
  const finalMessages = [];
@@ -299,7 +472,6 @@ function prepareMessagesForAPI(rawMessages) {
299
472
  for (const msg of cleaned) {
300
473
  // 跳过连续的相同角色消息(除了 tool)
301
474
  if (msg.role === lastRole && msg.role !== 'tool') {
302
- // 静默跳过,不打印日志
303
475
  continue;
304
476
  }
305
477
 
@@ -65,10 +65,27 @@ function scanPluginNames(pluginsDir) {
65
65
  return [];
66
66
  }
67
67
 
68
+ // 忽略的目录/文件(无意义或系统文件)
69
+ const IGNORE_PATTERNS = new Set([
70
+ '__pycache__',
71
+ 'node_modules',
72
+ '.git',
73
+ '.svn',
74
+ '.hg',
75
+ '__MACOSX',
76
+ '.DS_Store',
77
+ 'Thumbs.db',
78
+ ]);
79
+
68
80
  const names = new Set();
69
81
  const entries = fs.readdirSync(pluginsDir, { withFileTypes: true });
70
82
 
71
83
  for (const entry of entries) {
84
+ // 跳过忽略列表中的条目
85
+ if (IGNORE_PATTERNS.has(entry.name)) {
86
+ continue;
87
+ }
88
+
72
89
  if (entry.isDirectory()) {
73
90
  // 文件夹插件
74
91
  names.add(entry.name);
Binary file
Binary file
Binary file
Binary file
Binary file
package/undefined.png ADDED
Binary file