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
@@ -0,0 +1,576 @@
1
+ """
2
+ communication/channel.py - Message Channel
3
+ ===========================================
4
+ LocalChannel: same-machine agent-to-agent via asyncio queues.
5
+ RemoteChannel: cross-machine communication via WebSocket (AICQ relay).
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import json
11
+ import time
12
+ import uuid
13
+ import logging
14
+ from dataclasses import dataclass, field, asdict
15
+ from typing import Optional, List, Callable, Awaitable, Any
16
+
17
+ from .crypto import (
18
+ derive_shared_key,
19
+ generate_x25519_keypair,
20
+ x25519_key_exchange,
21
+ encrypt_message,
22
+ decrypt_message,
23
+ sign,
24
+ verify,
25
+ serialize_public_key,
26
+ deserialize_public_key,
27
+ )
28
+
29
+ logger = logging.getLogger("myagent.communication")
30
+
31
+
32
+ # =========================================================================
33
+ # Message Data Model
34
+ # =========================================================================
35
+
36
+ @dataclass
37
+ class Message:
38
+ """A communication message between agents."""
39
+
40
+ id: str = ""
41
+ from_agent: str = "" # Sender agent_id
42
+ to_agent: str = "" # Recipient agent_id
43
+ content: str = "" # Plaintext content
44
+ timestamp: float = 0.0
45
+ encrypted: bool = False
46
+ signature: str = "" # Hex signature (from sender)
47
+ msg_type: str = "text" # text | handshake | heartbeat | ack
48
+
49
+ def __post_init__(self):
50
+ if not self.id:
51
+ self.id = uuid.uuid4().hex[:16]
52
+ if self.timestamp == 0.0:
53
+ self.timestamp = time.time()
54
+
55
+ def to_dict(self) -> dict:
56
+ d = asdict(self)
57
+ return d
58
+
59
+ @classmethod
60
+ def from_dict(cls, data: dict) -> "Message":
61
+ return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
62
+
63
+ def to_json(self) -> str:
64
+ return json.dumps(self.to_dict(), ensure_ascii=False)
65
+
66
+
67
+ # =========================================================================
68
+ # Message Callback
69
+ # =========================================================================
70
+
71
+ MessageCallback = Callable[[Message], Awaitable[None]]
72
+
73
+
74
+ # =========================================================================
75
+ # Local Channel — Same-Machine Agent Communication
76
+ # =========================================================================
77
+
78
+ class LocalChannel:
79
+ """
80
+ LocalChannel enables encrypted message passing between agents on the
81
+ same machine using asyncio queues.
82
+
83
+ Each agent instance has its own ``LocalChannel``. Messages are routed
84
+ through a shared broker (dict of queues) keyed by agent_id.
85
+ """
86
+
87
+ # Shared broker across all LocalChannel instances on this process
88
+ _queues: dict[str, asyncio.Queue] = {}
89
+ _callbacks: dict[str, List[MessageCallback]] = {}
90
+
91
+ def __init__(
92
+ self,
93
+ agent_id: str,
94
+ ed25519_private_key: bytes,
95
+ ed25519_public_key: bytes,
96
+ ):
97
+ self.agent_id = agent_id
98
+ self._ed_priv = ed25519_private_key
99
+ self._ed_pub = ed25519_public_key
100
+
101
+ # Generate standalone X25519 keypair for DH (separate from Ed25519)
102
+ self._x_priv, self._x_pub = generate_x25519_keypair()
103
+
104
+ # Ensure our queue exists
105
+ if agent_id not in LocalChannel._queues:
106
+ LocalChannel._queues[agent_id] = asyncio.Queue()
107
+ if agent_id not in LocalChannel._callbacks:
108
+ LocalChannel._callbacks[agent_id] = []
109
+
110
+ self._running = False
111
+ self._receiver_task: Optional[asyncio.Task] = None
112
+
113
+ # ------------------------------------------------------------------
114
+ # Derive a shared AES key with another agent
115
+ # ------------------------------------------------------------------
116
+
117
+ def _derive_key(self, their_ed_pub: bytes) -> bytes:
118
+ their_x_pub = ed25519_to_x25519_public(their_ed_pub)
119
+ shared_secret = None
120
+ # Simple DH: we need the actual x25519 exchange function
121
+ from .crypto import x25519_key_exchange
122
+ shared_secret = x25519_key_exchange(self._x_priv, their_x_pub)
123
+ return derive_shared_key(shared_secret)
124
+
125
+ # ------------------------------------------------------------------
126
+ # Send
127
+ # ------------------------------------------------------------------
128
+
129
+ async def send(
130
+ self,
131
+ to_agent: str,
132
+ content: str,
133
+ msg_type: str = "text",
134
+ their_public_key: Optional[bytes] = None,
135
+ ) -> Message:
136
+ """Send an encrypted message to a local peer."""
137
+ msg = Message(
138
+ from_agent=self.agent_id,
139
+ to_agent=to_agent,
140
+ content=content,
141
+ msg_type=msg_type,
142
+ )
143
+
144
+ # Sign the message
145
+ msg_data = json.dumps({
146
+ "id": msg.id,
147
+ "from": msg.from_agent,
148
+ "to": msg.to_agent,
149
+ "content": msg.content,
150
+ "timestamp": msg.timestamp,
151
+ "type": msg.msg_type,
152
+ }, sort_keys=True).encode("utf-8")
153
+ sig = sign(self._ed_priv, msg_data)
154
+ msg.signature = sig.hex()
155
+
156
+ # Note: encryption requires a pre-established shared key.
157
+ # In local mode, messages are already in-process and signed.
158
+ # For real E2EE, the shared key must be established via DH with
159
+ # the peer's X25519 public key (separate from Ed25519 identity).
160
+ msg.encrypted = False
161
+
162
+ # Put into recipient's queue
163
+ queue = LocalChannel._queues.get(to_agent)
164
+ if queue is None:
165
+ raise RuntimeError(f"LocalChannel: agent '{to_agent}' has no queue")
166
+
167
+ await queue.put(msg)
168
+ return msg
169
+
170
+ # ------------------------------------------------------------------
171
+ # Receive
172
+ # ------------------------------------------------------------------
173
+
174
+ def on_message(self, callback: MessageCallback):
175
+ """Register a callback for incoming messages."""
176
+ LocalChannel._callbacks.setdefault(self.agent_id, []).append(callback)
177
+
178
+ async def _dispatch(self, msg: Message):
179
+ """Dispatch a received message to registered callbacks."""
180
+ for cb in LocalChannel._callbacks.get(self.agent_id, []):
181
+ try:
182
+ await cb(msg)
183
+ except Exception as e:
184
+ logger.error(f"LocalChannel callback error: {e}", exc_info=True)
185
+
186
+ # ------------------------------------------------------------------
187
+ # Receiver loop
188
+ # ------------------------------------------------------------------
189
+
190
+ async def _receiver_loop(self):
191
+ """Background task: read from queue and dispatch."""
192
+ queue = LocalChannel._queues.get(self.agent_id)
193
+ if not queue:
194
+ return
195
+ while self._running:
196
+ try:
197
+ msg = await asyncio.wait_for(queue.get(), timeout=1.0)
198
+ await self._dispatch(msg)
199
+ except asyncio.TimeoutError:
200
+ continue
201
+ except Exception as e:
202
+ logger.error(f"LocalChannel receiver error: {e}")
203
+
204
+ def start(self):
205
+ """Start the receiver loop."""
206
+ if self._running:
207
+ return
208
+ self._running = True
209
+ self._receiver_task = asyncio.create_task(self._receiver_loop())
210
+
211
+ async def stop(self):
212
+ """Stop the receiver loop."""
213
+ self._running = False
214
+ if self._receiver_task:
215
+ self._receiver_task.cancel()
216
+ try:
217
+ await self._receiver_task
218
+ except asyncio.CancelledError:
219
+ pass
220
+ self._receiver_task = None
221
+
222
+ # ------------------------------------------------------------------
223
+ # Static: register a new agent queue
224
+ # ------------------------------------------------------------------
225
+
226
+ @staticmethod
227
+ def register_agent(agent_id: str):
228
+ """Register a new agent in the shared broker."""
229
+ if agent_id not in LocalChannel._queues:
230
+ LocalChannel._queues[agent_id] = asyncio.Queue()
231
+ if agent_id not in LocalChannel._callbacks:
232
+ LocalChannel._callbacks[agent_id] = []
233
+
234
+
235
+ # =========================================================================
236
+ # Remote Channel — Cross-Machine via WebSocket
237
+ # =========================================================================
238
+
239
+ class RemoteChannel:
240
+ """
241
+ RemoteChannel connects to the AICQ relay server via WebSocket for
242
+ cross-machine agent communication.
243
+
244
+ Features:
245
+ - Encrypted messaging via AES-256-GCM
246
+ - Offline message queue (SQLite)
247
+ - Automatic reconnection
248
+ - Heartbeat for online status
249
+ """
250
+
251
+ def __init__(
252
+ self,
253
+ agent_id: str,
254
+ ed25519_private_key: bytes,
255
+ ed25519_public_key: bytes,
256
+ server_url: str = "wss://aicq.online/ws",
257
+ queue_db_path: str = "",
258
+ ):
259
+ self.agent_id = agent_id
260
+ self._ed_priv = ed25519_private_key
261
+ self._ed_pub = ed25519_public_key
262
+ self.server_url = server_url
263
+ self._queue_db_path = queue_db_path
264
+
265
+ # Generate standalone X25519 keypair for DH
266
+ self._x_priv, self._x_pub = generate_x25519_keypair()
267
+
268
+ self._ws = None
269
+ self._running = False
270
+ self._connected = False
271
+ self._recv_task: Optional[asyncio.Task] = None
272
+ self._heartbeat_task: Optional[asyncio.Task] = None
273
+ self._callbacks: List[MessageCallback] = []
274
+ self._shared_keys: dict[str, bytes] = {} # agent_id -> AES key
275
+ self._pending_handshakes: dict[str, asyncio.Future] = {}
276
+
277
+ # Offline queue
278
+ self._queue_conn = None
279
+
280
+ # ------------------------------------------------------------------
281
+ # Offline Queue (SQLite)
282
+ # ------------------------------------------------------------------
283
+
284
+ def _init_queue_db(self):
285
+ """Initialize the offline message queue SQLite database."""
286
+ if not self._queue_db_path:
287
+ return
288
+ import sqlite3
289
+ self._queue_conn = sqlite3.connect(self._queue_db_path)
290
+ self._queue_conn.execute("""
291
+ CREATE TABLE IF NOT EXISTS queued_messages (
292
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
293
+ from_agent TEXT NOT NULL,
294
+ to_agent TEXT NOT NULL,
295
+ encrypted_content TEXT NOT NULL,
296
+ created_at REAL NOT NULL,
297
+ delivered INTEGER DEFAULT 0
298
+ )
299
+ """)
300
+ self._queue_conn.commit()
301
+
302
+ def _queue_message(self, from_agent: str, to_agent: str, encrypted_content: str):
303
+ """Queue a message for later delivery."""
304
+ if not self._queue_conn:
305
+ return
306
+ self._queue_conn.execute(
307
+ "INSERT INTO queued_messages (from_agent, to_agent, encrypted_content, created_at, delivered) VALUES (?, ?, ?, ?, 0)",
308
+ (from_agent, to_agent, encrypted_content, time.time()),
309
+ )
310
+ self._queue_conn.commit()
311
+
312
+ def _get_undelivered(self) -> list:
313
+ """Get undelivered messages."""
314
+ if not self._queue_conn:
315
+ return []
316
+ rows = self._queue_conn.execute(
317
+ "SELECT id, from_agent, to_agent, encrypted_content, created_at FROM queued_messages WHERE delivered = 0 ORDER BY created_at ASC"
318
+ ).fetchall()
319
+ return [{"id": r[0], "from": r[1], "to": r[2], "content": r[3], "created": r[4]} for r in rows]
320
+
321
+ def _mark_delivered(self, msg_id: int):
322
+ """Mark a message as delivered."""
323
+ if not self._queue_conn:
324
+ return
325
+ self._queue_conn.execute(
326
+ "UPDATE queued_messages SET delivered = 1 WHERE id = ?", (msg_id,)
327
+ )
328
+ self._queue_conn.commit()
329
+
330
+ # ------------------------------------------------------------------
331
+ # Key Management
332
+ # ------------------------------------------------------------------
333
+
334
+ def _get_or_derive_key(self, their_agent_id: str, their_x25519_pub: bytes) -> bytes:
335
+ """Get or derive a shared key with a peer using their X25519 public key."""
336
+ if their_agent_id in self._shared_keys:
337
+ return self._shared_keys[their_agent_id]
338
+ shared = x25519_key_exchange(self._x_priv, their_x25519_pub)
339
+ key = derive_shared_key(shared)
340
+ self._shared_keys[their_agent_id] = key
341
+ return key
342
+
343
+ # ------------------------------------------------------------------
344
+ # WebSocket Connection
345
+ # ------------------------------------------------------------------
346
+
347
+ async def connect(self):
348
+ """Connect to the AICQ relay server."""
349
+ try:
350
+ import websockets
351
+ self._ws = await websockets.connect(
352
+ self.server_url,
353
+ ping_interval=30,
354
+ ping_timeout=10,
355
+ close_timeout=5,
356
+ )
357
+ self._connected = True
358
+ logger.info(f"RemoteChannel: connected to {self.server_url}")
359
+
360
+ # Send auth/register message (includes both identity and DH key)
361
+ auth_msg = json.dumps({
362
+ "type": "register",
363
+ "agent_id": self.agent_id,
364
+ "public_key": serialize_public_key(self._ed_pub),
365
+ "dh_public_key": self._x_pub.hex(),
366
+ })
367
+ await self._ws.send(auth_msg)
368
+
369
+ except Exception as e:
370
+ logger.warning(f"RemoteChannel: connection failed: {e}")
371
+ self._connected = False
372
+
373
+ async def disconnect(self):
374
+ """Disconnect from the relay server."""
375
+ self._connected = False
376
+ if self._ws:
377
+ try:
378
+ await self._ws.close()
379
+ except Exception:
380
+ pass
381
+ self._ws = None
382
+
383
+ # ------------------------------------------------------------------
384
+ # Send
385
+ # ------------------------------------------------------------------
386
+
387
+ async def send(
388
+ self,
389
+ to_agent: str,
390
+ content: str,
391
+ their_ed_pub_hex: str = "",
392
+ their_x25519_pub_hex: str = "",
393
+ msg_type: str = "text",
394
+ ) -> Message:
395
+ """Send an encrypted message to a remote peer."""
396
+ msg = Message(
397
+ from_agent=self.agent_id,
398
+ to_agent=to_agent,
399
+ content=content,
400
+ msg_type=msg_type,
401
+ )
402
+
403
+ # Sign the message
404
+ msg_data = json.dumps({
405
+ "id": msg.id,
406
+ "from": msg.from_agent,
407
+ "to": msg.to_agent,
408
+ "content": msg.content,
409
+ "timestamp": msg.timestamp,
410
+ "type": msg.msg_type,
411
+ }, sort_keys=True).encode("utf-8")
412
+ sig = sign(self._ed_priv, msg_data)
413
+ msg.signature = sig.hex()
414
+
415
+ # Encrypt using X25519 DH shared key
416
+ if their_x25519_pub_hex:
417
+ try:
418
+ their_x_pub = bytes.fromhex(their_x25519_pub_hex)
419
+ shared_key = self._get_or_derive_key(to_agent, their_x_pub)
420
+ encrypted_payload = encrypt_message(shared_key, {
421
+ "content": content,
422
+ "timestamp": msg.timestamp,
423
+ "msg_type": msg.msg_type,
424
+ "msg_id": msg.id,
425
+ "signature": msg.signature,
426
+ })
427
+ msg.content = encrypted_payload
428
+ msg.encrypted = True
429
+ except Exception as e:
430
+ logger.warning(f"RemoteChannel encryption failed: {e}")
431
+ msg.encrypted = False
432
+ else:
433
+ msg.encrypted = False
434
+
435
+ # Send via WebSocket or queue
436
+ wire_msg = json.dumps({
437
+ "type": msg_type,
438
+ "from": msg.from_agent,
439
+ "to": msg.to_agent,
440
+ "content": msg.content,
441
+ "encrypted": msg.encrypted,
442
+ "timestamp": msg.timestamp,
443
+ "msg_id": msg.id,
444
+ "signature": msg.signature,
445
+ })
446
+
447
+ if self._connected and self._ws:
448
+ try:
449
+ await self._ws.send(wire_msg)
450
+ except Exception as e:
451
+ logger.warning(f"RemoteChannel: send failed, queuing: {e}")
452
+ self._queue_message(msg.from_agent, msg.to_agent, wire_msg)
453
+ self._connected = False
454
+ else:
455
+ self._queue_message(msg.from_agent, msg.to_agent, wire_msg)
456
+
457
+ return msg
458
+
459
+ # ------------------------------------------------------------------
460
+ # Receive Loop
461
+ # ------------------------------------------------------------------
462
+
463
+ async def _receiver_loop(self):
464
+ """Background task: receive messages from WebSocket."""
465
+ while self._running:
466
+ if not self._connected:
467
+ try:
468
+ await self.connect()
469
+ except Exception:
470
+ await asyncio.sleep(5)
471
+ continue
472
+
473
+ try:
474
+ raw = await self._ws.recv()
475
+ data = json.loads(raw)
476
+ await self._handle_incoming(data)
477
+ except Exception as e:
478
+ if self._running:
479
+ logger.warning(f"RemoteChannel recv error: {e}")
480
+ self._connected = False
481
+ await asyncio.sleep(1)
482
+
483
+ async def _handle_incoming(self, data: dict):
484
+ """Handle an incoming message from the relay."""
485
+ msg_type = data.get("type", "text")
486
+
487
+ if msg_type == "heartbeat_ack":
488
+ return
489
+
490
+ msg = Message(
491
+ id=data.get("msg_id", ""),
492
+ from_agent=data.get("from", ""),
493
+ to_agent=data.get("to", ""),
494
+ content=data.get("content", ""),
495
+ timestamp=data.get("timestamp", 0.0),
496
+ encrypted=data.get("encrypted", False),
497
+ signature=data.get("signature", ""),
498
+ msg_type=msg_type,
499
+ )
500
+
501
+ # Dispatch to callbacks
502
+ for cb in self._callbacks:
503
+ try:
504
+ await cb(msg)
505
+ except Exception as e:
506
+ logger.error(f"RemoteChannel callback error: {e}")
507
+
508
+ # ------------------------------------------------------------------
509
+ # Heartbeat
510
+ # ------------------------------------------------------------------
511
+
512
+ async def _heartbeat_loop(self):
513
+ """Periodically send heartbeat messages."""
514
+ while self._running:
515
+ await asyncio.sleep(30)
516
+ if self._connected and self._ws:
517
+ try:
518
+ await self._ws.send(json.dumps({"type": "heartbeat"}))
519
+ except Exception:
520
+ self._connected = False
521
+
522
+ # ------------------------------------------------------------------
523
+ # Retry Undelivered Messages
524
+ # ------------------------------------------------------------------
525
+
526
+ async def _retry_loop(self):
527
+ """Periodically retry sending queued messages."""
528
+ while self._running:
529
+ await asyncio.sleep(10)
530
+ if not self._connected or not self._ws:
531
+ continue
532
+ undelivered = self._get_undelivered()
533
+ for item in undelivered:
534
+ try:
535
+ await self._ws.send(item["content"])
536
+ self._mark_delivered(item["id"])
537
+ except Exception:
538
+ break # Stop retrying if send fails
539
+
540
+ # ------------------------------------------------------------------
541
+ # Lifecycle
542
+ # ------------------------------------------------------------------
543
+
544
+ def on_message(self, callback: MessageCallback):
545
+ """Register a callback for incoming messages."""
546
+ self._callbacks.append(callback)
547
+
548
+ def start(self):
549
+ """Start the remote channel (receiver, heartbeat, retry loops)."""
550
+ if self._running:
551
+ return
552
+ self._running = True
553
+ self._init_queue_db()
554
+ self._recv_task = asyncio.create_task(self._receiver_loop())
555
+ self._heartbeat_task = asyncio.create_task(self._heartbeat_loop())
556
+ asyncio.create_task(self._retry_loop())
557
+
558
+ async def stop(self):
559
+ """Stop the remote channel."""
560
+ self._running = False
561
+ await self.disconnect()
562
+ if self._recv_task:
563
+ self._recv_task.cancel()
564
+ try:
565
+ await self._recv_task
566
+ except asyncio.CancelledError:
567
+ pass
568
+ if self._heartbeat_task:
569
+ self._heartbeat_task.cancel()
570
+ try:
571
+ await self._heartbeat_task
572
+ except asyncio.CancelledError:
573
+ pass
574
+ if self._queue_conn:
575
+ self._queue_conn.close()
576
+ self._queue_conn = None