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
parrot/tools/ecs.py ADDED
@@ -0,0 +1,819 @@
1
+ """
2
+ AWS ECS and EKS Tool for AI-Parrot
3
+
4
+ Provides helpers to inspect Fargate tasks, ECS services, and EKS clusters.
5
+ """
6
+ from __future__ import annotations
7
+ from typing import Any, Dict, List, Optional
8
+ from datetime import datetime, timedelta, timezone
9
+ import re
10
+ import base64
11
+ import ssl
12
+ from enum import Enum
13
+ from botocore.exceptions import ClientError
14
+ from botocore import session as boto_session
15
+ from botocore.signers import RequestSigner
16
+ from pydantic import Field, field_validator
17
+ import aiohttp
18
+ from ..interfaces.aws import AWSInterface
19
+ from .abstract import AbstractTool, AbstractToolArgsSchema, ToolResult
20
+
21
+
22
+ class ECSOperation(str, Enum):
23
+ """Supported ECS/EKS operations."""
24
+
25
+ LIST_ECS_CLUSTERS = "list_ecs_clusters"
26
+ LIST_ECS_SERVICES = "list_ecs_services"
27
+ LIST_SERVICES = "list_services"
28
+ LIST_ECS_TASKS = "list_ecs_tasks"
29
+ LIST_TASKS = "list_tasks"
30
+ DESCRIBE_ECS_TASKS = "describe_ecs_tasks"
31
+ DESCRIBE_TASKS = "describe_tasks"
32
+ GET_FARGATE_TASK_LOGS = "get_fargate_task_logs"
33
+ GET_FARGATE_LOGS = "get_fargate_logs"
34
+ DESCRIBE_EKS_CLUSTER = "describe_eks_cluster"
35
+ GET_EKS_CLUSTER_INFO = "get_eks_cluster_info"
36
+ LIST_EKS_CLUSTERS = "list_eks_clusters"
37
+ LIST_EKS_NODEGROUPS = "list_eks_nodegroups"
38
+ DESCRIBE_EKS_NODEGROUP = "describe_eks_nodegroup"
39
+ LIST_EKS_FARGATE_PROFILES = "list_eks_fargate_profiles"
40
+ DESCRIBE_EKS_FARGATE_PROFILE = "describe_eks_fargate_profile"
41
+ LIST_EKS_PODS = "list_eks_pods"
42
+ LIST_EC2_INSTANCES = "list_ec2_instances"
43
+
44
+
45
+ class ECSToolArgs(AbstractToolArgsSchema):
46
+ """Arguments schema for ECS/EKS operations."""
47
+
48
+ operation: ECSOperation = Field(
49
+ ..., description="Operation to perform for ECS/Fargate or EKS"
50
+ )
51
+
52
+ cluster_name: Optional[str] = Field(
53
+ None, description="ECS or EKS cluster name"
54
+ )
55
+ service_name: Optional[str] = Field(
56
+ None, description="ECS service name"
57
+ )
58
+ task_arns: Optional[List[str]] = Field(
59
+ None, description="Specific task ARNs to describe"
60
+ )
61
+ launch_type: Optional[str] = Field(
62
+ None, description="Filter tasks by launch type (e.g., 'FARGATE')"
63
+ )
64
+ desired_status: Optional[str] = Field(
65
+ None, description="Filter tasks by desired status (e.g., 'RUNNING')"
66
+ )
67
+ log_group_name: Optional[str] = Field(
68
+ None, description="CloudWatch log group used by Fargate tasks"
69
+ )
70
+ log_stream_prefix: Optional[str] = Field(
71
+ None, description="Prefix for CloudWatch log streams"
72
+ )
73
+ start_time: Optional[str] = Field(
74
+ None,
75
+ description=(
76
+ "Start time for log retrieval (ISO format or relative like '-1h', '-24h')."
77
+ ),
78
+ )
79
+ limit: Optional[int] = Field(
80
+ 100, description="Maximum number of log events to return"
81
+ )
82
+ eks_nodegroup: Optional[str] = Field(
83
+ None, description="EKS nodegroup name to describe"
84
+ )
85
+ eks_fargate_profile: Optional[str] = Field(
86
+ None, description="EKS Fargate profile name to describe"
87
+ )
88
+ namespace: Optional[str] = Field(
89
+ None, description="Kubernetes namespace to filter pods (default: all namespaces)"
90
+ )
91
+ instance_state: Optional[str] = Field(
92
+ None, description="Filter EC2 instances by state (e.g., 'running', 'stopped', 'terminated')"
93
+ )
94
+ instance_ids: Optional[List[str]] = Field(
95
+ None, description="Specific EC2 instance IDs to describe"
96
+ )
97
+
98
+ @field_validator("start_time", mode="before")
99
+ @classmethod
100
+ def validate_start_time(cls, value):
101
+ if value is None or value == "now":
102
+ return value
103
+ return value
104
+
105
+
106
+ class ECSTool(AbstractTool):
107
+ """
108
+ Tool for inspecting AWS ECS/Fargate tasks, EKS Kubernetes clusters, and EC2 instances.
109
+
110
+ Capabilities include:
111
+ - Listing ECS clusters, services, and tasks
112
+ - Describing ECS tasks (useful for Fargate workloads)
113
+ - Fetching Fargate task logs from CloudWatch
114
+ - Inspecting EKS cluster, nodegroup, and Fargate profile metadata
115
+ - Listing Kubernetes pods in EKS clusters
116
+ - Listing and describing EC2 instances
117
+ """
118
+
119
+ name: str = "aws_ecs_eks_tool"
120
+ description: str = "Inspect AWS ECS/Fargate tasks, EKS Kubernetes clusters, and EC2 instances"
121
+ args_schema: type[AbstractToolArgsSchema] = ECSToolArgs
122
+
123
+ def __init__(self, aws_id: str = "default", region_name: Optional[str] = None, **kwargs):
124
+ super().__init__()
125
+ self.aws = AWSInterface(aws_id=aws_id, region_name=region_name, **kwargs)
126
+
127
+ def _parse_time(self, value: Optional[str]) -> Optional[datetime]:
128
+ if value is None or value == "now":
129
+ return datetime.utc(tz=timezone.utc)
130
+
131
+ try:
132
+ return datetime.fromisoformat(value.replace("Z", "+00:00"))
133
+ except (ValueError, AttributeError):
134
+ pass
135
+
136
+ if value.startswith("-"):
137
+ raw = value[1:]
138
+ match = re.match(r"(\d+)([smhd])", raw)
139
+ if not match:
140
+ raise ValueError(f"Invalid time format: {value}")
141
+
142
+ amount, unit = match.groups()
143
+ amount = int(amount)
144
+ if unit == "s":
145
+ delta = timedelta(seconds=amount)
146
+ elif unit == "m":
147
+ delta = timedelta(minutes=amount)
148
+ elif unit == "h":
149
+ delta = timedelta(hours=amount)
150
+ elif unit == "d":
151
+ delta = timedelta(days=amount)
152
+ else:
153
+ raise ValueError(f"Unsupported time unit: {unit}")
154
+
155
+ return datetime.now(timezone.utc) - delta
156
+
157
+ raise ValueError(f"Invalid time format: {value}")
158
+
159
+ async def _list_ecs_clusters(self) -> List[str]:
160
+ async with self.aws.client("ecs") as ecs:
161
+ response = await ecs.list_clusters()
162
+ return response.get("clusterArns", [])
163
+
164
+ async def _list_services(self, cluster: str) -> List[str]:
165
+ async with self.aws.client("ecs") as ecs:
166
+ response = await ecs.list_services(cluster=cluster)
167
+ return response.get("serviceArns", [])
168
+
169
+ async def _list_tasks(
170
+ self,
171
+ cluster: str,
172
+ service_name: Optional[str] = None,
173
+ desired_status: Optional[str] = None,
174
+ launch_type: Optional[str] = None,
175
+ ) -> List[str]:
176
+ params: Dict[str, Any] = {"cluster": cluster}
177
+ if service_name:
178
+ params["serviceName"] = service_name
179
+ if desired_status:
180
+ params["desiredStatus"] = desired_status
181
+ if launch_type:
182
+ params["launchType"] = launch_type
183
+
184
+ async with self.aws.client("ecs") as ecs:
185
+ response = await ecs.list_tasks(**params)
186
+ return response.get("taskArns", [])
187
+
188
+ async def _describe_tasks(self, cluster: str, task_arns: List[str]) -> List[Dict[str, Any]]:
189
+ async with self.aws.client("ecs") as ecs:
190
+ response = await ecs.describe_tasks(cluster=cluster, tasks=task_arns)
191
+ return response.get("tasks", [])
192
+
193
+ async def _get_fargate_logs(
194
+ self,
195
+ log_group_name: str,
196
+ log_stream_prefix: Optional[str] = None,
197
+ start_time: Optional[datetime] = None,
198
+ limit: int = 100,
199
+ ) -> List[Dict[str, Any]]:
200
+ params: Dict[str, Any] = {
201
+ "logGroupName": log_group_name,
202
+ "limit": limit,
203
+ }
204
+ if log_stream_prefix:
205
+ params["logStreamNamePrefix"] = log_stream_prefix
206
+ if start_time:
207
+ params["startTime"] = int(start_time.timestamp() * 1000)
208
+
209
+ async with self.aws.client("logs") as logs:
210
+ response = await logs.filter_log_events(**params)
211
+ return [
212
+ {
213
+ "timestamp": datetime.fromtimestamp(event["timestamp"] / 1000).isoformat(),
214
+ "message": event.get("message"),
215
+ "log_stream": event.get("logStreamName"),
216
+ }
217
+ for event in response.get("events", [])
218
+ ]
219
+
220
+ async def _describe_eks_cluster(self, cluster_name: str) -> Dict[str, Any]:
221
+ async with self.aws.client("eks") as eks:
222
+ response = await eks.describe_cluster(name=cluster_name)
223
+ cluster = response.get("cluster", {})
224
+ return {
225
+ "name": cluster.get("name"),
226
+ "status": cluster.get("status"),
227
+ "version": cluster.get("version"),
228
+ "endpoint": cluster.get("endpoint"),
229
+ "arn": cluster.get("arn"),
230
+ "created_at": cluster.get("createdAt").isoformat()
231
+ if cluster.get("createdAt")
232
+ else None,
233
+ "role_arn": cluster.get("roleArn"),
234
+ "platform_version": cluster.get("platformVersion"),
235
+ "kubernetes_network_config": cluster.get("kubernetesNetworkConfig"),
236
+ "logging": cluster.get("logging"),
237
+ "resources_vpc_config": cluster.get("resourcesVpcConfig"),
238
+ }
239
+
240
+ async def _get_eks_cluster_info(self, cluster_name: str) -> Dict[str, Any]:
241
+ """Backward-compatible alias for describing an EKS cluster."""
242
+ return await self._describe_eks_cluster(cluster_name)
243
+
244
+ async def _list_eks_clusters(self) -> List[str]:
245
+ async with self.aws.client("eks") as eks:
246
+ response = await eks.list_clusters()
247
+ return response.get("clusters", [])
248
+
249
+ async def list_eks_clusters(self) -> List[str]:
250
+ """Public helper for listing available EKS clusters."""
251
+
252
+ return await self._list_eks_clusters()
253
+
254
+ async def _list_eks_nodegroups(self, cluster_name: str) -> List[str]:
255
+ async with self.aws.client("eks") as eks:
256
+ response = await eks.list_nodegroups(clusterName=cluster_name)
257
+ return response.get("nodegroups", [])
258
+
259
+ async def _describe_eks_nodegroup(self, cluster_name: str, nodegroup: str) -> Dict[str, Any]:
260
+ async with self.aws.client("eks") as eks:
261
+ response = await eks.describe_nodegroup(clusterName=cluster_name, nodegroupName=nodegroup)
262
+ return response.get("nodegroup", {})
263
+
264
+ async def _list_eks_fargate_profiles(self, cluster_name: str) -> List[str]:
265
+ async with self.aws.client("eks") as eks:
266
+ response = await eks.list_fargate_profiles(clusterName=cluster_name)
267
+ return response.get("fargateProfileNames", [])
268
+
269
+ async def _describe_eks_fargate_profile(
270
+ self, cluster_name: str, fargate_profile: str
271
+ ) -> Dict[str, Any]:
272
+ async with self.aws.client("eks") as eks:
273
+ response = await eks.describe_fargate_profile(
274
+ clusterName=cluster_name, fargateProfileName=fargate_profile
275
+ )
276
+ return response.get("fargateProfile", {})
277
+
278
+ async def _get_eks_token(self, cluster_name: str) -> str:
279
+ """Generate an authentication token for EKS cluster using STS."""
280
+ try:
281
+ session = boto_session.Session()
282
+ client = session.create_client('sts', region_name=self.aws._region)
283
+
284
+ service_id = client.meta.service_model.service_id
285
+ signer = RequestSigner(
286
+ service_id,
287
+ self.aws._region,
288
+ 'sts',
289
+ 'v4',
290
+ session.get_credentials(),
291
+ session.get_component('event_emitter')
292
+ )
293
+
294
+ params = {
295
+ 'method': 'GET',
296
+ 'url': f'https://sts.{self.aws._region}.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15',
297
+ 'body': {},
298
+ 'headers': {
299
+ 'x-k8s-aws-id': cluster_name
300
+ },
301
+ 'context': {}
302
+ }
303
+
304
+ signed_url = signer.generate_presigned_url(
305
+ params,
306
+ region_name=self.aws._region,
307
+ expires_in=60,
308
+ operation_name=''
309
+ )
310
+
311
+ token = f"k8s-aws-v1.{base64.urlsafe_b64encode(signed_url.encode()).decode().rstrip('=')}"
312
+ return token
313
+ except Exception as exc:
314
+ raise ValueError(f"Failed to generate EKS token: {exc}")
315
+
316
+ async def _list_eks_pods(
317
+ self, cluster_name: str, namespace: Optional[str] = None
318
+ ) -> List[Dict[str, Any]]:
319
+ """
320
+ List all pods in an EKS cluster.
321
+
322
+ This method authenticates with the EKS cluster using AWS STS and queries
323
+ the Kubernetes API to retrieve pod information.
324
+ """
325
+ try:
326
+ # Import aiohttp for making HTTP requests to k8s API
327
+ # Get cluster endpoint and certificate
328
+ cluster_info = await self._describe_eks_cluster(cluster_name)
329
+ endpoint = cluster_info.get("endpoint")
330
+ ca_data = cluster_info.get("resources_vpc_config", {})
331
+
332
+ if not endpoint:
333
+ raise ValueError(f"Could not get endpoint for cluster {cluster_name}")
334
+
335
+ # Get authentication token
336
+ token = await self._get_eks_token(cluster_name)
337
+
338
+ # Prepare the API URL
339
+ if namespace:
340
+ url = f"{endpoint}/api/v1/namespaces/{namespace}/pods"
341
+ else:
342
+ url = f"{endpoint}/api/v1/pods"
343
+
344
+ # Create SSL context (skip verification for simplicity, or use cluster CA)
345
+ ssl_context = ssl.create_default_context()
346
+ ssl_context.check_hostname = False
347
+ ssl_context.verify_mode = ssl.CERT_NONE
348
+
349
+ headers = {
350
+ "Authorization": f"Bearer {token}",
351
+ "Accept": "application/json"
352
+ }
353
+
354
+ async with aiohttp.ClientSession() as session:
355
+ async with session.get(url, headers=headers, ssl=ssl_context) as response:
356
+ if response.status != 200:
357
+ error_text = await response.text()
358
+ raise ValueError(
359
+ f"Failed to list pods: HTTP {response.status} - {error_text}"
360
+ )
361
+
362
+ data = await response.json()
363
+ items = data.get("items", [])
364
+
365
+ # Extract relevant pod information
366
+ pods = []
367
+ for item in items:
368
+ metadata = item.get("metadata", {})
369
+ spec = item.get("spec", {})
370
+ status = item.get("status", {})
371
+
372
+ pod_info = {
373
+ "name": metadata.get("name"),
374
+ "namespace": metadata.get("namespace"),
375
+ "uid": metadata.get("uid"),
376
+ "creation_timestamp": metadata.get("creationTimestamp"),
377
+ "labels": metadata.get("labels", {}),
378
+ "annotations": metadata.get("annotations", {}),
379
+ "node_name": spec.get("nodeName"),
380
+ "phase": status.get("phase"),
381
+ "pod_ip": status.get("podIP"),
382
+ "host_ip": status.get("hostIP"),
383
+ "start_time": status.get("startTime"),
384
+ "conditions": status.get("conditions", []),
385
+ "container_statuses": status.get("containerStatuses", []),
386
+ }
387
+ pods.append(pod_info)
388
+
389
+ return pods
390
+
391
+ except ImportError as e:
392
+ raise ValueError(
393
+ "aiohttp is required to list EKS pods. Install it with: pip install aiohttp"
394
+ ) from e
395
+ except Exception as exc:
396
+ raise ValueError(
397
+ f"Failed to list EKS pods: {exc}"
398
+ ) from exc
399
+
400
+ async def _list_ec2_instances(
401
+ self,
402
+ instance_state: Optional[str] = None,
403
+ instance_ids: Optional[List[str]] = None,
404
+ ) -> List[Dict[str, Any]]:
405
+ """
406
+ List EC2 instances in the AWS account.
407
+
408
+ Args:
409
+ instance_state: Filter by instance state (e.g., 'running', 'stopped')
410
+ instance_ids: Specific instance IDs to describe
411
+
412
+ Returns:
413
+ List of EC2 instance information dictionaries
414
+ """
415
+ params: Dict[str, Any] = {}
416
+
417
+ # Build filters
418
+ filters = []
419
+ if instance_state:
420
+ filters.append(
421
+ {"Name": "instance-state-name", "Values": [instance_state]}
422
+ )
423
+
424
+ if filters:
425
+ params["Filters"] = filters
426
+
427
+ if instance_ids:
428
+ params["InstanceIds"] = instance_ids
429
+
430
+ async with self.aws.client("ec2") as ec2:
431
+ response = await ec2.describe_instances(**params)
432
+
433
+ instances = []
434
+ for reservation in response.get("Reservations", []):
435
+ for instance in reservation.get("Instances", []):
436
+ # Extract relevant instance information
437
+ instance_info = {
438
+ "instance_id": instance.get("InstanceId"),
439
+ "instance_type": instance.get("InstanceType"),
440
+ "state": instance.get("State", {}).get("Name"),
441
+ "state_code": instance.get("State", {}).get("Code"),
442
+ "launch_time": instance.get("LaunchTime").isoformat()
443
+ if instance.get("LaunchTime")
444
+ else None,
445
+ "availability_zone": instance.get("Placement", {}).get(
446
+ "AvailabilityZone"
447
+ ),
448
+ "private_ip": instance.get("PrivateIpAddress"),
449
+ "public_ip": instance.get("PublicIpAddress"),
450
+ "private_dns": instance.get("PrivateDnsName"),
451
+ "public_dns": instance.get("PublicDnsName"),
452
+ "vpc_id": instance.get("VpcId"),
453
+ "subnet_id": instance.get("SubnetId"),
454
+ "architecture": instance.get("Architecture"),
455
+ "image_id": instance.get("ImageId"),
456
+ "key_name": instance.get("KeyName"),
457
+ "platform": instance.get("Platform"),
458
+ "tags": {
459
+ tag.get("Key"): tag.get("Value")
460
+ for tag in instance.get("Tags", [])
461
+ },
462
+ "security_groups": [
463
+ {
464
+ "id": sg.get("GroupId"),
465
+ "name": sg.get("GroupName"),
466
+ }
467
+ for sg in instance.get("SecurityGroups", [])
468
+ ],
469
+ }
470
+ instances.append(instance_info)
471
+
472
+ return instances
473
+
474
+ async def _execute(self, **kwargs) -> ToolResult:
475
+ try:
476
+ operation = kwargs.get("operation")
477
+
478
+ if operation == ECSOperation.LIST_ECS_CLUSTERS:
479
+ clusters = await self._list_ecs_clusters()
480
+ return ToolResult(
481
+ success=True,
482
+ status="completed",
483
+ result={"clusters": clusters, "count": len(clusters)},
484
+ metadata={"operation": "list_ecs_clusters"},
485
+ error=None,
486
+ timestamp=datetime.now(timezone.utc).isoformat(),
487
+ )
488
+
489
+ if operation in (
490
+ ECSOperation.LIST_ECS_SERVICES,
491
+ ECSOperation.LIST_SERVICES,
492
+ ):
493
+ if not kwargs.get("cluster_name"):
494
+ return ToolResult(
495
+ success=False,
496
+ status="error",
497
+ result=None,
498
+ error="cluster_name is required for list_ecs_services",
499
+ metadata={},
500
+ timestamp=datetime.now(timezone.utc).isoformat(),
501
+ )
502
+ services = await self._list_services(kwargs["cluster_name"])
503
+ return ToolResult(
504
+ success=True,
505
+ status="completed",
506
+ result={"services": services, "count": len(services)},
507
+ metadata={
508
+ "operation": ECSOperation.LIST_ECS_SERVICES.value,
509
+ "cluster": kwargs["cluster_name"],
510
+ },
511
+ error=None,
512
+ timestamp=datetime.now(timezone.utc).isoformat(),
513
+ )
514
+
515
+ if operation in (ECSOperation.LIST_ECS_TASKS, ECSOperation.LIST_TASKS):
516
+ if not kwargs.get("cluster_name"):
517
+ return ToolResult(
518
+ success=False,
519
+ status="error",
520
+ result=None,
521
+ error="cluster_name is required for list_ecs_tasks",
522
+ metadata={},
523
+ timestamp=datetime.now(timezone.utc).isoformat(),
524
+ )
525
+ tasks = await self._list_tasks(
526
+ cluster=kwargs["cluster_name"],
527
+ service_name=kwargs.get("service_name"),
528
+ desired_status=kwargs.get("desired_status"),
529
+ launch_type=kwargs.get("launch_type"),
530
+ )
531
+ return ToolResult(
532
+ success=True,
533
+ status="completed",
534
+ result={"tasks": tasks, "count": len(tasks)},
535
+ metadata={
536
+ "operation": ECSOperation.LIST_ECS_TASKS.value,
537
+ "cluster": kwargs["cluster_name"],
538
+ "service": kwargs.get("service_name"),
539
+ },
540
+ error=None,
541
+ timestamp=datetime.now(timezone.utc).isoformat(),
542
+ )
543
+
544
+ if operation in (
545
+ ECSOperation.DESCRIBE_ECS_TASKS,
546
+ ECSOperation.DESCRIBE_TASKS,
547
+ ):
548
+ if not kwargs.get("cluster_name") or not kwargs.get("task_arns"):
549
+ return ToolResult(
550
+ success=False,
551
+ status="error",
552
+ result=None,
553
+ error="cluster_name and task_arns are required for describe_ecs_tasks",
554
+ metadata={},
555
+ timestamp=datetime.now(timezone.utc).isoformat(),
556
+ )
557
+ details = await self._describe_tasks(
558
+ cluster=kwargs["cluster_name"], task_arns=kwargs["task_arns"]
559
+ )
560
+ return ToolResult(
561
+ success=True,
562
+ status="completed",
563
+ result={"tasks": details, "count": len(details)},
564
+ metadata={
565
+ "operation": ECSOperation.DESCRIBE_ECS_TASKS.value,
566
+ "cluster": kwargs["cluster_name"],
567
+ },
568
+ error=None,
569
+ timestamp=datetime.now(timezone.utc).isoformat(),
570
+ )
571
+
572
+ if operation in (
573
+ ECSOperation.GET_FARGATE_TASK_LOGS,
574
+ ECSOperation.GET_FARGATE_LOGS,
575
+ ):
576
+ if not kwargs.get("log_group_name"):
577
+ return ToolResult(
578
+ success=False,
579
+ status="error",
580
+ result=None,
581
+ error="log_group_name is required for get_fargate_task_logs",
582
+ metadata={},
583
+ timestamp=datetime.now(timezone.utc).isoformat(),
584
+ )
585
+ start_time = self._parse_time(kwargs.get("start_time")) if kwargs.get("start_time") else None
586
+ events = await self._get_fargate_logs(
587
+ log_group_name=kwargs["log_group_name"],
588
+ log_stream_prefix=kwargs.get("log_stream_prefix"),
589
+ start_time=start_time,
590
+ limit=kwargs.get("limit", 100),
591
+ )
592
+ return ToolResult(
593
+ success=True,
594
+ status="completed",
595
+ result={"events": events, "count": len(events)},
596
+ metadata={
597
+ "operation": ECSOperation.GET_FARGATE_TASK_LOGS.value,
598
+ "log_group": kwargs["log_group_name"],
599
+ "log_stream_prefix": kwargs.get("log_stream_prefix"),
600
+ },
601
+ error=None,
602
+ timestamp=datetime.now(timezone.utc).isoformat(),
603
+ )
604
+
605
+ if operation in (
606
+ ECSOperation.DESCRIBE_EKS_CLUSTER,
607
+ ECSOperation.GET_EKS_CLUSTER_INFO,
608
+ ):
609
+ if not kwargs.get("cluster_name"):
610
+ return ToolResult(
611
+ success=False,
612
+ status="error",
613
+ result=None,
614
+ error="cluster_name is required for describe_eks_cluster",
615
+ metadata={},
616
+ timestamp=datetime.now(timezone.utc).isoformat(),
617
+ )
618
+ info = await self._describe_eks_cluster(kwargs["cluster_name"])
619
+ return ToolResult(
620
+ success=True,
621
+ status="completed",
622
+ result=info,
623
+ metadata={
624
+ "operation": ECSOperation.DESCRIBE_EKS_CLUSTER.value,
625
+ "cluster": kwargs["cluster_name"],
626
+ },
627
+ error=None,
628
+ timestamp=datetime.now(timezone.utc).isoformat(),
629
+ )
630
+
631
+ if operation == ECSOperation.LIST_EKS_CLUSTERS:
632
+ clusters = await self._list_eks_clusters()
633
+ return ToolResult(
634
+ success=True,
635
+ status="completed",
636
+ result={"clusters": clusters, "count": len(clusters)},
637
+ metadata={"operation": ECSOperation.LIST_EKS_CLUSTERS.value},
638
+ error=None,
639
+ timestamp=datetime.now(timezone.utc).isoformat(),
640
+ )
641
+
642
+ if operation == ECSOperation.LIST_EKS_NODEGROUPS:
643
+ if not kwargs.get("cluster_name"):
644
+ return ToolResult(
645
+ success=False,
646
+ status="error",
647
+ result=None,
648
+ error="cluster_name is required for list_eks_nodegroups",
649
+ metadata={},
650
+ timestamp=datetime.now(timezone.utc).isoformat(),
651
+ )
652
+ nodegroups = await self._list_eks_nodegroups(kwargs["cluster_name"])
653
+ return ToolResult(
654
+ success=True,
655
+ status="completed",
656
+ result={"nodegroups": nodegroups, "count": len(nodegroups)},
657
+ metadata={
658
+ "operation": ECSOperation.LIST_EKS_NODEGROUPS.value,
659
+ "cluster": kwargs["cluster_name"],
660
+ },
661
+ error=None,
662
+ timestamp=datetime.now(timezone.utc).isoformat(),
663
+ )
664
+
665
+ if operation == ECSOperation.DESCRIBE_EKS_NODEGROUP:
666
+ if not kwargs.get("cluster_name") or not kwargs.get("eks_nodegroup"):
667
+ return ToolResult(
668
+ success=False,
669
+ status="error",
670
+ result=None,
671
+ error="cluster_name and eks_nodegroup are required for describe_eks_nodegroup",
672
+ metadata={},
673
+ timestamp=datetime.now(timezone.utc).isoformat(),
674
+ )
675
+ nodegroup = await self._describe_eks_nodegroup(
676
+ cluster_name=kwargs["cluster_name"], nodegroup=kwargs["eks_nodegroup"]
677
+ )
678
+ return ToolResult(
679
+ success=True,
680
+ status="completed",
681
+ result=nodegroup,
682
+ metadata={
683
+ "operation": ECSOperation.DESCRIBE_EKS_NODEGROUP.value,
684
+ "cluster": kwargs["cluster_name"],
685
+ "nodegroup": kwargs["eks_nodegroup"],
686
+ },
687
+ error=None,
688
+ timestamp=datetime.now(timezone.utc).isoformat(),
689
+ )
690
+
691
+ if operation == ECSOperation.LIST_EKS_FARGATE_PROFILES:
692
+ if not kwargs.get("cluster_name"):
693
+ return ToolResult(
694
+ success=False,
695
+ status="error",
696
+ result=None,
697
+ error="cluster_name is required for list_eks_fargate_profiles",
698
+ metadata={},
699
+ timestamp=datetime.now(timezone.utc).isoformat(),
700
+ )
701
+ profiles = await self._list_eks_fargate_profiles(kwargs["cluster_name"])
702
+ return ToolResult(
703
+ success=True,
704
+ status="completed",
705
+ result={"fargate_profiles": profiles, "count": len(profiles)},
706
+ metadata={
707
+ "operation": ECSOperation.LIST_EKS_FARGATE_PROFILES.value,
708
+ "cluster": kwargs["cluster_name"],
709
+ },
710
+ error=None,
711
+ timestamp=datetime.now(timezone.utc).isoformat(),
712
+ )
713
+
714
+ if operation == ECSOperation.DESCRIBE_EKS_FARGATE_PROFILE:
715
+ if not kwargs.get("cluster_name") or not kwargs.get("eks_fargate_profile"):
716
+ return ToolResult(
717
+ success=False,
718
+ status="error",
719
+ result=None,
720
+ error=(
721
+ "cluster_name and eks_fargate_profile are required for "
722
+ "describe_eks_fargate_profile"
723
+ ),
724
+ metadata={},
725
+ timestamp=datetime.now(timezone.utc).isoformat(),
726
+ )
727
+ profile = await self._describe_eks_fargate_profile(
728
+ cluster_name=kwargs["cluster_name"],
729
+ fargate_profile=kwargs["eks_fargate_profile"],
730
+ )
731
+ return ToolResult(
732
+ success=True,
733
+ status="completed",
734
+ result=profile,
735
+ metadata={
736
+ "operation": ECSOperation.DESCRIBE_EKS_FARGATE_PROFILE.value,
737
+ "cluster": kwargs["cluster_name"],
738
+ "fargate_profile": kwargs["eks_fargate_profile"],
739
+ },
740
+ error=None,
741
+ timestamp=datetime.now(timezone.utc).isoformat(),
742
+ )
743
+
744
+ if operation == ECSOperation.LIST_EKS_PODS:
745
+ if not kwargs.get("cluster_name"):
746
+ return ToolResult(
747
+ success=False,
748
+ status="error",
749
+ result=None,
750
+ error="cluster_name is required for list_eks_pods",
751
+ metadata={},
752
+ timestamp=datetime.now(timezone.utc).isoformat(),
753
+ )
754
+ pods = await self._list_eks_pods(
755
+ cluster_name=kwargs["cluster_name"],
756
+ namespace=kwargs.get("namespace"),
757
+ )
758
+ return ToolResult(
759
+ success=True,
760
+ status="completed",
761
+ result={"pods": pods, "count": len(pods)},
762
+ metadata={
763
+ "operation": ECSOperation.LIST_EKS_PODS.value,
764
+ "cluster": kwargs["cluster_name"],
765
+ "namespace": kwargs.get("namespace", "all"),
766
+ },
767
+ error=None,
768
+ timestamp=datetime.now(timezone.utc).isoformat(),
769
+ )
770
+
771
+ if operation == ECSOperation.LIST_EC2_INSTANCES:
772
+ instances = await self._list_ec2_instances(
773
+ instance_state=kwargs.get("instance_state"),
774
+ instance_ids=kwargs.get("instance_ids"),
775
+ )
776
+ return ToolResult(
777
+ success=True,
778
+ status="completed",
779
+ result={"instances": instances, "count": len(instances)},
780
+ metadata={
781
+ "operation": ECSOperation.LIST_EC2_INSTANCES.value,
782
+ "instance_state": kwargs.get("instance_state"),
783
+ },
784
+ error=None,
785
+ timestamp=datetime.now(timezone.utc).isoformat(),
786
+ )
787
+
788
+ return ToolResult(
789
+ success=False,
790
+ status="error",
791
+ result=None,
792
+ error=f"Unknown operation: {operation}",
793
+ metadata={"operation": str(operation)},
794
+ timestamp=datetime.now(timezone.utc).isoformat(),
795
+ )
796
+
797
+ except ClientError as exc:
798
+ error_code = exc.response["Error"].get("Code")
799
+ error_msg = exc.response["Error"].get("Message")
800
+ return ToolResult(
801
+ success=False,
802
+ status="aws_error",
803
+ result=None,
804
+ error=f"AWS Error ({error_code}): {error_msg}",
805
+ metadata={"operation": kwargs.get("operation"), "error_code": error_code},
806
+ timestamp=datetime.now(timezone.utc).isoformat(),
807
+ )
808
+ except Exception as exc:
809
+ return ToolResult(
810
+ success=False,
811
+ status="error",
812
+ result=None,
813
+ error=f"ECS/EKS operation failed: {exc}",
814
+ metadata={
815
+ "operation": kwargs.get("operation"),
816
+ "exception_type": type(exc).__name__,
817
+ },
818
+ timestamp=datetime.now(timezone.utc).isoformat(),
819
+ )