myagent-ai 1.0.0

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 (486) hide show
  1. package/Dockerfile +30 -0
  2. package/README.md +333 -0
  3. package/agents/__init__.py +6 -0
  4. package/agents/__pycache__/main_agent.cpython-312.pyc +0 -0
  5. package/agents/base.py +115 -0
  6. package/agents/main_agent.py +695 -0
  7. package/agents/memory_agent.py +313 -0
  8. package/agents/tool_agent.py +248 -0
  9. package/chatbot/__init__.py +5 -0
  10. package/chatbot/base.py +124 -0
  11. package/chatbot/discord_bot.py +146 -0
  12. package/chatbot/feishu_bot.py +548 -0
  13. package/chatbot/manager.py +164 -0
  14. package/chatbot/qq_bot.py +189 -0
  15. package/chatbot/telegram_bot.py +167 -0
  16. package/chatbot/wechat_bot.py +558 -0
  17. package/communication/__init__.py +66 -0
  18. package/communication/channel.py +576 -0
  19. package/communication/crypto.py +347 -0
  20. package/communication/manager.py +397 -0
  21. package/communication/peer.py +156 -0
  22. package/config.py +464 -0
  23. package/core/__init__.py +10 -0
  24. package/core/config_broadcast.py +276 -0
  25. package/core/llm.py +878 -0
  26. package/core/logger.py +241 -0
  27. package/core/task_queue.py +362 -0
  28. package/core/utils.py +184 -0
  29. package/executor/__init__.py +4 -0
  30. package/executor/__pycache__/engine.cpython-312.pyc +0 -0
  31. package/executor/engine.py +1215 -0
  32. package/groups/__init__.py +15 -0
  33. package/groups/manager.py +724 -0
  34. package/knowledge/__init__.py +4 -0
  35. package/knowledge/rag.py +444 -0
  36. package/main.py +801 -0
  37. package/memory/__init__.py +4 -0
  38. package/memory/manager.py +840 -0
  39. package/organization/__init__.py +4 -0
  40. package/organization/manager.py +350 -0
  41. package/package.json +58 -0
  42. package/requirements.txt +59 -0
  43. package/setup.py +40 -0
  44. package/skills/ASR/LICENSE.txt +21 -0
  45. package/skills/ASR/SKILL.md +580 -0
  46. package/skills/ASR/scripts/asr.ts +27 -0
  47. package/skills/LLM/LICENSE.txt +21 -0
  48. package/skills/LLM/SKILL.md +856 -0
  49. package/skills/LLM/scripts/chat.ts +32 -0
  50. package/skills/TTS/LICENSE.txt +21 -0
  51. package/skills/TTS/SKILL.md +735 -0
  52. package/skills/TTS/tts.ts +25 -0
  53. package/skills/VLM/LICENSE.txt +21 -0
  54. package/skills/VLM/SKILL.md +588 -0
  55. package/skills/VLM/scripts/vlm.ts +57 -0
  56. package/skills/__init__.py +5 -0
  57. package/skills/agent-browser/SKILL.md +328 -0
  58. package/skills/ai-news-collectors/SKILL.md +157 -0
  59. package/skills/ai-news-collectors/_meta.json +6 -0
  60. package/skills/ai-news-collectors/references/sources.md +128 -0
  61. package/skills/aminer-open-academic/SKILL.md +312 -0
  62. package/skills/aminer-open-academic/_meta.json +6 -0
  63. package/skills/aminer-open-academic/evals/evals.json +46 -0
  64. package/skills/aminer-open-academic/references/api-catalog.md +1032 -0
  65. package/skills/aminer-open-academic/scripts/__pycache__/aminer_client.cpython-312.pyc +0 -0
  66. package/skills/aminer-open-academic/scripts/aminer_client.py +875 -0
  67. package/skills/auto-target-tracker/SKILL.md +317 -0
  68. package/skills/base.py +147 -0
  69. package/skills/blog-writer/2024-02-17-radical-transparency-sales.md +35 -0
  70. package/skills/blog-writer/2024-02-17-raycast-spotlight-superpowers.md +33 -0
  71. package/skills/blog-writer/2024-02-17-short-form-content-marketing.md +47 -0
  72. package/skills/blog-writer/2024-02-17-typing-speed-benefits.md +33 -0
  73. package/skills/blog-writer/2024-03-14-effective-ai-prompts.md +55 -0
  74. package/skills/blog-writer/2024-11-08-ai-revolutionizing-entry-level-sales.md +43 -0
  75. package/skills/blog-writer/2025-11-12-why-ai-art-is-useless.md +49 -0
  76. package/skills/blog-writer/README.md +2 -0
  77. package/skills/blog-writer/SKILL.md +158 -0
  78. package/skills/blog-writer/__pycache__/manage_examples.cpython-312.pyc +0 -0
  79. package/skills/blog-writer/_meta.json +6 -0
  80. package/skills/blog-writer/manage_examples.py +90 -0
  81. package/skills/blog-writer/style-guide.md +160 -0
  82. package/skills/browser_skill.py +146 -0
  83. package/skills/coding-agent/SKILL.md +120 -0
  84. package/skills/coding-agent/_meta.json +6 -0
  85. package/skills/coding-agent/criteria.md +48 -0
  86. package/skills/coding-agent/execution.md +42 -0
  87. package/skills/coding-agent/memory-template.md +38 -0
  88. package/skills/coding-agent/planning.md +31 -0
  89. package/skills/coding-agent/state.md +60 -0
  90. package/skills/coding-agent/verification.md +39 -0
  91. package/skills/content-strategy/SKILL.md +181 -0
  92. package/skills/content-strategy/_meta.json +6 -0
  93. package/skills/contentanalysis/ExtractWisdom/SKILL.md +229 -0
  94. package/skills/contentanalysis/ExtractWisdom/Workflows/Extract.md +60 -0
  95. package/skills/contentanalysis/SKILL.md +14 -0
  96. package/skills/docx/CHANGELOG.md +85 -0
  97. package/skills/docx/LICENSE.txt +30 -0
  98. package/skills/docx/SKILL.md +455 -0
  99. package/skills/docx/docx-js.md +681 -0
  100. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  101. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  102. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  103. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  104. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  105. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  106. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  107. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  108. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  109. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  110. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  111. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  112. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  113. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  114. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  115. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  116. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  117. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  118. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  119. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  120. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  121. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  122. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  123. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  124. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  125. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  126. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  127. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  128. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  129. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  130. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  131. package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  132. package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  133. package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  134. package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  135. package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  136. package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  137. package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  138. package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  139. package/skills/docx/ooxml/scripts/__pycache__/pack.cpython-312.pyc +0 -0
  140. package/skills/docx/ooxml/scripts/__pycache__/unpack.cpython-312.pyc +0 -0
  141. package/skills/docx/ooxml/scripts/__pycache__/validate.cpython-312.pyc +0 -0
  142. package/skills/docx/ooxml/scripts/pack.py +159 -0
  143. package/skills/docx/ooxml/scripts/unpack.py +29 -0
  144. package/skills/docx/ooxml/scripts/validate.py +69 -0
  145. package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  146. package/skills/docx/ooxml/scripts/validation/__pycache__/__init__.cpython-312.pyc +0 -0
  147. package/skills/docx/ooxml/scripts/validation/__pycache__/base.cpython-312.pyc +0 -0
  148. package/skills/docx/ooxml/scripts/validation/__pycache__/docx.cpython-312.pyc +0 -0
  149. package/skills/docx/ooxml/scripts/validation/__pycache__/pptx.cpython-312.pyc +0 -0
  150. package/skills/docx/ooxml/scripts/validation/__pycache__/redlining.cpython-312.pyc +0 -0
  151. package/skills/docx/ooxml/scripts/validation/base.py +951 -0
  152. package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  153. package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  154. package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  155. package/skills/docx/ooxml.md +615 -0
  156. package/skills/docx/scripts/__init__.py +1 -0
  157. package/skills/docx/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  158. package/skills/docx/scripts/__pycache__/add_toc_placeholders.cpython-312.pyc +0 -0
  159. package/skills/docx/scripts/__pycache__/document.cpython-312.pyc +0 -0
  160. package/skills/docx/scripts/__pycache__/utilities.cpython-312.pyc +0 -0
  161. package/skills/docx/scripts/add_toc_placeholders.py +220 -0
  162. package/skills/docx/scripts/document.py +1302 -0
  163. package/skills/docx/scripts/templates/comments.xml +3 -0
  164. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  165. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  166. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  167. package/skills/docx/scripts/templates/people.xml +3 -0
  168. package/skills/docx/scripts/utilities.py +374 -0
  169. package/skills/dream-interpreter/SKILL.md +88 -0
  170. package/skills/dream-interpreter/assets/example_asset.txt +24 -0
  171. package/skills/dream-interpreter/references/api_reference.md +34 -0
  172. package/skills/dream-interpreter/references/interpretation-guide.md +83 -0
  173. package/skills/dream-interpreter/references/output-schema.md +65 -0
  174. package/skills/dream-interpreter/references/questioning-strategy.md +62 -0
  175. package/skills/dream-interpreter/references/visual-mapping.md +81 -0
  176. package/skills/dream-interpreter/scripts/__pycache__/example.cpython-312.pyc +0 -0
  177. package/skills/dream-interpreter/scripts/example.py +19 -0
  178. package/skills/dream-interpreter/skill.json +7 -0
  179. package/skills/file_skill.py +246 -0
  180. package/skills/finance/Finance_API_Doc.md +445 -0
  181. package/skills/finance/SKILL.md +53 -0
  182. package/skills/fullstack-dev/SKILL.md +205 -0
  183. package/skills/get-fortune-analysis/SKILL.md +370 -0
  184. package/skills/get-fortune-analysis/lunar_python.py +91 -0
  185. package/skills/gift-evaluator/SKILL.md +83 -0
  186. package/skills/gift-evaluator/__pycache__/html_tools.cpython-312.pyc +0 -0
  187. package/skills/gift-evaluator/html_tools.py +268 -0
  188. package/skills/image-edit/LICENSE.txt +21 -0
  189. package/skills/image-edit/SKILL.md +896 -0
  190. package/skills/image-edit/scripts/image-edit.ts +36 -0
  191. package/skills/image-generation/LICENSE.txt +21 -0
  192. package/skills/image-generation/SKILL.md +583 -0
  193. package/skills/image-generation/scripts/image-generation.ts +28 -0
  194. package/skills/image-understand/LICENSE.txt +21 -0
  195. package/skills/image-understand/SKILL.md +855 -0
  196. package/skills/image-understand/scripts/image-understand.ts +41 -0
  197. package/skills/interview-designer/README.md +70 -0
  198. package/skills/interview-designer/SKILL.md +53 -0
  199. package/skills/interview-designer/_meta.json +6 -0
  200. package/skills/interview-designer/references/design_rationale.md +43 -0
  201. package/skills/interview-designer/templates/interview_guide_template.md +62 -0
  202. package/skills/market-research-reports/SKILL.md +901 -0
  203. package/skills/market-research-reports/assets/FORMATTING_GUIDE.md +428 -0
  204. package/skills/market-research-reports/assets/market_report_template.tex +1380 -0
  205. package/skills/market-research-reports/assets/market_research.sty +564 -0
  206. package/skills/market-research-reports/references/data_analysis_patterns.md +548 -0
  207. package/skills/market-research-reports/references/report_structure_guide.md +999 -0
  208. package/skills/market-research-reports/references/visual_generation_guide.md +1077 -0
  209. package/skills/market-research-reports/scripts/__pycache__/generate_market_visuals.cpython-312.pyc +0 -0
  210. package/skills/market-research-reports/scripts/generate_market_visuals.py +529 -0
  211. package/skills/marketing-mode/README.md +49 -0
  212. package/skills/marketing-mode/SKILL.md +693 -0
  213. package/skills/marketing-mode/_meta.json +6 -0
  214. package/skills/marketing-mode/mode-prompt.md +39 -0
  215. package/skills/marketing-mode/skill.json +51 -0
  216. package/skills/mindfulness-meditation/SKILL.md +65 -0
  217. package/skills/mindfulness-meditation/_meta.json +6 -0
  218. package/skills/multi-search-engine/CHANGELOG.md +15 -0
  219. package/skills/multi-search-engine/CHANNELLOG.md +48 -0
  220. package/skills/multi-search-engine/SKILL.md +78 -0
  221. package/skills/multi-search-engine/_meta.json +6 -0
  222. package/skills/multi-search-engine/config.json +14 -0
  223. package/skills/multi-search-engine/metadata.json +7 -0
  224. package/skills/multi-search-engine/references/international-search.md +651 -0
  225. package/skills/pdf/LICENSE.txt +30 -0
  226. package/skills/pdf/SKILL.md +1534 -0
  227. package/skills/pdf/forms.md +205 -0
  228. package/skills/pdf/reference.md +765 -0
  229. package/skills/pdf/scripts/__pycache__/add_zai_metadata.cpython-312.pyc +0 -0
  230. package/skills/pdf/scripts/__pycache__/check_bounding_boxes.cpython-312.pyc +0 -0
  231. package/skills/pdf/scripts/__pycache__/check_bounding_boxes_test.cpython-312.pyc +0 -0
  232. package/skills/pdf/scripts/__pycache__/check_fillable_fields.cpython-312.pyc +0 -0
  233. package/skills/pdf/scripts/__pycache__/convert_pdf_to_images.cpython-312.pyc +0 -0
  234. package/skills/pdf/scripts/__pycache__/create_validation_image.cpython-312.pyc +0 -0
  235. package/skills/pdf/scripts/__pycache__/extract_form_field_info.cpython-312.pyc +0 -0
  236. package/skills/pdf/scripts/__pycache__/fill_fillable_fields.cpython-312.pyc +0 -0
  237. package/skills/pdf/scripts/__pycache__/fill_pdf_form_with_annotations.cpython-312.pyc +0 -0
  238. package/skills/pdf/scripts/__pycache__/sanitize_code.cpython-312.pyc +0 -0
  239. package/skills/pdf/scripts/add_zai_metadata.py +172 -0
  240. package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  241. package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  242. package/skills/pdf/scripts/check_fillable_fields.py +12 -0
  243. package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  244. package/skills/pdf/scripts/create_validation_image.py +41 -0
  245. package/skills/pdf/scripts/extract_form_field_info.py +152 -0
  246. package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  247. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  248. package/skills/pdf/scripts/sanitize_code.py +110 -0
  249. package/skills/podcast-generate/LICENSE.txt +21 -0
  250. package/skills/podcast-generate/SKILL.md +198 -0
  251. package/skills/podcast-generate/generate.ts +661 -0
  252. package/skills/podcast-generate/package.json +30 -0
  253. package/skills/podcast-generate/readme.md +177 -0
  254. package/skills/podcast-generate/test_data/segments.jsonl +3 -0
  255. package/skills/podcast-generate/tsconfig.json +26 -0
  256. package/skills/pptx/LICENSE.txt +30 -0
  257. package/skills/pptx/SKILL.md +507 -0
  258. package/skills/pptx/html2pptx.md +625 -0
  259. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  260. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  261. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  262. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  263. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  264. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  265. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  266. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  267. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  268. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  269. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  270. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  271. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  272. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  273. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  274. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  275. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  276. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  277. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  278. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  279. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  280. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  281. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  282. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  283. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  284. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  285. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  286. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  287. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  288. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  289. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  290. package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  291. package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  292. package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  293. package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  294. package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  295. package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  296. package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  297. package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  298. package/skills/pptx/ooxml/scripts/__pycache__/pack.cpython-312.pyc +0 -0
  299. package/skills/pptx/ooxml/scripts/__pycache__/unpack.cpython-312.pyc +0 -0
  300. package/skills/pptx/ooxml/scripts/__pycache__/validate.cpython-312.pyc +0 -0
  301. package/skills/pptx/ooxml/scripts/pack.py +159 -0
  302. package/skills/pptx/ooxml/scripts/unpack.py +29 -0
  303. package/skills/pptx/ooxml/scripts/validate.py +69 -0
  304. package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  305. package/skills/pptx/ooxml/scripts/validation/__pycache__/__init__.cpython-312.pyc +0 -0
  306. package/skills/pptx/ooxml/scripts/validation/__pycache__/base.cpython-312.pyc +0 -0
  307. package/skills/pptx/ooxml/scripts/validation/__pycache__/docx.cpython-312.pyc +0 -0
  308. package/skills/pptx/ooxml/scripts/validation/__pycache__/pptx.cpython-312.pyc +0 -0
  309. package/skills/pptx/ooxml/scripts/validation/__pycache__/redlining.cpython-312.pyc +0 -0
  310. package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  311. package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  312. package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  313. package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  314. package/skills/pptx/ooxml.md +427 -0
  315. package/skills/pptx/scripts/__pycache__/inventory.cpython-312.pyc +0 -0
  316. package/skills/pptx/scripts/__pycache__/inventory.cpython-313.pyc +0 -0
  317. package/skills/pptx/scripts/__pycache__/rearrange.cpython-312.pyc +0 -0
  318. package/skills/pptx/scripts/__pycache__/replace.cpython-312.pyc +0 -0
  319. package/skills/pptx/scripts/__pycache__/thumbnail.cpython-312.pyc +0 -0
  320. package/skills/pptx/scripts/html2pptx.js +1044 -0
  321. package/skills/pptx/scripts/inventory.py +1020 -0
  322. package/skills/pptx/scripts/rearrange.py +231 -0
  323. package/skills/pptx/scripts/replace.py +385 -0
  324. package/skills/pptx/scripts/thumbnail.py +450 -0
  325. package/skills/qingyan-research/SKILL.md +294 -0
  326. package/skills/qingyan-research/__pycache__/generate_html.cpython-312.pyc +0 -0
  327. package/skills/qingyan-research/generate_html.py +33 -0
  328. package/skills/registry.py +344 -0
  329. package/skills/search_skill.py +228 -0
  330. package/skills/seo-content-writer/SKILL.md +661 -0
  331. package/skills/seo-content-writer/_meta.json +6 -0
  332. package/skills/seo-content-writer/references/content-structure-templates.md +875 -0
  333. package/skills/seo-content-writer/references/title-formulas.md +339 -0
  334. package/skills/skill-creator/LICENSE.txt +202 -0
  335. package/skills/skill-creator/SKILL.md +485 -0
  336. package/skills/skill-creator/agents/analyzer.md +274 -0
  337. package/skills/skill-creator/agents/comparator.md +202 -0
  338. package/skills/skill-creator/agents/grader.md +223 -0
  339. package/skills/skill-creator/assets/eval_review.html +146 -0
  340. package/skills/skill-creator/eval-viewer/__pycache__/generate_review.cpython-312.pyc +0 -0
  341. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  342. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  343. package/skills/skill-creator/references/schemas.md +430 -0
  344. package/skills/skill-creator/scripts/__init__.py +0 -0
  345. package/skills/skill-creator/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  346. package/skills/skill-creator/scripts/__pycache__/aggregate_benchmark.cpython-312.pyc +0 -0
  347. package/skills/skill-creator/scripts/__pycache__/generate_report.cpython-312.pyc +0 -0
  348. package/skills/skill-creator/scripts/__pycache__/improve_description.cpython-312.pyc +0 -0
  349. package/skills/skill-creator/scripts/__pycache__/package_skill.cpython-312.pyc +0 -0
  350. package/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
  351. package/skills/skill-creator/scripts/__pycache__/run_eval.cpython-312.pyc +0 -0
  352. package/skills/skill-creator/scripts/__pycache__/run_loop.cpython-312.pyc +0 -0
  353. package/skills/skill-creator/scripts/__pycache__/utils.cpython-312.pyc +0 -0
  354. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  355. package/skills/skill-creator/scripts/generate_report.py +326 -0
  356. package/skills/skill-creator/scripts/improve_description.py +236 -0
  357. package/skills/skill-creator/scripts/package_skill.py +136 -0
  358. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  359. package/skills/skill-creator/scripts/run_eval.py +310 -0
  360. package/skills/skill-creator/scripts/run_loop.py +328 -0
  361. package/skills/skill-creator/scripts/utils.py +47 -0
  362. package/skills/skill-finder-cn/SKILL.md +66 -0
  363. package/skills/skill-finder-cn/_meta.json +6 -0
  364. package/skills/skill-finder-cn/package.json +5 -0
  365. package/skills/skill-finder-cn/scripts/search.sh +15 -0
  366. package/skills/skill-vetter/SKILL.md +137 -0
  367. package/skills/stock-analysis-skill/SKILL.md +156 -0
  368. package/skills/stock-analysis-skill/package.json +21 -0
  369. package/skills/stock-analysis-skill/src/analyzer.ts +264 -0
  370. package/skills/stock-analysis-skill/src/dataFetcher.ts +130 -0
  371. package/skills/stock-analysis-skill/src/dividend.ts +226 -0
  372. package/skills/stock-analysis-skill/src/index.ts +327 -0
  373. package/skills/stock-analysis-skill/src/rumorScanner.ts +200 -0
  374. package/skills/stock-analysis-skill/src/types.ts +167 -0
  375. package/skills/stock-analysis-skill/src/watchlist.ts +292 -0
  376. package/skills/stock-analysis-skill/tsconfig.json +15 -0
  377. package/skills/storyboard-manager/SKILL.md +532 -0
  378. package/skills/storyboard-manager/index.js +9 -0
  379. package/skills/storyboard-manager/package.json +11 -0
  380. package/skills/storyboard-manager/references/character_development.md +232 -0
  381. package/skills/storyboard-manager/references/story_structures.md +148 -0
  382. package/skills/storyboard-manager/scripts/__pycache__/consistency_checker.cpython-312.pyc +0 -0
  383. package/skills/storyboard-manager/scripts/__pycache__/timeline_tracker.cpython-312.pyc +0 -0
  384. package/skills/storyboard-manager/scripts/consistency_checker.py +391 -0
  385. package/skills/storyboard-manager/scripts/timeline_tracker.py +352 -0
  386. package/skills/system_skill.py +249 -0
  387. package/skills/ui-ux-pro-max/SKILL.md +43 -0
  388. package/skills/ui-ux-pro-max/_meta.json +6 -0
  389. package/skills/ui-ux-pro-max/assets/data/charts.csv +26 -0
  390. package/skills/ui-ux-pro-max/assets/data/colors.csv +97 -0
  391. package/skills/ui-ux-pro-max/assets/data/icons.csv +101 -0
  392. package/skills/ui-ux-pro-max/assets/data/landing.csv +31 -0
  393. package/skills/ui-ux-pro-max/assets/data/products.csv +97 -0
  394. package/skills/ui-ux-pro-max/assets/data/react-performance.csv +45 -0
  395. package/skills/ui-ux-pro-max/assets/data/stacks/astro.csv +54 -0
  396. package/skills/ui-ux-pro-max/assets/data/stacks/flutter.csv +53 -0
  397. package/skills/ui-ux-pro-max/assets/data/stacks/html-tailwind.csv +56 -0
  398. package/skills/ui-ux-pro-max/assets/data/stacks/jetpack-compose.csv +53 -0
  399. package/skills/ui-ux-pro-max/assets/data/stacks/nextjs.csv +53 -0
  400. package/skills/ui-ux-pro-max/assets/data/stacks/nuxt-ui.csv +51 -0
  401. package/skills/ui-ux-pro-max/assets/data/stacks/nuxtjs.csv +59 -0
  402. package/skills/ui-ux-pro-max/assets/data/stacks/react-native.csv +52 -0
  403. package/skills/ui-ux-pro-max/assets/data/stacks/react.csv +54 -0
  404. package/skills/ui-ux-pro-max/assets/data/stacks/shadcn.csv +61 -0
  405. package/skills/ui-ux-pro-max/assets/data/stacks/svelte.csv +54 -0
  406. package/skills/ui-ux-pro-max/assets/data/stacks/swiftui.csv +51 -0
  407. package/skills/ui-ux-pro-max/assets/data/stacks/vue.csv +50 -0
  408. package/skills/ui-ux-pro-max/assets/data/styles.csv +68 -0
  409. package/skills/ui-ux-pro-max/assets/data/typography.csv +58 -0
  410. package/skills/ui-ux-pro-max/assets/data/ui-reasoning.csv +101 -0
  411. package/skills/ui-ux-pro-max/assets/data/ux-guidelines.csv +100 -0
  412. package/skills/ui-ux-pro-max/assets/data/web-interface.csv +31 -0
  413. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  414. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  415. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  416. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  417. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  418. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  419. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  420. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  421. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  422. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  423. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  424. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  425. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  426. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  427. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  428. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  429. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  430. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  431. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  432. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  433. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  434. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  435. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  436. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  437. package/skills/ui-ux-pro-max/references/upstream-README.md +488 -0
  438. package/skills/ui-ux-pro-max/references/upstream-skill-content.md +288 -0
  439. package/skills/ui-ux-pro-max/scripts/__init__.py +0 -0
  440. package/skills/ui-ux-pro-max/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  441. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
  442. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
  443. package/skills/ui-ux-pro-max/scripts/__pycache__/search.cpython-312.pyc +0 -0
  444. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  445. package/skills/ui-ux-pro-max/scripts/design_system.py +1071 -0
  446. package/skills/ui-ux-pro-max/scripts/search.py +111 -0
  447. package/skills/video-generation/LICENSE.txt +21 -0
  448. package/skills/video-generation/SKILL.md +1082 -0
  449. package/skills/video-generation/scripts/video.ts +168 -0
  450. package/skills/video-understand/LICENSE.txt +21 -0
  451. package/skills/video-understand/SKILL.md +916 -0
  452. package/skills/video-understand/scripts/video-understand.ts +41 -0
  453. package/skills/visual-design-foundations/SKILL.md +318 -0
  454. package/skills/visual-design-foundations/references/color-systems.md +417 -0
  455. package/skills/visual-design-foundations/references/spacing-iconography.md +425 -0
  456. package/skills/visual-design-foundations/references/typography-systems.md +432 -0
  457. package/skills/web-reader/LICENSE.txt +21 -0
  458. package/skills/web-reader/SKILL.md +1140 -0
  459. package/skills/web-reader/scripts/web-reader.ts +37 -0
  460. package/skills/web-search/LICENSE.txt +21 -0
  461. package/skills/web-search/SKILL.md +912 -0
  462. package/skills/web-search/scripts/web_search.ts +44 -0
  463. package/skills/web-shader-extractor/SKILL.md +145 -0
  464. package/skills/web-shader-extractor/references/config-extraction.md +50 -0
  465. package/skills/web-shader-extractor/references/encoded-definitions.md +53 -0
  466. package/skills/web-shader-extractor/references/extraction-workflow.md +61 -0
  467. package/skills/web-shader-extractor/references/porting-strategy.md +164 -0
  468. package/skills/web-shader-extractor/references/shader-injection.md +126 -0
  469. package/skills/web-shader-extractor/references/shaders-com.md +190 -0
  470. package/skills/web-shader-extractor/references/tech-signatures.md +54 -0
  471. package/skills/web-shader-extractor/references/tsl-extraction.md +41 -0
  472. package/skills/web-shader-extractor/references/unicorn-studio.md +353 -0
  473. package/skills/web-shader-extractor/scripts/fetch-rendered-dom.mjs +153 -0
  474. package/skills/web-shader-extractor/scripts/scan-bundle.sh +76 -0
  475. package/skills/writing-plans/SKILL.md +116 -0
  476. package/skills/writing-plans/_meta.json +6 -0
  477. package/skills/xlsx/LICENSE.txt +30 -0
  478. package/skills/xlsx/SKILL.md +496 -0
  479. package/skills/xlsx/__pycache__/recalc.cpython-312.pyc +0 -0
  480. package/skills/xlsx/recalc.py +178 -0
  481. package/start.sh +36 -0
  482. package/web/__init__.py +1 -0
  483. package/web/__pycache__/api_server.cpython-312.pyc +0 -0
  484. package/web/api_server.py +2043 -0
  485. package/web/ui/chat.html +3235 -0
  486. package/web/ui/index.html +458 -0
package/core/llm.py ADDED
@@ -0,0 +1,878 @@
1
+ """
2
+ core/llm.py - LLM 客户端模块
3
+ =============================
4
+ 统一封装多种 LLM 提供商的调用接口。
5
+ 支持: OpenAI, Anthropic (Claude), Ollama (本地), Zhipu GLM, 自定义兼容接口
6
+
7
+ 增强功能:
8
+ - JSON 严格解析(4 策略)
9
+ - 流式输出 (Streaming)
10
+ - Token 用量追踪 & 费用统计
11
+ - 全局重试 + 指数退避
12
+ - asyncio 现代化 (get_running_loop)
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import time
18
+ import asyncio
19
+ from typing import (
20
+ Optional, Dict, Any, List, Generator, AsyncGenerator,
21
+ )
22
+ from dataclasses import dataclass, field
23
+
24
+ from core.logger import get_logger
25
+ from core.utils import safe_json_parse
26
+
27
+ logger = get_logger("myagent.llm")
28
+
29
+
30
+ # ==============================================================================
31
+ # 消息类型定义
32
+ # ==============================================================================
33
+
34
+ @dataclass
35
+ class Message:
36
+ """聊天消息"""
37
+ role: str # system | user | assistant | tool
38
+ content: str = ""
39
+ name: str = "" # 消息发送者标识
40
+ tool_call_id: str = "" # 工具调用ID
41
+ tool_calls: List[Dict] = field(default_factory=list)
42
+ metadata: Dict[str, Any] = field(default_factory=dict)
43
+
44
+ def to_dict(self) -> dict:
45
+ result = {"role": self.role, "content": self.content}
46
+ if self.name:
47
+ result["name"] = self.name
48
+ if self.tool_call_id:
49
+ result["tool_call_id"] = self.tool_call_id
50
+ if self.tool_calls:
51
+ result["tool_calls"] = self.tool_calls
52
+ return result
53
+
54
+ @classmethod
55
+ def from_dict(cls, data: dict) -> "Message":
56
+ return cls(
57
+ role=data.get("role", "user"),
58
+ content=data.get("content", ""),
59
+ name=data.get("name", ""),
60
+ tool_call_id=data.get("tool_call_id", ""),
61
+ tool_calls=data.get("tool_calls", []),
62
+ )
63
+
64
+
65
+ @dataclass
66
+ class LLMResponse:
67
+ """LLM 响应"""
68
+ content: str = ""
69
+ tool_calls: List[Dict] = field(default_factory=list)
70
+ usage: Dict[str, int] = field(default_factory=dict)
71
+ model: str = ""
72
+ finish_reason: str = ""
73
+ raw_response: Any = None
74
+ success: bool = True
75
+ error: str = ""
76
+
77
+
78
+ # ==============================================================================
79
+ # LLM 客户端
80
+ # ==============================================================================
81
+
82
+ class LLMClient:
83
+ """
84
+ 统一 LLM 客户端,支持多种提供商。
85
+
86
+ 支持提供商: openai, anthropic, ollama, zhipu, custom
87
+
88
+ 使用示例:
89
+ client = LLMClient(provider="openai", api_key="sk-...", model="gpt-4")
90
+ response = await client.chat([Message(role="user", content="你好")])
91
+ """
92
+
93
+ def __init__(
94
+ self,
95
+ provider: str = "openai",
96
+ api_key: str = "",
97
+ base_url: str = "",
98
+ model: str = "gpt-4",
99
+ temperature: float = 0.1,
100
+ max_tokens: int = 4096,
101
+ timeout: int = 120,
102
+ max_retries: int = 3,
103
+ **kwargs,
104
+ ):
105
+ self.provider = provider
106
+ self.api_key = api_key
107
+ self.base_url = base_url
108
+ self.model = model
109
+ self.temperature = temperature
110
+ self.max_tokens = max_tokens
111
+ self.timeout = timeout
112
+ self.max_retries = max_retries
113
+ self.extra = kwargs
114
+ self._client = None
115
+
116
+ # ---- Token 用量追踪 ----
117
+ self._total_prompt_tokens: int = 0
118
+ self._total_completion_tokens: int = 0
119
+ self._total_tokens_used: int = 0
120
+ self._total_cost: float = 0.0
121
+ self._call_count: int = 0
122
+
123
+ # ------------------------------------------------------------------
124
+ # Token 用量 & 费用追踪
125
+ # ------------------------------------------------------------------
126
+
127
+ def _record_usage(self, usage: Dict[str, int], model: str = ""):
128
+ """记录一次调用的 token 用量并估算费用。"""
129
+ prompt = usage.get("prompt_tokens", 0) or usage.get("input_tokens", 0)
130
+ completion = usage.get("completion_tokens", 0) or usage.get("output_tokens", 0)
131
+ total = prompt + completion
132
+
133
+ self._total_prompt_tokens += prompt
134
+ self._total_completion_tokens += completion
135
+ self._total_tokens_used += total
136
+ self._call_count += 1
137
+
138
+ # 简单费用估算 (每百万 token, 粗略均价)
139
+ cost = self._estimate_cost(prompt, completion, model or self.model)
140
+ self._total_cost += cost
141
+
142
+ @staticmethod
143
+ def _estimate_cost(prompt_tokens: int, completion_tokens: int, model: str) -> float:
144
+ """
145
+ 按模型粗略估算 API 费用 (USD)。
146
+ 价格基于 2024 年公开信息,仅做参考。
147
+ """
148
+ # (input price per 1M tokens, output price per 1M tokens)
149
+ pricing: Dict[str, tuple] = {
150
+ "gpt-4": (30.0, 60.0),
151
+ "gpt-4-turbo": (10.0, 30.0),
152
+ "gpt-4o": (2.5, 10.0),
153
+ "gpt-4o-mini": (0.15, 0.6),
154
+ "gpt-3.5-turbo": (0.5, 1.5),
155
+ "claude-3-opus": (15.0, 75.0),
156
+ "claude-3-sonnet": (3.0, 15.0),
157
+ "claude-3-haiku": (0.25, 1.25),
158
+ "claude-3.5-sonnet": (3.0, 15.0),
159
+ "glm-4": (14.0, 14.0),
160
+ "glm-4-flash": (0.1, 0.1),
161
+ "glm-4-plus": (10.0, 10.0),
162
+ }
163
+ # 找到最匹配的模型价格
164
+ input_price, output_price = 2.0, 8.0 # 默认
165
+ for model_key, (ip, op) in pricing.items():
166
+ if model_key in model:
167
+ input_price, output_price = ip, op
168
+ break
169
+ return (prompt_tokens / 1_000_000) * input_price + (completion_tokens / 1_000_000) * output_price
170
+
171
+ def get_usage_stats(self) -> Dict[str, Any]:
172
+ """获取用量统计。"""
173
+ return {
174
+ "total_prompt_tokens": self._total_prompt_tokens,
175
+ "total_completion_tokens": self._total_completion_tokens,
176
+ "total_tokens_used": self._total_tokens_used,
177
+ "total_cost_usd": round(self._total_cost, 6),
178
+ "call_count": self._call_count,
179
+ "model": self.model,
180
+ "provider": self.provider,
181
+ }
182
+
183
+ def reset_usage(self):
184
+ """重置用量统计。"""
185
+ self._total_prompt_tokens = 0
186
+ self._total_completion_tokens = 0
187
+ self._total_tokens_used = 0
188
+ self._total_cost = 0.0
189
+ self._call_count = 0
190
+ logger.info("用量统计已重置")
191
+
192
+ # ------------------------------------------------------------------
193
+ # 客户端初始化
194
+ # ------------------------------------------------------------------
195
+
196
+ def _ensure_client(self):
197
+ """延迟初始化 LLM 客户端"""
198
+ if self._client is not None:
199
+ return
200
+
201
+ if self.provider in ("openai", "custom"):
202
+ self._init_openai()
203
+ elif self.provider == "anthropic":
204
+ self._init_anthropic()
205
+ elif self.provider == "ollama":
206
+ self._init_ollama()
207
+ elif self.provider == "zhipu":
208
+ self._init_zhipu()
209
+ else:
210
+ raise ValueError(f"不支持的 LLM 提供商: {self.provider}")
211
+
212
+ def _init_openai(self):
213
+ """初始化 OpenAI / 兼容客户端"""
214
+ try:
215
+ from openai import OpenAI
216
+ kwargs = {}
217
+ if self.api_key:
218
+ kwargs["api_key"] = self.api_key
219
+ if self.base_url:
220
+ kwargs["base_url"] = self.base_url
221
+ self._client = OpenAI(**kwargs)
222
+ logger.info(f"OpenAI 客户端已初始化 (model={self.model})")
223
+ except ImportError:
224
+ raise ImportError("请安装 openai: pip install openai")
225
+
226
+ def _init_anthropic(self):
227
+ """初始化 Anthropic 客户端"""
228
+ try:
229
+ import anthropic
230
+ key = self.extra.get("anthropic_api_key") or self.api_key
231
+ if not key:
232
+ raise ValueError("Anthropic API Key 未设置")
233
+ self._client = anthropic.Anthropic(api_key=key)
234
+ self.model = self.model or "claude-3-sonnet-20240229"
235
+ logger.info(f"Anthropic 客户端已初始化 (model={self.model})")
236
+ except ImportError:
237
+ raise ImportError("请安装 anthropic: pip install anthropic")
238
+
239
+ def _init_ollama(self):
240
+ """初始化 Ollama 客户端"""
241
+ try:
242
+ import requests
243
+ self._client = "ollama"
244
+ if not self.base_url:
245
+ self.base_url = "http://localhost:11434"
246
+ logger.info(f"Ollama 客户端已初始化 (model={self.model}, url={self.base_url})")
247
+ except ImportError:
248
+ raise ImportError("请安装 requests: pip install requests")
249
+
250
+ def _init_zhipu(self):
251
+ """初始化 Zhipu (智谱) GLM 客户端
252
+
253
+ 使用 OpenAI 兼容接口:
254
+ - API base: https://open.bigmodel.cn/api/paas/v4/
255
+ - 环境变量: ZHIPUAI_API_KEY
256
+ """
257
+ try:
258
+ from openai import OpenAI
259
+ import os
260
+
261
+ api_key = self.api_key or os.environ.get("ZHIPUAI_API_KEY", "")
262
+ if not api_key:
263
+ raise ValueError(
264
+ "Zhipu API Key 未设置,请传入 api_key 或设置 ZHIPUAI_API_KEY 环境变量"
265
+ )
266
+
267
+ base_url = self.base_url or "https://open.bigmodel.cn/api/paas/v4/"
268
+ self.base_url = base_url
269
+
270
+ self._client = OpenAI(
271
+ api_key=api_key,
272
+ base_url=base_url,
273
+ )
274
+ if not self.model or self.model == "gpt-4":
275
+ self.model = "glm-4-flash"
276
+ logger.info(f"Zhipu GLM 客户端已初始化 (model={self.model}, url={base_url})")
277
+ except ImportError:
278
+ raise ImportError("请安装 openai: pip install openai")
279
+
280
+ # ------------------------------------------------------------------
281
+ # 核心 Chat 方法 (含重试)
282
+ # ------------------------------------------------------------------
283
+
284
+ async def _run_with_retry(self, func, *args, **kwargs):
285
+ """
286
+ 带指数退避的通用重试包装器。
287
+
288
+ 重试策略:
289
+ - 最多 self.max_retries 次 (默认 3)
290
+ - 退避延迟: 1s, 2s, 4s, ...
291
+ - 重试条件: 连接错误 / 速率限制 / 服务器错误
292
+ """
293
+ last_error = None
294
+ for attempt in range(self.max_retries):
295
+ try:
296
+ return await func(*args, **kwargs)
297
+ except Exception as e:
298
+ last_error = e
299
+ error_lower = str(e).lower()
300
+ # 判断是否值得重试
301
+ is_retryable = any(keyword in error_lower for keyword in (
302
+ "connection",
303
+ "timeout",
304
+ "rate_limit",
305
+ "rate limit",
306
+ "429",
307
+ "500",
308
+ "502",
309
+ "503",
310
+ "504",
311
+ "overloaded",
312
+ "capacity",
313
+ ))
314
+ if not is_retryable or attempt >= self.max_retries - 1:
315
+ raise
316
+ delay = 1.0 * (2 ** attempt) # 1s, 2s, 4s ...
317
+ logger.warning(
318
+ f"LLM 调用第 {attempt + 1}/{self.max_retries} 次重试 "
319
+ f"(延迟 {delay:.1f}s): {e}"
320
+ )
321
+ await asyncio.sleep(delay)
322
+ raise last_error # type: ignore
323
+
324
+ async def chat(
325
+ self,
326
+ messages: List[Message],
327
+ tools: Optional[List[Dict]] = None,
328
+ tool_choice: str = "auto",
329
+ response_format: Optional[Dict] = None,
330
+ **kwargs,
331
+ ) -> LLMResponse:
332
+ """
333
+ 发送聊天请求。
334
+
335
+ Args:
336
+ messages: 消息列表
337
+ tools: 可用工具列表 (OpenAI function calling 格式)
338
+ tool_choice: 工具选择策略
339
+ response_format: 响应格式 (如 {"type": "json_object"})
340
+ **kwargs: 额外参数
341
+
342
+ Returns:
343
+ LLMResponse 对象
344
+ """
345
+ self._ensure_client()
346
+
347
+ msg_dicts = [m.to_dict() for m in messages]
348
+ request_kwargs = {
349
+ "model": self.model,
350
+ "messages": msg_dicts,
351
+ "temperature": self.temperature,
352
+ "max_tokens": self.max_tokens,
353
+ }
354
+ if tools:
355
+ request_kwargs["tools"] = tools
356
+ request_kwargs["tool_choice"] = tool_choice
357
+ if response_format:
358
+ request_kwargs["response_format"] = response_format
359
+ request_kwargs.update(kwargs)
360
+
361
+ try:
362
+ if self.provider in ("openai", "custom", "zhipu"):
363
+ response = await self._run_with_retry(self._chat_openai, request_kwargs)
364
+ elif self.provider == "anthropic":
365
+ response = await self._run_with_retry(
366
+ self._chat_anthropic, messages, request_kwargs
367
+ )
368
+ elif self.provider == "ollama":
369
+ response = await self._run_with_retry(self._chat_ollama, request_kwargs)
370
+ else:
371
+ return LLMResponse(success=False, error="未知提供商")
372
+
373
+ # 记录用量
374
+ if response.usage:
375
+ self._record_usage(response.usage, response.model)
376
+
377
+ return response
378
+
379
+ except Exception as e:
380
+ logger.error(f"LLM 调用失败: {e}")
381
+ return LLMResponse(success=False, error=str(e))
382
+
383
+ # ------------------------------------------------------------------
384
+ # 提供商专属调用方法
385
+ # ------------------------------------------------------------------
386
+
387
+ async def _chat_openai(self, kwargs: dict) -> LLMResponse:
388
+ """OpenAI / 兼容接口调用 (含 Zhipu)"""
389
+ loop = asyncio.get_running_loop()
390
+ response = await loop.run_in_executor(
391
+ None, lambda: self._client.chat.completions.create(**kwargs)
392
+ )
393
+
394
+ choice = response.choices[0]
395
+ usage = {}
396
+ if response.usage:
397
+ usage = {
398
+ "prompt_tokens": response.usage.prompt_tokens,
399
+ "completion_tokens": response.usage.completion_tokens,
400
+ "total_tokens": response.usage.total_tokens,
401
+ }
402
+
403
+ tool_calls = []
404
+ if choice.message.tool_calls:
405
+ for tc in choice.message.tool_calls:
406
+ try:
407
+ args = json.loads(tc.function.arguments)
408
+ except json.JSONDecodeError:
409
+ args = {}
410
+ tool_calls.append({
411
+ "id": tc.id,
412
+ "name": tc.function.name,
413
+ "arguments": args,
414
+ })
415
+
416
+ return LLMResponse(
417
+ content=choice.message.content or "",
418
+ tool_calls=tool_calls,
419
+ usage=usage,
420
+ model=response.model,
421
+ finish_reason=choice.finish_reason or "",
422
+ raw_response=response,
423
+ )
424
+
425
+ async def _chat_anthropic(self, messages: List[Message], kwargs: dict) -> LLMResponse:
426
+ """Anthropic Claude 接口调用"""
427
+ loop = asyncio.get_running_loop()
428
+
429
+ # 转换消息格式
430
+ system_msg = ""
431
+ anth_messages = []
432
+ for m in messages:
433
+ if m.role == "system":
434
+ system_msg = m.content
435
+ continue
436
+ anth_messages.append({"role": m.role, "content": m.content})
437
+
438
+ create_kwargs = {
439
+ "model": self.model,
440
+ "messages": anth_messages,
441
+ "max_tokens": self.max_tokens,
442
+ }
443
+ if system_msg:
444
+ create_kwargs["system"] = system_msg
445
+
446
+ response = await loop.run_in_executor(
447
+ None, lambda: self._client.messages.create(**create_kwargs)
448
+ )
449
+
450
+ content = ""
451
+ for block in response.content:
452
+ if block.type == "text":
453
+ content += block.text
454
+
455
+ return LLMResponse(
456
+ content=content,
457
+ usage={
458
+ "input_tokens": response.usage.input_tokens,
459
+ "output_tokens": response.usage.output_tokens,
460
+ },
461
+ model=response.model,
462
+ finish_reason=response.stop_reason or "",
463
+ )
464
+
465
+ async def _chat_ollama(self, kwargs: dict) -> LLMResponse:
466
+ """Ollama 本地模型调用"""
467
+ import requests
468
+ loop = asyncio.get_running_loop()
469
+
470
+ url = f"{self.base_url}/api/chat"
471
+ payload = {
472
+ "model": self.model,
473
+ "messages": kwargs["messages"],
474
+ "stream": False,
475
+ "options": {
476
+ "temperature": self.temperature,
477
+ "num_predict": self.max_tokens,
478
+ }
479
+ }
480
+
481
+ def _request():
482
+ r = requests.post(url, json=payload, timeout=self.timeout)
483
+ r.raise_for_status()
484
+ return r.json()
485
+
486
+ result = await loop.run_in_executor(None, _request)
487
+ return LLMResponse(
488
+ content=result.get("message", {}).get("content", ""),
489
+ usage={
490
+ "prompt_tokens": result.get("prompt_eval_count", 0),
491
+ "completion_tokens": result.get("eval_count", 0),
492
+ },
493
+ model=self.model,
494
+ finish_reason="stop" if result.get("done") else "",
495
+ )
496
+
497
+ # ------------------------------------------------------------------
498
+ # 流式输出 (Streaming)
499
+ # ------------------------------------------------------------------
500
+
501
+ async def chat_stream(
502
+ self,
503
+ messages: List[Message],
504
+ tools: Optional[List[Dict]] = None,
505
+ tool_choice: str = "auto",
506
+ response_format: Optional[Dict] = None,
507
+ **kwargs,
508
+ ) -> AsyncGenerator[str, None]:
509
+ """
510
+ 流式聊天:逐 chunk yield 文本片段。
511
+
512
+ Args:
513
+ messages: 消息列表
514
+ tools: 可用工具列表
515
+ tool_choice: 工具选择策略
516
+ response_format: 响应格式
517
+ **kwargs: 额外参数
518
+
519
+ Yields:
520
+ str: 每次 yield 一个文本 chunk
521
+ """
522
+ self._ensure_client()
523
+
524
+ msg_dicts = [m.to_dict() for m in messages]
525
+ request_kwargs = {
526
+ "model": self.model,
527
+ "messages": msg_dicts,
528
+ "temperature": kwargs.pop("temperature", self.temperature),
529
+ "max_tokens": self.max_tokens,
530
+ "stream": True,
531
+ }
532
+ if tools:
533
+ request_kwargs["tools"] = tools
534
+ request_kwargs["tool_choice"] = tool_choice
535
+ if response_format:
536
+ request_kwargs["response_format"] = response_format
537
+ request_kwargs.update(kwargs)
538
+
539
+ try:
540
+ if self.provider in ("openai", "custom", "zhipu"):
541
+ async for chunk in self._stream_openai(request_kwargs):
542
+ yield chunk
543
+ elif self.provider == "anthropic":
544
+ async for chunk in self._stream_anthropic(messages, request_kwargs):
545
+ yield chunk
546
+ elif self.provider == "ollama":
547
+ async for chunk in self._stream_ollama(request_kwargs):
548
+ yield chunk
549
+ else:
550
+ logger.error(f"流式调用不支持提供商: {self.provider}")
551
+ except Exception as e:
552
+ logger.error(f"流式 LLM 调用失败: {e}")
553
+
554
+ async def _stream_openai(self, kwargs: dict) -> AsyncGenerator[str, None]:
555
+ """OpenAI / 兼容接口 (含 Zhipu) 流式调用"""
556
+ loop = asyncio.get_running_loop()
557
+
558
+ def _create_stream():
559
+ return self._client.chat.completions.create(**kwargs)
560
+
561
+ stream = await loop.run_in_executor(None, _create_stream)
562
+
563
+ # 使用迭代器在 executor 中逐步获取
564
+ def _next_chunk(it):
565
+ try:
566
+ return next(it)
567
+ except StopIteration:
568
+ return None
569
+
570
+ iterator = iter(stream)
571
+ while True:
572
+ chunk = await loop.run_in_executor(None, _next_chunk, iterator)
573
+ if chunk is None:
574
+ break
575
+ if chunk.choices and chunk.choices[0].delta.content:
576
+ yield chunk.choices[0].delta.content
577
+
578
+ async def _stream_anthropic(
579
+ self, messages: List[Message], kwargs: dict
580
+ ) -> AsyncGenerator[str, None]:
581
+ """Anthropic Claude 流式调用"""
582
+ loop = asyncio.get_running_loop()
583
+
584
+ # 转换消息格式
585
+ system_msg = ""
586
+ anth_messages = []
587
+ for m in messages:
588
+ if m.role == "system":
589
+ system_msg = m.content
590
+ continue
591
+ anth_messages.append({"role": m.role, "content": m.content})
592
+
593
+ create_kwargs = {
594
+ "model": self.model,
595
+ "messages": anth_messages,
596
+ "max_tokens": self.max_tokens,
597
+ "stream": True,
598
+ }
599
+ if system_msg:
600
+ create_kwargs["system"] = system_msg
601
+
602
+ def _create_stream():
603
+ return self._client.messages.create(**create_kwargs)
604
+
605
+ stream = await loop.run_in_executor(None, _create_stream)
606
+
607
+ def _next_event(it):
608
+ try:
609
+ return next(it)
610
+ except StopIteration:
611
+ return None
612
+
613
+ iterator = iter(stream)
614
+ while True:
615
+ event = await loop.run_in_executor(None, _next_event, iterator)
616
+ if event is None:
617
+ break
618
+ if event.type == "content_block_delta":
619
+ if hasattr(event.delta, "text"):
620
+ yield event.delta.text
621
+
622
+ async def _stream_ollama(self, kwargs: dict) -> AsyncGenerator[str, None]:
623
+ """Ollama 流式调用"""
624
+ import requests
625
+ loop = asyncio.get_running_loop()
626
+
627
+ url = f"{self.base_url}/api/chat"
628
+ payload = {
629
+ "model": self.model,
630
+ "messages": kwargs["messages"],
631
+ "stream": True,
632
+ "options": {
633
+ "temperature": self.temperature,
634
+ "num_predict": self.max_tokens,
635
+ }
636
+ }
637
+
638
+ def _request_stream():
639
+ return requests.post(url, json=payload, timeout=self.timeout, stream=True)
640
+
641
+ resp = await loop.run_in_executor(None, _request_stream)
642
+ resp.raise_for_status()
643
+
644
+ import io
645
+ buffer = ""
646
+
647
+ def _read_chunk():
648
+ nonlocal buffer
649
+ # Read line by line from streaming response
650
+ for line in resp.iter_lines():
651
+ if not line:
652
+ continue
653
+ decoded = line.decode("utf-8")
654
+ try:
655
+ data = json.loads(decoded)
656
+ return data.get("message", {}).get("content", "")
657
+ except json.JSONDecodeError:
658
+ continue
659
+ return None
660
+
661
+ while True:
662
+ chunk = await loop.run_in_executor(None, _read_chunk)
663
+ if chunk is None:
664
+ break
665
+ if chunk:
666
+ yield chunk
667
+
668
+ # ------------------------------------------------------------------
669
+ # 同步包装
670
+ # ------------------------------------------------------------------
671
+
672
+ def chat_sync(
673
+ self,
674
+ messages: List[Message],
675
+ **kwargs,
676
+ ) -> LLMResponse:
677
+ """同步版本聊天方法"""
678
+ try:
679
+ loop = asyncio.get_running_loop()
680
+ except RuntimeError:
681
+ loop = None
682
+
683
+ if loop and loop.is_running():
684
+ import concurrent.futures
685
+ with concurrent.futures.ThreadPoolExecutor() as pool:
686
+ future = pool.submit(asyncio.run, self.chat(messages, **kwargs))
687
+ return future.result()
688
+ else:
689
+ return asyncio.run(self.chat(messages, **kwargs))
690
+
691
+ # ------------------------------------------------------------------
692
+ # JSON 严格解析 (4 策略)
693
+ # ------------------------------------------------------------------
694
+
695
+ @staticmethod
696
+ def _parse_json_strict(text: str) -> Any:
697
+ """
698
+ 使用多策略严格解析 JSON 字符串。
699
+ 复用 core.utils.safe_json_parse (3 策略: 直接/代码块/括号匹配)。
700
+
701
+ Returns:
702
+ 解析后的 Python 对象,全部失败返回 None。
703
+ """
704
+ if not text:
705
+ return None
706
+ result = safe_json_parse(text)
707
+ if result is not None:
708
+ return result
709
+ return None
710
+
711
+ async def chat_json_strict(
712
+ self,
713
+ messages: List[Message],
714
+ required_fields: Optional[List[str]] = None,
715
+ max_retries: int = 2,
716
+ **kwargs,
717
+ ) -> Dict[str, Any]:
718
+ """
719
+ 发送聊天请求并严格解析为 JSON 对象。
720
+
721
+ 特性:
722
+ - 自动注入 JSON 模式系统指令
723
+ - 使用 temperature=0 确保确定性
724
+ - 4 策略严格解析
725
+ - 失败自动重试 (默认 1 次)
726
+ - 校验 required_fields
727
+
728
+ Args:
729
+ messages: 消息列表
730
+ required_fields: 必需字段列表
731
+ max_retries: 解析失败最大重试次数 (默认 2,即原始 + 1 次重试)
732
+ **kwargs: 额外参数
733
+
734
+ Returns:
735
+ 解析后的字典
736
+ """
737
+ # 注入 JSON 模式系统指令
738
+ json_system = (
739
+ "你必须且只能以合法 JSON 格式回复。"
740
+ "不要包含任何多余文本、解释、说明或 markdown 标记。"
741
+ "直接输出 JSON 对象或 JSON 数组。"
742
+ )
743
+ has_json_instruction = False
744
+ for m in messages:
745
+ if m.role == "system" and "json" in m.content.lower():
746
+ has_json_instruction = True
747
+ break
748
+
749
+ if not has_json_instruction:
750
+ messages = [
751
+ Message(role="system", content=json_system),
752
+ *messages,
753
+ ]
754
+
755
+ # 强制 temperature=0
756
+ kwargs.setdefault("temperature", 0)
757
+
758
+ last_error = ""
759
+ for attempt in range(max_retries):
760
+ response = await self.chat(messages, **kwargs)
761
+
762
+ if not response.success:
763
+ last_error = response.error
764
+ logger.warning(
765
+ f"chat_json_strict 第 {attempt + 1}/{max_retries} 次 "
766
+ f"调用失败: {response.error}"
767
+ )
768
+ if attempt < max_retries - 1:
769
+ await asyncio.sleep(1.0)
770
+ continue
771
+
772
+ # 4 策略解析
773
+ result = self._parse_json_strict(response.content)
774
+
775
+ if result is not None:
776
+ if isinstance(result, list):
777
+ result = {"items": result}
778
+ if not isinstance(result, dict):
779
+ last_error = f"解析结果不是 dict/list,而是 {type(result).__name__}"
780
+ logger.warning(last_error)
781
+ if attempt < max_retries - 1:
782
+ await asyncio.sleep(1.0)
783
+ continue
784
+
785
+ # 校验必需字段
786
+ if required_fields:
787
+ missing = [f for f in required_fields if f not in result]
788
+ if missing:
789
+ last_error = f"缺少必需字段: {', '.join(missing)}"
790
+ logger.warning(
791
+ f"chat_json_strict 第 {attempt + 1}/{max_retries} 次: {last_error}"
792
+ )
793
+ # 追加提醒后重试
794
+ messages = [
795
+ *messages,
796
+ Message(
797
+ role="user",
798
+ content=(
799
+ f"你的回复缺少必需字段: {', '.join(missing)}。"
800
+ f"请重新以合法 JSON 格式回复,包含所有必需字段。"
801
+ ),
802
+ ),
803
+ ]
804
+ if attempt < max_retries - 1:
805
+ await asyncio.sleep(1.0)
806
+ continue
807
+
808
+ return result
809
+
810
+ last_error = "所有解析策略均失败"
811
+ logger.warning(
812
+ f"chat_json_strict 第 {attempt + 1}/{max_retries} 次: {last_error}"
813
+ )
814
+ # 追加提醒后重试
815
+ messages = [
816
+ *messages,
817
+ Message(
818
+ role="user",
819
+ content="你的回复无法解析为 JSON。请只输出合法的 JSON,不要包含其他文本。",
820
+ ),
821
+ ]
822
+ if attempt < max_retries - 1:
823
+ await asyncio.sleep(1.0)
824
+
825
+ return {"error": f"JSON 解析失败: {last_error}", "raw": response.content if 'response' in dir() else ""}
826
+
827
+ # ------------------------------------------------------------------
828
+ # 原有 JSON 方法 (保留向后兼容)
829
+ # ------------------------------------------------------------------
830
+
831
+ async def chat_json(
832
+ self,
833
+ messages: List[Message],
834
+ required_fields: Optional[List[str]] = None,
835
+ **kwargs,
836
+ ) -> Dict[str, Any]:
837
+ """
838
+ 发送聊天请求并解析为 JSON 对象。
839
+ 委托给 chat_json_strict() (更严格的 4 策略解析 + 重试)。
840
+ 添加 response_format=json_object 以利用 OpenAI 兼容的 JSON mode。
841
+ """
842
+ kwargs.setdefault("response_format", {"type": "json_object"})
843
+ return await self.chat_json_strict(
844
+ messages, required_fields=required_fields, max_retries=1, **kwargs
845
+ )
846
+
847
+
848
+ # ==============================================================================
849
+ # 全局 LLM 客户端工厂
850
+ # ==============================================================================
851
+
852
+ _global_llm_client: Optional[LLMClient] = None
853
+
854
+
855
+ def get_llm_client() -> LLMClient:
856
+ """获取全局 LLM 客户端"""
857
+ global _global_llm_client
858
+ if _global_llm_client is None:
859
+ from config import get_config
860
+ cfg = get_config().config.llm
861
+ _global_llm_client = LLMClient(
862
+ provider=cfg.provider,
863
+ api_key=cfg.api_key,
864
+ base_url=cfg.base_url,
865
+ model=cfg.model,
866
+ temperature=cfg.temperature,
867
+ max_tokens=cfg.max_tokens,
868
+ timeout=cfg.timeout,
869
+ max_retries=cfg.max_retries,
870
+ anthropic_api_key=cfg.anthropic_api_key,
871
+ )
872
+ return _global_llm_client
873
+
874
+
875
+ def reset_llm_client():
876
+ """重置全局客户端"""
877
+ global _global_llm_client
878
+ _global_llm_client = None