ai-parrot 0.17.2__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

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 (535) hide show
  1. agentui/.prettierrc +15 -0
  2. agentui/QUICKSTART.md +272 -0
  3. agentui/README.md +59 -0
  4. agentui/env.example +16 -0
  5. agentui/jsconfig.json +14 -0
  6. agentui/package-lock.json +4242 -0
  7. agentui/package.json +34 -0
  8. agentui/scripts/postinstall/apply-patches.mjs +260 -0
  9. agentui/src/app.css +61 -0
  10. agentui/src/app.d.ts +13 -0
  11. agentui/src/app.html +12 -0
  12. agentui/src/components/LoadingSpinner.svelte +64 -0
  13. agentui/src/components/ThemeSwitcher.svelte +159 -0
  14. agentui/src/components/index.js +4 -0
  15. agentui/src/lib/api/bots.ts +60 -0
  16. agentui/src/lib/api/chat.ts +22 -0
  17. agentui/src/lib/api/http.ts +25 -0
  18. agentui/src/lib/components/BotCard.svelte +33 -0
  19. agentui/src/lib/components/ChatBubble.svelte +63 -0
  20. agentui/src/lib/components/Toast.svelte +21 -0
  21. agentui/src/lib/config.ts +20 -0
  22. agentui/src/lib/stores/auth.svelte.ts +73 -0
  23. agentui/src/lib/stores/theme.svelte.js +64 -0
  24. agentui/src/lib/stores/toast.svelte.ts +31 -0
  25. agentui/src/lib/utils/conversation.ts +39 -0
  26. agentui/src/routes/+layout.svelte +20 -0
  27. agentui/src/routes/+page.svelte +232 -0
  28. agentui/src/routes/login/+page.svelte +200 -0
  29. agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
  30. agentui/src/routes/talk/[agentId]/+page.ts +7 -0
  31. agentui/static/README.md +1 -0
  32. agentui/svelte.config.js +11 -0
  33. agentui/tailwind.config.ts +53 -0
  34. agentui/tsconfig.json +3 -0
  35. agentui/vite.config.ts +10 -0
  36. ai_parrot-0.17.2.dist-info/METADATA +472 -0
  37. ai_parrot-0.17.2.dist-info/RECORD +535 -0
  38. ai_parrot-0.17.2.dist-info/WHEEL +6 -0
  39. ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
  40. ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
  41. ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
  42. crew-builder/.prettierrc +15 -0
  43. crew-builder/QUICKSTART.md +259 -0
  44. crew-builder/README.md +113 -0
  45. crew-builder/env.example +17 -0
  46. crew-builder/jsconfig.json +14 -0
  47. crew-builder/package-lock.json +4182 -0
  48. crew-builder/package.json +37 -0
  49. crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
  50. crew-builder/src/app.css +62 -0
  51. crew-builder/src/app.d.ts +13 -0
  52. crew-builder/src/app.html +12 -0
  53. crew-builder/src/components/LoadingSpinner.svelte +64 -0
  54. crew-builder/src/components/ThemeSwitcher.svelte +149 -0
  55. crew-builder/src/components/index.js +9 -0
  56. crew-builder/src/lib/api/bots.ts +60 -0
  57. crew-builder/src/lib/api/chat.ts +80 -0
  58. crew-builder/src/lib/api/client.ts +56 -0
  59. crew-builder/src/lib/api/crew/crew.ts +136 -0
  60. crew-builder/src/lib/api/index.ts +5 -0
  61. crew-builder/src/lib/api/o365/auth.ts +65 -0
  62. crew-builder/src/lib/auth/auth.ts +54 -0
  63. crew-builder/src/lib/components/AgentNode.svelte +43 -0
  64. crew-builder/src/lib/components/BotCard.svelte +33 -0
  65. crew-builder/src/lib/components/ChatBubble.svelte +67 -0
  66. crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
  67. crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
  68. crew-builder/src/lib/components/JsonViewer.svelte +24 -0
  69. crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
  70. crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
  71. crew-builder/src/lib/components/Toast.svelte +67 -0
  72. crew-builder/src/lib/components/Toolbar.svelte +157 -0
  73. crew-builder/src/lib/components/index.ts +10 -0
  74. crew-builder/src/lib/config.ts +8 -0
  75. crew-builder/src/lib/stores/auth.svelte.ts +228 -0
  76. crew-builder/src/lib/stores/crewStore.ts +369 -0
  77. crew-builder/src/lib/stores/theme.svelte.js +145 -0
  78. crew-builder/src/lib/stores/toast.svelte.ts +69 -0
  79. crew-builder/src/lib/utils/conversation.ts +39 -0
  80. crew-builder/src/lib/utils/markdown.ts +122 -0
  81. crew-builder/src/lib/utils/talkHistory.ts +47 -0
  82. crew-builder/src/routes/+layout.svelte +20 -0
  83. crew-builder/src/routes/+page.svelte +539 -0
  84. crew-builder/src/routes/agents/+page.svelte +247 -0
  85. crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
  86. crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
  87. crew-builder/src/routes/builder/+page.svelte +204 -0
  88. crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
  89. crew-builder/src/routes/crew/ask/+page.ts +1 -0
  90. crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
  91. crew-builder/src/routes/login/+page.svelte +197 -0
  92. crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
  93. crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
  94. crew-builder/static/README.md +1 -0
  95. crew-builder/svelte.config.js +11 -0
  96. crew-builder/tailwind.config.ts +53 -0
  97. crew-builder/tsconfig.json +3 -0
  98. crew-builder/vite.config.ts +10 -0
  99. mcp_servers/calculator_server.py +309 -0
  100. parrot/__init__.py +27 -0
  101. parrot/__pycache__/__init__.cpython-310.pyc +0 -0
  102. parrot/__pycache__/version.cpython-310.pyc +0 -0
  103. parrot/_version.py +34 -0
  104. parrot/a2a/__init__.py +48 -0
  105. parrot/a2a/client.py +658 -0
  106. parrot/a2a/discovery.py +89 -0
  107. parrot/a2a/mixin.py +257 -0
  108. parrot/a2a/models.py +376 -0
  109. parrot/a2a/server.py +770 -0
  110. parrot/agents/__init__.py +29 -0
  111. parrot/bots/__init__.py +12 -0
  112. parrot/bots/a2a_agent.py +19 -0
  113. parrot/bots/abstract.py +3139 -0
  114. parrot/bots/agent.py +1129 -0
  115. parrot/bots/basic.py +9 -0
  116. parrot/bots/chatbot.py +669 -0
  117. parrot/bots/data.py +1618 -0
  118. parrot/bots/database/__init__.py +5 -0
  119. parrot/bots/database/abstract.py +3071 -0
  120. parrot/bots/database/cache.py +286 -0
  121. parrot/bots/database/models.py +468 -0
  122. parrot/bots/database/prompts.py +154 -0
  123. parrot/bots/database/retries.py +98 -0
  124. parrot/bots/database/router.py +269 -0
  125. parrot/bots/database/sql.py +41 -0
  126. parrot/bots/db/__init__.py +6 -0
  127. parrot/bots/db/abstract.py +556 -0
  128. parrot/bots/db/bigquery.py +602 -0
  129. parrot/bots/db/cache.py +85 -0
  130. parrot/bots/db/documentdb.py +668 -0
  131. parrot/bots/db/elastic.py +1014 -0
  132. parrot/bots/db/influx.py +898 -0
  133. parrot/bots/db/mock.py +96 -0
  134. parrot/bots/db/multi.py +783 -0
  135. parrot/bots/db/prompts.py +185 -0
  136. parrot/bots/db/sql.py +1255 -0
  137. parrot/bots/db/tools.py +212 -0
  138. parrot/bots/document.py +680 -0
  139. parrot/bots/hrbot.py +15 -0
  140. parrot/bots/kb.py +170 -0
  141. parrot/bots/mcp.py +36 -0
  142. parrot/bots/orchestration/README.md +463 -0
  143. parrot/bots/orchestration/__init__.py +1 -0
  144. parrot/bots/orchestration/agent.py +155 -0
  145. parrot/bots/orchestration/crew.py +3330 -0
  146. parrot/bots/orchestration/fsm.py +1179 -0
  147. parrot/bots/orchestration/hr.py +434 -0
  148. parrot/bots/orchestration/storage/__init__.py +4 -0
  149. parrot/bots/orchestration/storage/memory.py +100 -0
  150. parrot/bots/orchestration/storage/mixin.py +119 -0
  151. parrot/bots/orchestration/verify.py +202 -0
  152. parrot/bots/product.py +204 -0
  153. parrot/bots/prompts/__init__.py +96 -0
  154. parrot/bots/prompts/agents.py +155 -0
  155. parrot/bots/prompts/data.py +216 -0
  156. parrot/bots/prompts/output_generation.py +8 -0
  157. parrot/bots/scraper/__init__.py +3 -0
  158. parrot/bots/scraper/models.py +122 -0
  159. parrot/bots/scraper/scraper.py +1173 -0
  160. parrot/bots/scraper/templates.py +115 -0
  161. parrot/bots/stores/__init__.py +5 -0
  162. parrot/bots/stores/local.py +172 -0
  163. parrot/bots/webdev.py +81 -0
  164. parrot/cli.py +17 -0
  165. parrot/clients/__init__.py +16 -0
  166. parrot/clients/base.py +1491 -0
  167. parrot/clients/claude.py +1191 -0
  168. parrot/clients/factory.py +129 -0
  169. parrot/clients/google.py +4567 -0
  170. parrot/clients/gpt.py +1975 -0
  171. parrot/clients/grok.py +432 -0
  172. parrot/clients/groq.py +986 -0
  173. parrot/clients/hf.py +582 -0
  174. parrot/clients/models.py +18 -0
  175. parrot/conf.py +395 -0
  176. parrot/embeddings/__init__.py +9 -0
  177. parrot/embeddings/base.py +157 -0
  178. parrot/embeddings/google.py +98 -0
  179. parrot/embeddings/huggingface.py +74 -0
  180. parrot/embeddings/openai.py +84 -0
  181. parrot/embeddings/processor.py +88 -0
  182. parrot/exceptions.c +13868 -0
  183. parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  184. parrot/exceptions.pxd +22 -0
  185. parrot/exceptions.pxi +15 -0
  186. parrot/exceptions.pyx +44 -0
  187. parrot/generators/__init__.py +29 -0
  188. parrot/generators/base.py +200 -0
  189. parrot/generators/html.py +293 -0
  190. parrot/generators/react.py +205 -0
  191. parrot/generators/streamlit.py +203 -0
  192. parrot/generators/template.py +105 -0
  193. parrot/handlers/__init__.py +4 -0
  194. parrot/handlers/agent.py +861 -0
  195. parrot/handlers/agents/__init__.py +1 -0
  196. parrot/handlers/agents/abstract.py +900 -0
  197. parrot/handlers/bots.py +338 -0
  198. parrot/handlers/chat.py +915 -0
  199. parrot/handlers/creation.sql +192 -0
  200. parrot/handlers/crew/ARCHITECTURE.md +362 -0
  201. parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
  202. parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
  203. parrot/handlers/crew/__init__.py +0 -0
  204. parrot/handlers/crew/handler.py +801 -0
  205. parrot/handlers/crew/models.py +229 -0
  206. parrot/handlers/crew/redis_persistence.py +523 -0
  207. parrot/handlers/jobs/__init__.py +10 -0
  208. parrot/handlers/jobs/job.py +384 -0
  209. parrot/handlers/jobs/mixin.py +627 -0
  210. parrot/handlers/jobs/models.py +115 -0
  211. parrot/handlers/jobs/worker.py +31 -0
  212. parrot/handlers/models.py +596 -0
  213. parrot/handlers/o365_auth.py +105 -0
  214. parrot/handlers/stream.py +337 -0
  215. parrot/interfaces/__init__.py +6 -0
  216. parrot/interfaces/aws.py +143 -0
  217. parrot/interfaces/credentials.py +113 -0
  218. parrot/interfaces/database.py +27 -0
  219. parrot/interfaces/google.py +1123 -0
  220. parrot/interfaces/hierarchy.py +1227 -0
  221. parrot/interfaces/http.py +651 -0
  222. parrot/interfaces/images/__init__.py +0 -0
  223. parrot/interfaces/images/plugins/__init__.py +24 -0
  224. parrot/interfaces/images/plugins/abstract.py +58 -0
  225. parrot/interfaces/images/plugins/analisys.py +148 -0
  226. parrot/interfaces/images/plugins/classify.py +150 -0
  227. parrot/interfaces/images/plugins/classifybase.py +182 -0
  228. parrot/interfaces/images/plugins/detect.py +150 -0
  229. parrot/interfaces/images/plugins/exif.py +1103 -0
  230. parrot/interfaces/images/plugins/hash.py +52 -0
  231. parrot/interfaces/images/plugins/vision.py +104 -0
  232. parrot/interfaces/images/plugins/yolo.py +66 -0
  233. parrot/interfaces/images/plugins/zerodetect.py +197 -0
  234. parrot/interfaces/o365.py +978 -0
  235. parrot/interfaces/onedrive.py +822 -0
  236. parrot/interfaces/sharepoint.py +1435 -0
  237. parrot/interfaces/soap.py +257 -0
  238. parrot/loaders/__init__.py +8 -0
  239. parrot/loaders/abstract.py +1131 -0
  240. parrot/loaders/audio.py +199 -0
  241. parrot/loaders/basepdf.py +53 -0
  242. parrot/loaders/basevideo.py +1568 -0
  243. parrot/loaders/csv.py +409 -0
  244. parrot/loaders/docx.py +116 -0
  245. parrot/loaders/epubloader.py +316 -0
  246. parrot/loaders/excel.py +199 -0
  247. parrot/loaders/factory.py +55 -0
  248. parrot/loaders/files/__init__.py +0 -0
  249. parrot/loaders/files/abstract.py +39 -0
  250. parrot/loaders/files/html.py +26 -0
  251. parrot/loaders/files/text.py +63 -0
  252. parrot/loaders/html.py +152 -0
  253. parrot/loaders/markdown.py +442 -0
  254. parrot/loaders/pdf.py +373 -0
  255. parrot/loaders/pdfmark.py +320 -0
  256. parrot/loaders/pdftables.py +506 -0
  257. parrot/loaders/ppt.py +476 -0
  258. parrot/loaders/qa.py +63 -0
  259. parrot/loaders/splitters/__init__.py +10 -0
  260. parrot/loaders/splitters/base.py +138 -0
  261. parrot/loaders/splitters/md.py +228 -0
  262. parrot/loaders/splitters/token.py +143 -0
  263. parrot/loaders/txt.py +26 -0
  264. parrot/loaders/video.py +89 -0
  265. parrot/loaders/videolocal.py +218 -0
  266. parrot/loaders/videounderstanding.py +377 -0
  267. parrot/loaders/vimeo.py +167 -0
  268. parrot/loaders/web.py +599 -0
  269. parrot/loaders/youtube.py +504 -0
  270. parrot/manager/__init__.py +5 -0
  271. parrot/manager/manager.py +1030 -0
  272. parrot/mcp/__init__.py +28 -0
  273. parrot/mcp/adapter.py +105 -0
  274. parrot/mcp/cli.py +174 -0
  275. parrot/mcp/client.py +119 -0
  276. parrot/mcp/config.py +75 -0
  277. parrot/mcp/integration.py +842 -0
  278. parrot/mcp/oauth.py +933 -0
  279. parrot/mcp/server.py +225 -0
  280. parrot/mcp/transports/__init__.py +3 -0
  281. parrot/mcp/transports/base.py +279 -0
  282. parrot/mcp/transports/grpc_session.py +163 -0
  283. parrot/mcp/transports/http.py +312 -0
  284. parrot/mcp/transports/mcp.proto +108 -0
  285. parrot/mcp/transports/quic.py +1082 -0
  286. parrot/mcp/transports/sse.py +330 -0
  287. parrot/mcp/transports/stdio.py +309 -0
  288. parrot/mcp/transports/unix.py +395 -0
  289. parrot/mcp/transports/websocket.py +547 -0
  290. parrot/memory/__init__.py +16 -0
  291. parrot/memory/abstract.py +209 -0
  292. parrot/memory/agent.py +32 -0
  293. parrot/memory/cache.py +175 -0
  294. parrot/memory/core.py +555 -0
  295. parrot/memory/file.py +153 -0
  296. parrot/memory/mem.py +131 -0
  297. parrot/memory/redis.py +613 -0
  298. parrot/models/__init__.py +46 -0
  299. parrot/models/basic.py +118 -0
  300. parrot/models/compliance.py +208 -0
  301. parrot/models/crew.py +395 -0
  302. parrot/models/detections.py +654 -0
  303. parrot/models/generation.py +85 -0
  304. parrot/models/google.py +223 -0
  305. parrot/models/groq.py +23 -0
  306. parrot/models/openai.py +30 -0
  307. parrot/models/outputs.py +285 -0
  308. parrot/models/responses.py +938 -0
  309. parrot/notifications/__init__.py +743 -0
  310. parrot/openapi/__init__.py +3 -0
  311. parrot/openapi/components.yaml +641 -0
  312. parrot/openapi/config.py +322 -0
  313. parrot/outputs/__init__.py +32 -0
  314. parrot/outputs/formats/__init__.py +108 -0
  315. parrot/outputs/formats/altair.py +359 -0
  316. parrot/outputs/formats/application.py +122 -0
  317. parrot/outputs/formats/base.py +351 -0
  318. parrot/outputs/formats/bokeh.py +356 -0
  319. parrot/outputs/formats/card.py +424 -0
  320. parrot/outputs/formats/chart.py +436 -0
  321. parrot/outputs/formats/d3.py +255 -0
  322. parrot/outputs/formats/echarts.py +310 -0
  323. parrot/outputs/formats/generators/__init__.py +0 -0
  324. parrot/outputs/formats/generators/abstract.py +61 -0
  325. parrot/outputs/formats/generators/panel.py +145 -0
  326. parrot/outputs/formats/generators/streamlit.py +86 -0
  327. parrot/outputs/formats/generators/terminal.py +63 -0
  328. parrot/outputs/formats/holoviews.py +310 -0
  329. parrot/outputs/formats/html.py +147 -0
  330. parrot/outputs/formats/jinja2.py +46 -0
  331. parrot/outputs/formats/json.py +87 -0
  332. parrot/outputs/formats/map.py +933 -0
  333. parrot/outputs/formats/markdown.py +172 -0
  334. parrot/outputs/formats/matplotlib.py +237 -0
  335. parrot/outputs/formats/mixins/__init__.py +0 -0
  336. parrot/outputs/formats/mixins/emaps.py +855 -0
  337. parrot/outputs/formats/plotly.py +341 -0
  338. parrot/outputs/formats/seaborn.py +310 -0
  339. parrot/outputs/formats/table.py +397 -0
  340. parrot/outputs/formats/template_report.py +138 -0
  341. parrot/outputs/formats/yaml.py +125 -0
  342. parrot/outputs/formatter.py +152 -0
  343. parrot/outputs/templates/__init__.py +95 -0
  344. parrot/pipelines/__init__.py +0 -0
  345. parrot/pipelines/abstract.py +210 -0
  346. parrot/pipelines/detector.py +124 -0
  347. parrot/pipelines/models.py +90 -0
  348. parrot/pipelines/planogram.py +3002 -0
  349. parrot/pipelines/table.sql +97 -0
  350. parrot/plugins/__init__.py +106 -0
  351. parrot/plugins/importer.py +80 -0
  352. parrot/py.typed +0 -0
  353. parrot/registry/__init__.py +18 -0
  354. parrot/registry/registry.py +594 -0
  355. parrot/scheduler/__init__.py +1189 -0
  356. parrot/scheduler/models.py +60 -0
  357. parrot/security/__init__.py +16 -0
  358. parrot/security/prompt_injection.py +268 -0
  359. parrot/security/security_events.sql +25 -0
  360. parrot/services/__init__.py +1 -0
  361. parrot/services/mcp/__init__.py +8 -0
  362. parrot/services/mcp/config.py +13 -0
  363. parrot/services/mcp/server.py +295 -0
  364. parrot/services/o365_remote_auth.py +235 -0
  365. parrot/stores/__init__.py +7 -0
  366. parrot/stores/abstract.py +352 -0
  367. parrot/stores/arango.py +1090 -0
  368. parrot/stores/bigquery.py +1377 -0
  369. parrot/stores/cache.py +106 -0
  370. parrot/stores/empty.py +10 -0
  371. parrot/stores/faiss_store.py +1157 -0
  372. parrot/stores/kb/__init__.py +9 -0
  373. parrot/stores/kb/abstract.py +68 -0
  374. parrot/stores/kb/cache.py +165 -0
  375. parrot/stores/kb/doc.py +325 -0
  376. parrot/stores/kb/hierarchy.py +346 -0
  377. parrot/stores/kb/local.py +457 -0
  378. parrot/stores/kb/prompt.py +28 -0
  379. parrot/stores/kb/redis.py +659 -0
  380. parrot/stores/kb/store.py +115 -0
  381. parrot/stores/kb/user.py +374 -0
  382. parrot/stores/models.py +59 -0
  383. parrot/stores/pgvector.py +3 -0
  384. parrot/stores/postgres.py +2853 -0
  385. parrot/stores/utils/__init__.py +0 -0
  386. parrot/stores/utils/chunking.py +197 -0
  387. parrot/telemetry/__init__.py +3 -0
  388. parrot/telemetry/mixin.py +111 -0
  389. parrot/template/__init__.py +3 -0
  390. parrot/template/engine.py +259 -0
  391. parrot/tools/__init__.py +23 -0
  392. parrot/tools/abstract.py +644 -0
  393. parrot/tools/agent.py +363 -0
  394. parrot/tools/arangodbsearch.py +537 -0
  395. parrot/tools/arxiv_tool.py +188 -0
  396. parrot/tools/calculator/__init__.py +3 -0
  397. parrot/tools/calculator/operations/__init__.py +38 -0
  398. parrot/tools/calculator/operations/calculus.py +80 -0
  399. parrot/tools/calculator/operations/statistics.py +76 -0
  400. parrot/tools/calculator/tool.py +150 -0
  401. parrot/tools/cloudwatch.py +988 -0
  402. parrot/tools/codeinterpreter/__init__.py +127 -0
  403. parrot/tools/codeinterpreter/executor.py +371 -0
  404. parrot/tools/codeinterpreter/internals.py +473 -0
  405. parrot/tools/codeinterpreter/models.py +643 -0
  406. parrot/tools/codeinterpreter/prompts.py +224 -0
  407. parrot/tools/codeinterpreter/tool.py +664 -0
  408. parrot/tools/company_info/__init__.py +6 -0
  409. parrot/tools/company_info/tool.py +1138 -0
  410. parrot/tools/correlationanalysis.py +437 -0
  411. parrot/tools/database/abstract.py +286 -0
  412. parrot/tools/database/bq.py +115 -0
  413. parrot/tools/database/cache.py +284 -0
  414. parrot/tools/database/models.py +95 -0
  415. parrot/tools/database/pg.py +343 -0
  416. parrot/tools/databasequery.py +1159 -0
  417. parrot/tools/db.py +1800 -0
  418. parrot/tools/ddgo.py +370 -0
  419. parrot/tools/decorators.py +271 -0
  420. parrot/tools/dftohtml.py +282 -0
  421. parrot/tools/document.py +549 -0
  422. parrot/tools/ecs.py +819 -0
  423. parrot/tools/edareport.py +368 -0
  424. parrot/tools/elasticsearch.py +1049 -0
  425. parrot/tools/employees.py +462 -0
  426. parrot/tools/epson/__init__.py +96 -0
  427. parrot/tools/excel.py +683 -0
  428. parrot/tools/file/__init__.py +13 -0
  429. parrot/tools/file/abstract.py +76 -0
  430. parrot/tools/file/gcs.py +378 -0
  431. parrot/tools/file/local.py +284 -0
  432. parrot/tools/file/s3.py +511 -0
  433. parrot/tools/file/tmp.py +309 -0
  434. parrot/tools/file/tool.py +501 -0
  435. parrot/tools/file_reader.py +129 -0
  436. parrot/tools/flowtask/__init__.py +19 -0
  437. parrot/tools/flowtask/tool.py +761 -0
  438. parrot/tools/gittoolkit.py +508 -0
  439. parrot/tools/google/__init__.py +18 -0
  440. parrot/tools/google/base.py +169 -0
  441. parrot/tools/google/tools.py +1251 -0
  442. parrot/tools/googlelocation.py +5 -0
  443. parrot/tools/googleroutes.py +5 -0
  444. parrot/tools/googlesearch.py +5 -0
  445. parrot/tools/googlesitesearch.py +5 -0
  446. parrot/tools/googlevoice.py +2 -0
  447. parrot/tools/gvoice.py +695 -0
  448. parrot/tools/ibisworld/README.md +225 -0
  449. parrot/tools/ibisworld/__init__.py +11 -0
  450. parrot/tools/ibisworld/tool.py +366 -0
  451. parrot/tools/jiratoolkit.py +1718 -0
  452. parrot/tools/manager.py +1098 -0
  453. parrot/tools/math.py +152 -0
  454. parrot/tools/metadata.py +476 -0
  455. parrot/tools/msteams.py +1621 -0
  456. parrot/tools/msword.py +635 -0
  457. parrot/tools/multidb.py +580 -0
  458. parrot/tools/multistoresearch.py +369 -0
  459. parrot/tools/networkninja.py +167 -0
  460. parrot/tools/nextstop/__init__.py +4 -0
  461. parrot/tools/nextstop/base.py +286 -0
  462. parrot/tools/nextstop/employee.py +733 -0
  463. parrot/tools/nextstop/store.py +462 -0
  464. parrot/tools/notification.py +435 -0
  465. parrot/tools/o365/__init__.py +42 -0
  466. parrot/tools/o365/base.py +295 -0
  467. parrot/tools/o365/bundle.py +522 -0
  468. parrot/tools/o365/events.py +554 -0
  469. parrot/tools/o365/mail.py +992 -0
  470. parrot/tools/o365/onedrive.py +497 -0
  471. parrot/tools/o365/sharepoint.py +641 -0
  472. parrot/tools/openapi_toolkit.py +904 -0
  473. parrot/tools/openweather.py +527 -0
  474. parrot/tools/pdfprint.py +1001 -0
  475. parrot/tools/powerbi.py +518 -0
  476. parrot/tools/powerpoint.py +1113 -0
  477. parrot/tools/pricestool.py +146 -0
  478. parrot/tools/products/__init__.py +246 -0
  479. parrot/tools/prophet_tool.py +171 -0
  480. parrot/tools/pythonpandas.py +630 -0
  481. parrot/tools/pythonrepl.py +910 -0
  482. parrot/tools/qsource.py +436 -0
  483. parrot/tools/querytoolkit.py +395 -0
  484. parrot/tools/quickeda.py +827 -0
  485. parrot/tools/resttool.py +553 -0
  486. parrot/tools/retail/__init__.py +0 -0
  487. parrot/tools/retail/bby.py +528 -0
  488. parrot/tools/sandboxtool.py +703 -0
  489. parrot/tools/sassie/__init__.py +352 -0
  490. parrot/tools/scraping/__init__.py +7 -0
  491. parrot/tools/scraping/docs/select.md +466 -0
  492. parrot/tools/scraping/documentation.md +1278 -0
  493. parrot/tools/scraping/driver.py +436 -0
  494. parrot/tools/scraping/models.py +576 -0
  495. parrot/tools/scraping/options.py +85 -0
  496. parrot/tools/scraping/orchestrator.py +517 -0
  497. parrot/tools/scraping/readme.md +740 -0
  498. parrot/tools/scraping/tool.py +3115 -0
  499. parrot/tools/seasonaldetection.py +642 -0
  500. parrot/tools/shell_tool/__init__.py +5 -0
  501. parrot/tools/shell_tool/actions.py +408 -0
  502. parrot/tools/shell_tool/engine.py +155 -0
  503. parrot/tools/shell_tool/models.py +322 -0
  504. parrot/tools/shell_tool/tool.py +442 -0
  505. parrot/tools/site_search.py +214 -0
  506. parrot/tools/textfile.py +418 -0
  507. parrot/tools/think.py +378 -0
  508. parrot/tools/toolkit.py +298 -0
  509. parrot/tools/webapp_tool.py +187 -0
  510. parrot/tools/whatif.py +1279 -0
  511. parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
  512. parrot/tools/workday/__init__.py +6 -0
  513. parrot/tools/workday/models.py +1389 -0
  514. parrot/tools/workday/tool.py +1293 -0
  515. parrot/tools/yfinance_tool.py +306 -0
  516. parrot/tools/zipcode.py +217 -0
  517. parrot/utils/__init__.py +2 -0
  518. parrot/utils/helpers.py +73 -0
  519. parrot/utils/parsers/__init__.py +5 -0
  520. parrot/utils/parsers/toml.c +12078 -0
  521. parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  522. parrot/utils/parsers/toml.pyx +21 -0
  523. parrot/utils/toml.py +11 -0
  524. parrot/utils/types.cpp +20936 -0
  525. parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
  526. parrot/utils/types.pyx +213 -0
  527. parrot/utils/uv.py +11 -0
  528. parrot/version.py +10 -0
  529. parrot/yaml-rs/Cargo.lock +350 -0
  530. parrot/yaml-rs/Cargo.toml +19 -0
  531. parrot/yaml-rs/pyproject.toml +19 -0
  532. parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
  533. parrot/yaml-rs/src/lib.rs +222 -0
  534. requirements/docker-compose.yml +24 -0
  535. requirements/requirements-dev.txt +21 -0
@@ -0,0 +1,547 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+ import uuid
5
+ import contextlib
6
+ from typing import Dict, Any, Optional
7
+ from dataclasses import dataclass
8
+ from aiohttp import web, WSMsgType, ClientSession, ClientWebSocketResponse
9
+ import aiohttp
10
+
11
+ from parrot.mcp.config import MCPServerConfig
12
+ from parrot.mcp.transports.base import MCPServerBase
13
+ from parrot.mcp.oauth import OAuthRoutesMixin
14
+ from parrot.mcp.client import MCPClientConfig, MCPConnectionError
15
+
16
+
17
+ @dataclass
18
+ class WebSocketConnection:
19
+ """Represents an active WebSocket connection with session info."""
20
+ websocket: web.WebSocketResponse
21
+ session_id: str
22
+ message_queue: asyncio.Queue
23
+ last_ping: float = 0.0
24
+
25
+
26
+ class WebSocketMCPServer(OAuthRoutesMixin, MCPServerBase):
27
+ """MCP server using WebSocket transport for bidirectional communication.
28
+
29
+ Implements the WebSocket transport as proposed in SEP-1288:
30
+ - Session-based connection management (single connection per session)
31
+ - Bidirectional JSON-RPC communication
32
+ - Server-initiated notifications support
33
+ - OAuth authentication via query params or websocket subprotocol
34
+ - Automatic ping/pong keep-alive
35
+ """
36
+
37
+ def __init__(self, config: MCPServerConfig, parent_app: Optional[web.Application] = None):
38
+ super().__init__(config)
39
+ self.app = parent_app or web.Application()
40
+ self.base_path = config.base_path or "/mcp"
41
+ # WebSocket endpoint is at /mcp/ws (base_path + /ws)
42
+ self.ws_path = f"{self.base_path.rstrip('/')}/ws"
43
+ self._init_oauth_support()
44
+ self.runner = None
45
+ self.site = None
46
+ self.sessions: Dict[str, WebSocketConnection] = {}
47
+ self._external_setup = parent_app is not None
48
+
49
+ # Register routes
50
+ self.app.router.add_get(self.ws_path, self._handle_websocket)
51
+ self.app.router.add_get("/", self._handle_info, allow_head=True)
52
+
53
+ if self.oauth_server:
54
+ self.oauth_server.register_routes(self.app)
55
+
56
+ async def start(self):
57
+ """Start the WebSocket MCP server."""
58
+ if self._external_setup:
59
+ self.logger.info("WebSocket MCP server using existing aiohttp application")
60
+ return
61
+
62
+ self.logger.info(
63
+ f"Starting WebSocket MCP server on {self.config.host}:{self.config.port}"
64
+ )
65
+
66
+ self.runner = web.AppRunner(self.app)
67
+ await self.runner.setup()
68
+
69
+ self.site = web.TCPSite(
70
+ self.runner,
71
+ self.config.host,
72
+ self.config.port
73
+ )
74
+ await self.site.start()
75
+
76
+ self.logger.info(
77
+ f"WebSocket MCP server started at ws://{self.config.host}:{self.config.port}{self.ws_path}"
78
+ )
79
+
80
+ async def stop(self):
81
+ """Stop the WebSocket server."""
82
+ # Close all active WebSocket connections
83
+ for session_id, conn in list(self.sessions.items()):
84
+ try:
85
+ await conn.websocket.close()
86
+ except Exception as e:
87
+ self.logger.warning(f"Error closing WebSocket for session {session_id}: {e}")
88
+ self.sessions.pop(session_id, None)
89
+
90
+ if not self._external_setup:
91
+ if self.site:
92
+ await self.site.stop()
93
+ if self.runner:
94
+ await self.runner.cleanup()
95
+
96
+ self.logger.info("WebSocket MCP server stopped")
97
+
98
+ async def _handle_info(self, request: web.Request) -> web.Response:
99
+ """Return server info endpoint."""
100
+ auth_response = self._authenticate_request(request)
101
+ if auth_response:
102
+ return auth_response
103
+
104
+ info = {
105
+ "name": self.config.name,
106
+ "version": self.config.version,
107
+ "description": self.config.description,
108
+ "transport": "websocket",
109
+ "endpoint": self.ws_path,
110
+ "tools": list(self.tools.keys()),
111
+ "tool_count": len(self.tools)
112
+ }
113
+ return web.json_response(info)
114
+
115
+ def _get_session_id(self, request: web.Request) -> str:
116
+ """Extract session ID from request headers or query params, or generate new one."""
117
+ session_id = (
118
+ request.headers.get("X-MCP-Session-Id") or
119
+ request.query.get("session_id") or
120
+ str(uuid.uuid4())
121
+ )
122
+ return session_id
123
+
124
+ async def _handle_websocket(self, request: web.Request) -> web.WebSocketResponse:
125
+ """Handle WebSocket connection upgrade and message loop."""
126
+ # OAuth authentication check
127
+ auth_response = self._authenticate_request(request)
128
+ if auth_response:
129
+ return auth_response
130
+
131
+ session_id = self._get_session_id(request)
132
+
133
+ # Close existing connection for this session (SEP-1288: single connection per session)
134
+ if session_id in self.sessions:
135
+ old_conn = self.sessions[session_id]
136
+ self.logger.info(f"Closing previous WebSocket connection for session {session_id}")
137
+ try:
138
+ await old_conn.websocket.close(code=1000, message=b"New connection established")
139
+ except Exception:
140
+ pass
141
+
142
+ # Upgrade to WebSocket
143
+ ws = web.WebSocketResponse(heartbeat=30.0)
144
+ await ws.prepare(request)
145
+
146
+ # Create connection object
147
+ connection = WebSocketConnection(
148
+ websocket=ws,
149
+ session_id=session_id,
150
+ message_queue=asyncio.Queue()
151
+ )
152
+ self.sessions[session_id] = connection
153
+
154
+ self.logger.info(f"WebSocket client connected: {session_id}")
155
+
156
+ # Send connection established message
157
+ await self._send_message(ws, {
158
+ "jsonrpc": "2.0",
159
+ "method": "notifications/connection",
160
+ "params": {
161
+ "type": "connected",
162
+ "sessionId": session_id
163
+ }
164
+ })
165
+
166
+ try:
167
+ # Message handling loop
168
+ async for msg in ws:
169
+ if msg.type == WSMsgType.TEXT:
170
+ await self._handle_message(session_id, msg.data)
171
+ elif msg.type == WSMsgType.ERROR:
172
+ self.logger.error(f"WebSocket error for {session_id}: {ws.exception()}")
173
+ break
174
+ elif msg.type == WSMsgType.CLOSE:
175
+ self.logger.info(f"WebSocket closed by client: {session_id}")
176
+ break
177
+
178
+ except asyncio.CancelledError:
179
+ self.logger.info(f"WebSocket connection cancelled: {session_id}")
180
+ except Exception as e:
181
+ self.logger.error(f"Error in WebSocket handler for {session_id}: {e}")
182
+ finally:
183
+ # Cleanup
184
+ self.sessions.pop(session_id, None)
185
+ if not ws.closed:
186
+ await ws.close()
187
+ self.logger.info(f"WebSocket client disconnected: {session_id}")
188
+
189
+ return ws
190
+
191
+ async def _handle_message(self, session_id: str, message_data: str):
192
+ """Handle incoming JSON-RPC message from WebSocket client."""
193
+ try:
194
+ data = json.loads(message_data)
195
+ method = data.get("method")
196
+ params = data.get("params", {})
197
+ request_id = data.get("id")
198
+
199
+ self.logger.debug(f"WebSocket message from {session_id}: {method}")
200
+
201
+ # Handle JSON-RPC request
202
+ try:
203
+ if method == "initialize":
204
+ result = await self.handle_initialize(params)
205
+ elif method == "tools/list":
206
+ result = await self.handle_tools_list(params)
207
+ elif method == "tools/call":
208
+ result = await self.handle_tools_call(params)
209
+ elif method == "notifications/initialized":
210
+ # Client initialization complete notification (no response needed)
211
+ self.logger.info(f"Client {session_id} initialization complete")
212
+ return
213
+ else:
214
+ raise RuntimeError(f"Unknown method: {method}")
215
+
216
+ # Send success response
217
+ response = {
218
+ "jsonrpc": "2.0",
219
+ "id": request_id,
220
+ "result": result
221
+ }
222
+
223
+ except Exception as e:
224
+ self.logger.error(f"Error handling {method} for {session_id}: {e}")
225
+ response = {
226
+ "jsonrpc": "2.0",
227
+ "id": request_id,
228
+ "error": {
229
+ "code": -32603,
230
+ "message": str(e)
231
+ }
232
+ }
233
+
234
+ # Send response back to client
235
+ connection = self.sessions.get(session_id)
236
+ if connection:
237
+ await self._send_message(connection.websocket, response)
238
+
239
+ except json.JSONDecodeError as e:
240
+ self.logger.error(f"Invalid JSON from {session_id}: {e}")
241
+ # Send parse error
242
+ connection = self.sessions.get(session_id)
243
+ if connection:
244
+ await self._send_message(connection.websocket, {
245
+ "jsonrpc": "2.0",
246
+ "id": None,
247
+ "error": {
248
+ "code": -32700,
249
+ "message": "Parse error"
250
+ }
251
+ })
252
+
253
+ async def _send_message(self, ws: web.WebSocketResponse, message: Dict[str, Any]):
254
+ """Send JSON-RPC message to WebSocket client."""
255
+ try:
256
+ await ws.send_str(json.dumps(message))
257
+ except Exception as e:
258
+ self.logger.error(f"Failed to send WebSocket message: {e}")
259
+
260
+ async def send_notification(self, session_id: str, method: str, params: Dict[str, Any]):
261
+ """Send server-initiated notification to client.
262
+
263
+ This enables server-to-client notifications like:
264
+ - notifications/resources/updated
265
+ - notifications/tools/list_changed
266
+ """
267
+ connection = self.sessions.get(session_id)
268
+ if not connection:
269
+ self.logger.warning(f"Cannot send notification: session {session_id} not found")
270
+ return
271
+
272
+ notification = {
273
+ "jsonrpc": "2.0",
274
+ "method": method,
275
+ "params": params
276
+ }
277
+ await self._send_message(connection.websocket, notification)
278
+
279
+
280
+ class WebSocketMCPSession:
281
+ """MCP client session for WebSocket transport.
282
+
283
+ Implements the client side of SEP-1288 WebSocket transport:
284
+ - Connects to WebSocket MCP server
285
+ - Manages session ID persistence
286
+ - Handles request/response matching
287
+ - Supports automatic reconnection
288
+ - Receives server-initiated notifications
289
+ """
290
+
291
+ def __init__(self, config: MCPClientConfig, logger):
292
+ self.config = config
293
+ self.logger = logger
294
+ self._request_id = 0
295
+ self._session: Optional[ClientSession] = None
296
+ self._websocket: Optional[ClientWebSocketResponse] = None
297
+ self._response_futures: Dict[int, asyncio.Future] = {}
298
+ self._session_id: Optional[str] = None
299
+ self._connected = False
300
+ self._receiver_task: Optional[asyncio.Task] = None
301
+ self._reconnect_attempts = 0
302
+ self._max_reconnect_attempts = 5
303
+
304
+ async def connect(self):
305
+ """Connect to WebSocket MCP server."""
306
+ if self._connected:
307
+ return
308
+
309
+ try:
310
+ # Create aiohttp session
311
+ self._session = ClientSession()
312
+
313
+ # Build WebSocket URL
314
+ url = self.config.url
315
+ if not url.startswith("ws://") and not url.startswith("wss://"):
316
+ # Convert http(s) to ws(s)
317
+ url = url.replace("http://", "ws://").replace("https://", "wss://")
318
+
319
+ # Add session ID if we have one (for reconnection)
320
+ params = {}
321
+ if self._session_id:
322
+ params["session_id"] = self._session_id
323
+
324
+ # Prepare headers
325
+ headers = dict(self.config.headers or {})
326
+
327
+ # Add authentication
328
+ if self.config.auth_type == "bearer" and self.config.auth_config:
329
+ token = self.config.auth_config.get("token")
330
+ if token:
331
+ headers["Authorization"] = f"Bearer {token}"
332
+ elif self.config.auth_type == "api_key" and self.config.auth_config:
333
+ api_key = self.config.auth_config.get("api_key")
334
+ header_name = self.config.auth_config.get("header_name", "X-API-Key")
335
+ if api_key:
336
+ headers[header_name] = api_key
337
+
338
+ # Connect to WebSocket
339
+ self._websocket = await self._session.ws_connect(
340
+ url,
341
+ params=params,
342
+ headers=headers
343
+ )
344
+
345
+ self.logger.info(f"Connected to WebSocket MCP server: {url}")
346
+
347
+ # Mark as connected BEFORE starting receiver and initialization
348
+ self._connected = True
349
+
350
+ # Start background receiver task
351
+ self._receiver_task = asyncio.create_task(self._receive_messages())
352
+
353
+ # Wait a moment for receiver to be ready
354
+ await asyncio.sleep(0.1)
355
+
356
+ # Initialize MCP session
357
+ await self._initialize_session()
358
+
359
+ self._reconnect_attempts = 0
360
+
361
+ except Exception as e:
362
+ self.logger.error(f"Failed to connect to WebSocket MCP server: {e}")
363
+ self._connected = False
364
+ await self.disconnect()
365
+ raise MCPConnectionError(f"WebSocket connection failed: {e}")
366
+
367
+ async def _receive_messages(self):
368
+ """Background task to receive messages from server."""
369
+ try:
370
+ async for msg in self._websocket:
371
+ if msg.type == WSMsgType.TEXT:
372
+ await self._handle_message(msg.data)
373
+ elif msg.type == WSMsgType.ERROR:
374
+ self.logger.error(f"WebSocket error: {self._websocket.exception()}")
375
+ break
376
+ elif msg.type == WSMsgType.CLOSE:
377
+ self.logger.info("WebSocket closed by server")
378
+ break
379
+ except asyncio.CancelledError:
380
+ self.logger.debug("Message receiver task cancelled")
381
+ except Exception as e:
382
+ self.logger.error(f"Error in message receiver: {e}")
383
+ finally:
384
+ self._connected = False
385
+
386
+ async def _handle_message(self, message_data: str):
387
+ """Handle incoming message from server."""
388
+ try:
389
+ data = json.loads(message_data)
390
+
391
+ # Check if this is a response to a request
392
+ if "id" in data and data["id"] is not None:
393
+ request_id = data["id"]
394
+ if request_id in self._response_futures:
395
+ future = self._response_futures.pop(request_id)
396
+ if "error" in data:
397
+ future.set_exception(
398
+ RuntimeError(f"MCP error: {data['error']['message']}")
399
+ )
400
+ else:
401
+ future.set_result(data.get("result"))
402
+
403
+ # Handle notifications from server
404
+ elif "method" in data:
405
+ method = data["method"]
406
+ params = data.get("params", {})
407
+
408
+ if method == "notifications/connection":
409
+ # Extract session ID from connection notification
410
+ self._session_id = params.get("sessionId")
411
+ self.logger.info(f"Session ID: {self._session_id}")
412
+ else:
413
+ self.logger.info(f"Server notification: {method}")
414
+ # Could add notification handlers here
415
+
416
+ except json.JSONDecodeError as e:
417
+ self.logger.error(f"Invalid JSON from server: {e}")
418
+ except Exception as e:
419
+ self.logger.error(f"Error handling message: {e}")
420
+
421
+ async def _initialize_session(self):
422
+ """Initialize MCP session over WebSocket."""
423
+ init_result = await self._send_request("initialize", {
424
+ "protocolVersion": "2024-11-05",
425
+ "capabilities": {},
426
+ "clientInfo": {
427
+ "name": "ai-parrot-websocket-client",
428
+ "version": "1.0"
429
+ }
430
+ })
431
+
432
+ self.logger.info(f"MCP session initialized: {init_result.get('serverInfo', {}).get('name', 'unknown')}")
433
+
434
+ # Send initialized notification
435
+ await self._send_notification("notifications/initialized", {})
436
+
437
+ async def _send_request(self, method: str, params: dict = None) -> Any:
438
+ """Send JSON-RPC request and wait for response."""
439
+ if not self._connected or not self._websocket:
440
+ raise MCPConnectionError("Not connected to WebSocket server")
441
+
442
+ request_id = self._get_next_id()
443
+ request = {
444
+ "jsonrpc": "2.0",
445
+ "id": request_id,
446
+ "method": method,
447
+ "params": params or {}
448
+ }
449
+
450
+ # Create future for response
451
+ future = asyncio.Future()
452
+ self._response_futures[request_id] = future
453
+
454
+ try:
455
+ # Send request
456
+ await self._websocket.send_str(json.dumps(request))
457
+
458
+ # Wait for response (with timeout)
459
+ result = await asyncio.wait_for(future, timeout=30.0)
460
+ return result
461
+
462
+ except asyncio.TimeoutError:
463
+ self._response_futures.pop(request_id, None)
464
+ raise MCPConnectionError(f"Request timeout for method: {method}")
465
+ except Exception as e:
466
+ self._response_futures.pop(request_id, None)
467
+ raise
468
+
469
+ async def _send_notification(self, method: str, params: dict = None):
470
+ """Send JSON-RPC notification (no response expected)."""
471
+ if not self._connected or not self._websocket:
472
+ raise MCPConnectionError("Not connected to WebSocket server")
473
+
474
+ notification = {
475
+ "jsonrpc": "2.0",
476
+ "method": method,
477
+ "params": params or {}
478
+ }
479
+
480
+ await self._websocket.send_str(json.dumps(notification))
481
+
482
+ def _get_next_id(self) -> int:
483
+ """Get next request ID."""
484
+ self._request_id += 1
485
+ return self._request_id
486
+
487
+ async def list_tools(self):
488
+ """List available tools from MCP server."""
489
+ result = await self._send_request("tools/list", {})
490
+
491
+ # Convert to compatible format
492
+ tools = []
493
+ for tool_dict in result.get("tools", []):
494
+ # Create simple object with attributes
495
+ tool_obj = type('Tool', (), tool_dict)()
496
+ tools.append(tool_obj)
497
+
498
+ return tools
499
+
500
+ async def call_tool(self, tool_name: str, arguments: dict):
501
+ """Call a tool on the MCP server."""
502
+ result = await self._send_request("tools/call", {
503
+ "name": tool_name,
504
+ "arguments": arguments
505
+ })
506
+
507
+ # Convert result to compatible format matching other transports
508
+ # MCP returns: {"content": [{"type": "text", "text": "..."}], "isError": false}
509
+ if isinstance(result, dict):
510
+ content_list = result.get("content", [])
511
+ # Convert to object with content attribute containing text items
512
+ result_obj = type('ToolResult', (), {
513
+ 'content': [
514
+ type('ContentItem', (), item)()
515
+ for item in content_list
516
+ ],
517
+ 'isError': result.get("isError", False)
518
+ })()
519
+ return result_obj
520
+
521
+ return result
522
+
523
+ async def disconnect(self):
524
+ """Disconnect from WebSocket server."""
525
+ self._connected = False
526
+
527
+ # Cancel receiver task
528
+ if self._receiver_task and not self._receiver_task.done():
529
+ self._receiver_task.cancel()
530
+ with contextlib.suppress(asyncio.CancelledError):
531
+ await self._receiver_task
532
+
533
+ # Close WebSocket
534
+ if self._websocket and not self._websocket.closed:
535
+ await self._websocket.close()
536
+
537
+ # Close session
538
+ if self._session and not self._session.closed:
539
+ await self._session.close()
540
+
541
+ # Clear futures
542
+ for future in self._response_futures.values():
543
+ if not future.done():
544
+ future.cancel()
545
+ self._response_futures.clear()
546
+
547
+ self.logger.info("Disconnected from WebSocket MCP server")
@@ -0,0 +1,16 @@
1
+ from .abstract import ConversationMemory, ConversationHistory, ConversationTurn
2
+ from .mem import InMemoryConversation
3
+ from .redis import RedisConversation
4
+ from .file import FileConversationMemory
5
+ from .agent import AgentMemory
6
+
7
+
8
+ __all__ = [
9
+ "ConversationMemory",
10
+ "ConversationHistory",
11
+ "ConversationTurn",
12
+ "InMemoryConversation",
13
+ "FileConversationMemory",
14
+ "RedisConversation",
15
+ "AgentMemory",
16
+ ]