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,801 @@
1
+ """
2
+ REST API Handler for AgentCrew Management.
3
+
4
+ Provides endpoints for creating, managing, and executing agent crews.
5
+
6
+ Endpoints:
7
+ PUT /api/v1/crew - Create a new crew
8
+ GET /api/v1/crew - List all crews or get specific crew by name
9
+ POST /api/v1/crew/execute - Execute a crew asynchronously
10
+ PATCH /api/v1/crew/job - Get job status and results
11
+ DELETE /api/v1/crew - Delete a crew
12
+ """
13
+ from typing import Any, List, Optional
14
+ import uuid
15
+ import json
16
+ from aiohttp import web
17
+ from navigator.views import BaseView
18
+ from navigator.types import WebApp # pylint: disable=E0611,E0401
19
+ from navigator.applications.base import BaseApplication # pylint: disable=E0611,E0401
20
+ from navconfig.logging import logging
21
+ from parrot.bots.orchestration.crew import AgentCrew
22
+ from .models import (
23
+ CrewDefinition,
24
+ JobStatus,
25
+ ExecutionMode,
26
+ )
27
+ from ..jobs import JobManager
28
+
29
+
30
+ class CrewHandler(BaseView):
31
+ """
32
+ REST API Handler for AgentCrew operations.
33
+
34
+ This handler provides a complete REST API for managing and executing
35
+ agent crews with support for sequential, parallel, and flow-based
36
+ execution modes.
37
+ """
38
+
39
+ path: str = '/api/v1/crew'
40
+ app: WebApp = None
41
+
42
+ def __init__(self, *args, **kwargs):
43
+ super().__init__(*args, **kwargs)
44
+ self.logger = logging.getLogger('Parrot.CrewHandler')
45
+ # Get bot manager from app if available
46
+ self._bot_manager = None
47
+ self.job_manager: JobManager = self.app['job_manager'] if 'job_manager' in self.app else JobManager()
48
+
49
+ @property
50
+ def bot_manager(self):
51
+ """Get bot manager."""
52
+ if not self._bot_manager:
53
+ app = self.request.app
54
+ self._bot_manager = app['bot_manager'] if 'bot_manager' in app else None
55
+ return self._bot_manager
56
+
57
+ @bot_manager.setter
58
+ def bot_manager(self, value):
59
+ """Set bot manager."""
60
+ self._bot_manager = value
61
+
62
+ @staticmethod
63
+ async def configure_job_manager(app: WebApp):
64
+ """Configure and start job manager."""
65
+ app['job_manager'] = JobManager()
66
+ await app['job_manager'].start()
67
+
68
+ @classmethod
69
+ def configure(cls, app: WebApp = None, path: str = None, **kwargs) -> WebApp:
70
+ """configure.
71
+ Configure the CrewHandler in an aiohttp Web Application.
72
+ Args:
73
+ app (WebApp): aiohttp Web Application instance.
74
+ path (str, optional): route path for Model.
75
+
76
+ Raises:
77
+ TypeError: Invalid aiohttp Application.
78
+ ConfigError: Wrong configuration parameters.
79
+ """
80
+ if isinstance(app, BaseApplication):
81
+ cls.app = app.get_app()
82
+ elif isinstance(app, WebApp):
83
+ cls.app = app # register the app into the Extension
84
+ # startup operations over extension backend
85
+ if app:
86
+ url = f"{path}"
87
+ app.router.add_view(
88
+ r"{url}/{{id:.*}}".format(url=url), cls
89
+ )
90
+ app.router.add_view(
91
+ r"{url}{{meta:(:.*)?}}".format(url=url), cls
92
+ )
93
+ app.on_startup.append(cls.configure_job_manager)
94
+
95
+ async def upload(self):
96
+ """
97
+ Upload a crew definition from a JSON file.
98
+
99
+ This endpoint accepts multipart/form-data with a JSON file containing
100
+ the crew definition from the visual builder.
101
+
102
+ Form data:
103
+ - file: JSON file with crew definition
104
+
105
+ Returns:
106
+ 201: Crew created successfully from file
107
+ 400: Invalid file or format
108
+ 500: Server error
109
+ """
110
+ try:
111
+ # Get multipart reader
112
+ reader = await self.request.multipart()
113
+
114
+ # Read file field
115
+ field = await reader.next()
116
+
117
+ if not field or field.name != 'file':
118
+ return self.error(
119
+ response={"message": "No file provided. Expected 'file' field."},
120
+ status=400
121
+ )
122
+
123
+ # Read file content
124
+ content = await field.read(decode=True)
125
+ try:
126
+ crew_data = json.loads(content)
127
+ except json.JSONDecodeError as e:
128
+ return self.error(
129
+ response={"message": f"Invalid JSON format: {str(e)}"},
130
+ status=400
131
+ )
132
+
133
+ # Validate bot manager availability
134
+ if not self.bot_manager:
135
+ return self.error(
136
+ response={"message": "BotManager not available"},
137
+ status=500
138
+ )
139
+
140
+ # Parse into CrewDefinition
141
+ try:
142
+ crew_def = CrewDefinition(**crew_data)
143
+ except Exception as e:
144
+ return self.error(
145
+ response={"message": f"Invalid crew definition: {str(e)}"},
146
+ status=400
147
+ )
148
+
149
+ # Create the crew
150
+ try:
151
+ crew = await self._create_crew_from_definition(crew_def)
152
+
153
+ # Register crew in bot manager
154
+ await self.bot_manager.add_crew(crew_def.name, crew, crew_def)
155
+
156
+ self.logger.info(
157
+ f"Uploaded and created crew '{crew_def.name}' with {len(crew_def.agents)} agents"
158
+ )
159
+
160
+ return self.json_response(
161
+ {
162
+ "message": "Crew uploaded and created successfully",
163
+ "crew_id": crew_def.crew_id,
164
+ "name": crew_def.name,
165
+ "execution_mode": crew_def.execution_mode.value, # pylint: disable=E1101 #noqa
166
+ "agents": [agent.agent_id for agent in crew_def.agents],
167
+ "created_at": crew_def.created_at.isoformat()
168
+ },
169
+ status=201
170
+ )
171
+
172
+ except Exception as e:
173
+ self.logger.error(f"Error creating crew from upload: {e}", exc_info=True)
174
+ return self.error(
175
+ response={"message": f"Error creating crew: {str(e)}"},
176
+ status=400
177
+ )
178
+
179
+ except web.HTTPError:
180
+ raise
181
+ except Exception as e:
182
+ self.logger.error(f"Error processing upload: {e}", exc_info=True)
183
+ return self.error(
184
+ response={"message": f"Error processing upload: {str(e)}"},
185
+ status=500
186
+ )
187
+
188
+ async def put(self):
189
+ """
190
+ Create a new AgentCrew or update an existing one.
191
+
192
+ URL parameters:
193
+ - id: Crew ID or name (optional, for updates)
194
+ e.g., /api/v1/crew/my-crew-id
195
+
196
+ Request body should contain CrewDefinition:
197
+ {
198
+ "name": "research_crew",
199
+ "execution_mode": "sequential|parallel|flow",
200
+ "agents": [
201
+ {
202
+ "agent_id": "researcher",
203
+ "agent_class": "BaseAgent",
204
+ "name": "Research Agent",
205
+ "config": {"model": "gpt-4", "temperature": 0.7},
206
+ "tools": ["web_search"],
207
+ "system_prompt": "You are a researcher..."
208
+ }
209
+ ],
210
+ "flow_relations": [ // Only for flow mode
211
+ {"source": "agent1", "target": ["agent2", "agent3"]},
212
+ {"source": ["agent2", "agent3"], "target": "agent4"}
213
+ ],
214
+ "shared_tools": ["calculator"],
215
+ "max_parallel_tasks": 10
216
+ }
217
+
218
+ Returns:
219
+ 201: Crew created successfully
220
+ 200: Crew updated successfully
221
+ 400: Invalid request
222
+ 404: Crew not found (for updates)
223
+ 500: Server error
224
+ """
225
+ try:
226
+ # Get crew ID from URL if provided
227
+ match_params = self.match_parameters(self.request)
228
+ url_crew_id = match_params.get('id')
229
+
230
+ # Parse request body
231
+ data = await self.request.json()
232
+ crew_def = CrewDefinition(**data)
233
+
234
+ # Validate bot manager availability
235
+ if not self.bot_manager:
236
+ return self.error(
237
+ response={
238
+ "message": "BotManager not available"
239
+ },
240
+ status=500
241
+ )
242
+ # if crew_id is provided, then is an update
243
+ if url_crew_id:
244
+ existing_crew = await self.bot_manager.get_crew(url_crew_id)
245
+ if not existing_crew:
246
+ return self.error(
247
+ response={
248
+ "message": f"Crew '{url_crew_id}' not found for update"
249
+ },
250
+ status=404
251
+ )
252
+ # Update existing crew definition
253
+ _, existing_def = existing_crew
254
+ crew_def.crew_id = existing_def.crew_id # Preserve original ID
255
+ crew_def.created_at = existing_def.created_at # Preserve creation time
256
+ crew_def.updated_at = None # Will be set on save
257
+
258
+ # Remove old crew
259
+ await self.bot_manager.remove_crew(url_crew_id)
260
+
261
+ self.logger.info(f"Updating crew '{url_crew_id}'")
262
+
263
+ # Create the crew via bot manager
264
+ try:
265
+ crew = await self._create_crew_from_definition(crew_def)
266
+
267
+ crew_key = url_crew_id or crew_def.name
268
+
269
+ # Register crew in bot manager
270
+ await self.bot_manager.add_crew(crew_key, crew, crew_def)
271
+
272
+ action = "updated" if url_crew_id else "created"
273
+ status_code = 202 if url_crew_id else 201
274
+
275
+ self.logger.info(
276
+ f"{action.capitalize()} crew '{crew_def.name}' with {len(crew_def.agents)} agents"
277
+ )
278
+
279
+ return self.json_response(
280
+ {
281
+ "message": f"Crew {action} successfully",
282
+ "crew_id": crew_def.crew_id,
283
+ "name": crew_def.name,
284
+ "execution_mode": crew_def.execution_mode.value, # pylint: disable=E1101
285
+ "agents": [agent.agent_id for agent in crew_def.agents],
286
+ "created_at": crew_def.created_at.isoformat() # pylint: disable=E1101
287
+ },
288
+ status=status_code
289
+ )
290
+
291
+ except Exception as e:
292
+ self.logger.error(f"Error creating crew: {e}", exc_info=True)
293
+ return self.error(
294
+ response={
295
+ "message": f"Error creating crew: {str(e)}"
296
+ },
297
+ status=400
298
+ )
299
+ except web.HTTPError:
300
+ raise
301
+ except Exception as e:
302
+ self.logger.error(f"Error parsing request: {e}", exc_info=True)
303
+ return self.error(
304
+ response={
305
+ "message": f"Invalid request: {str(e)}"
306
+ },
307
+ status=400
308
+ )
309
+
310
+ async def get(self):
311
+ """
312
+ Get crew information.
313
+
314
+ Query parameters:
315
+ - name: Crew name (optional) - returns specific crew if provided
316
+ - crew_id: Crew ID (optional) - returns specific crew if provided
317
+
318
+ Returns:
319
+ 200: Crew definition(s)
320
+ 404: Crew not found
321
+ 500: Server error
322
+ """
323
+ try:
324
+ qs = self.get_arguments(self.request)
325
+ match_params = self.match_parameters(self.request)
326
+ crew_id = match_params.get('id') or qs.get('crew_id')
327
+ crew_name = qs.get('name')
328
+
329
+ if not self.bot_manager:
330
+ return self.error(
331
+ response={"message": "BotManager not available"},
332
+ status=400
333
+ )
334
+
335
+ # Get specific crew
336
+ if crew_name or crew_id:
337
+ identifier = crew_name or crew_id
338
+ crew_data = await self.bot_manager.get_crew(identifier)
339
+
340
+ if not crew_data:
341
+ return self.error(
342
+ response={
343
+ "message": f"Crew '{identifier}' not found"
344
+ },
345
+ status=404
346
+ )
347
+
348
+ crew, crew_def = crew_data
349
+ return self.json_response({
350
+ "crew_id": crew_def.crew_id,
351
+ "name": crew_def.name,
352
+ "description": crew_def.description,
353
+ "execution_mode": crew_def.execution_mode.value,
354
+ "agents": [agent.dict() for agent in crew_def.agents],
355
+ "flow_relations": [
356
+ rel.dict() for rel in crew_def.flow_relations
357
+ ],
358
+ "shared_tools": crew_def.shared_tools,
359
+ "max_parallel_tasks": crew_def.max_parallel_tasks,
360
+ "created_at": crew_def.created_at.isoformat(),
361
+ "updated_at": crew_def.updated_at.isoformat(),
362
+ "metadata": crew_def.metadata
363
+ })
364
+
365
+ # List all crews
366
+ crews = self.bot_manager.list_crews()
367
+ crew_list = []
368
+
369
+ crew_list.extend(
370
+ {
371
+ "crew_id": crew_def.crew_id,
372
+ "name": crew_def.name,
373
+ "description": crew_def.description,
374
+ "execution_mode": crew_def.execution_mode.value,
375
+ "agent_count": len(crew_def.agents),
376
+ "created_at": crew_def.created_at.isoformat(),
377
+ }
378
+ for name, (crew, crew_def) in crews.items()
379
+ )
380
+
381
+ return self.json_response({
382
+ "crews": crew_list,
383
+ "total": len(crew_list)
384
+ })
385
+ except web.HTTPError:
386
+ raise
387
+ except Exception as e:
388
+ self.logger.error(f"Error getting crew: {e}", exc_info=True)
389
+ return self.error(
390
+ response={"message": f"Error: {str(e)}"},
391
+ status=500
392
+ )
393
+
394
+ async def post(self):
395
+ """
396
+ Execute a crew asynchronously.
397
+
398
+ Request body:
399
+ {
400
+ "crew_id": "uuid" or "name": "crew_name",
401
+ "query": "What is the status of AI research?" or {"agent1": "task1", "agent2": "task2"},
402
+ "execution_mode": "sequential|parallel|loop|flow",
403
+ "user_id": "optional_user_id",
404
+ "session_id": "optional_session_id",
405
+ "synthesis_prompt": "optional synthesis prompt for research mode",
406
+ "kwargs": {} // Additional execution arguments
407
+ }
408
+
409
+ Returns:
410
+ 202: Job created and queued
411
+ 400: Invalid request
412
+ 404: Crew not found
413
+ 500: Server error
414
+ """
415
+ try:
416
+ # Parse request
417
+ data = await self.request.json()
418
+
419
+ # Get crew identifier
420
+ crew_id = data.get('crew_id') or data.get('name')
421
+ if not crew_id:
422
+ return self.error(
423
+ response={"message": "crew_id or name is required"},
424
+ status=400
425
+ )
426
+
427
+ query = data.get('query')
428
+ if not query:
429
+ return self.error(
430
+ response={"message": "query is required"},
431
+ status=400
432
+ )
433
+
434
+ # Get crew
435
+ if not self.bot_manager:
436
+ return self.error(
437
+ response={"message": "BotManager not available"},
438
+ status=500
439
+ )
440
+
441
+ crew_data = await self.bot_manager.get_crew(crew_id)
442
+ if not crew_data:
443
+ return self.error(
444
+ response={"message": f"Crew '{crew_id}' not found"},
445
+ status=404
446
+ )
447
+
448
+ crew, crew_def = crew_data
449
+ requested_mode = data.get('execution_mode')
450
+ override_mode: Optional[ExecutionMode] = None
451
+ if requested_mode:
452
+ try:
453
+ override_mode = ExecutionMode(requested_mode)
454
+ except ValueError:
455
+ return self.error(
456
+ response={"message": f"Invalid execution mode: {requested_mode}"},
457
+ status=400
458
+ )
459
+
460
+ selected_mode = override_mode or crew_def.execution_mode
461
+ # Create a job for async execution
462
+ job_id = str(uuid.uuid4())
463
+
464
+ # Create job
465
+ job = self.job_manager.create_job(
466
+ job_id=job_id,
467
+ obj_id=crew_def.crew_id,
468
+ query=query,
469
+ user_id=data.get('user_id'),
470
+ session_id=data.get('session_id'),
471
+ execution_mode=selected_mode.value
472
+ )
473
+
474
+ # Execute asynchronously
475
+ execution_kwargs = data.get('kwargs', {})
476
+ synthesis_prompt = data.get('synthesis_prompt', None)
477
+
478
+ execution_kwargs.update({
479
+ 'user_id': job.user_id,
480
+ 'session_id': job.session_id,
481
+ "max_tokens": execution_kwargs.get("max_tokens", 4096),
482
+ "temperature": execution_kwargs.get("temperature", 0.1)
483
+ })
484
+ if synthesis_prompt:
485
+ execution_kwargs['synthesis_prompt'] = synthesis_prompt
486
+
487
+ async def execute_crew():
488
+ """Async execution function."""
489
+ try:
490
+ # Determine execution mode
491
+ mode = override_mode or crew_def.execution_mode
492
+
493
+ if mode == ExecutionMode.SEQUENTIAL:
494
+ result = await crew.run_sequential(
495
+ query=query,
496
+ **execution_kwargs
497
+ )
498
+ elif mode == ExecutionMode.PARALLEL:
499
+ # Handle parallel execution
500
+ if isinstance(query, dict):
501
+ tasks = [
502
+ {"agent_id": agent_id, "query": agent_query}
503
+ for agent_id, agent_query in query.items()
504
+ ]
505
+ else:
506
+ tasks = [
507
+ {"agent_id": agent_id, "query": query}
508
+ for agent_id in crew.agents.keys()
509
+ ]
510
+
511
+ result = await crew.run_parallel(
512
+ tasks=tasks,
513
+ **execution_kwargs
514
+ )
515
+ elif mode == ExecutionMode.LOOP:
516
+ if not isinstance(query, str):
517
+ raise ValueError("Loop execution requires a string query for the initial task")
518
+
519
+ loop_condition = execution_kwargs.pop('condition', None)
520
+ if not loop_condition or not isinstance(loop_condition, str):
521
+ raise ValueError("Loop execution requires a 'condition' string in kwargs")
522
+
523
+ agent_sequence = execution_kwargs.pop('agent_sequence', None)
524
+ if agent_sequence is not None:
525
+ if not isinstance(agent_sequence, list):
526
+ raise ValueError("'agent_sequence' must be a list of agent identifiers")
527
+ if not all(isinstance(agent_id, str) for agent_id in agent_sequence):
528
+ raise ValueError("'agent_sequence' values must be strings")
529
+
530
+ max_iterations = execution_kwargs.pop('max_iterations', None)
531
+ if max_iterations is None:
532
+ max_iterations = 2
533
+ elif not isinstance(max_iterations, int):
534
+ raise ValueError("'max_iterations' must be an integer")
535
+
536
+ result = await crew.run_loop(
537
+ initial_task=query,
538
+ condition=loop_condition,
539
+ agent_sequence=agent_sequence,
540
+ max_iterations=max_iterations,
541
+ **execution_kwargs
542
+ )
543
+ elif mode == ExecutionMode.FLOW:
544
+ result = await crew.run_flow(
545
+ initial_task=query,
546
+ **execution_kwargs
547
+ )
548
+ else:
549
+ raise ValueError(f"Unknown execution mode: {mode}")
550
+
551
+ # Convert CrewResult to dict if necessary
552
+ if hasattr(result, 'to_dict'):
553
+ return result.to_dict()
554
+ elif hasattr(result, '__dict__'):
555
+ return result.__dict__
556
+ else:
557
+ return result
558
+
559
+ except Exception as e:
560
+ self.logger.error(
561
+ f"Error executing crew {crew_id}: {e}",
562
+ exc_info=True
563
+ )
564
+ raise
565
+
566
+ # Start execution
567
+ await self.job_manager.execute_job(
568
+ job.job_id,
569
+ execute_crew
570
+ )
571
+
572
+ # Return job ID for tracking
573
+ return self.json_response(
574
+ {
575
+ "job_id": job.job_id,
576
+ "crew_id": crew_def.crew_id,
577
+ "status": job.status.value,
578
+ "message": "Crew execution started",
579
+ "created_at": job.created_at.isoformat(),
580
+ "execution_mode": selected_mode.value
581
+ },
582
+ status=202
583
+ )
584
+ except web.HTTPError:
585
+ raise
586
+ except Exception as e:
587
+ self.logger.error(f"Error creating job: {e}", exc_info=True)
588
+ return self.error(
589
+ response={"message": f"Error: {str(e)}"},
590
+ status=500
591
+ )
592
+
593
+ async def patch(self):
594
+ """
595
+ Get job status and results.
596
+
597
+ Query parameters:
598
+ - job_id: Job identifier (required)
599
+
600
+ Returns:
601
+ 200: Job status and results if completed
602
+ 404: Job not found
603
+ 500: Server error
604
+ """
605
+ try:
606
+ qs = self.get_arguments(self.request)
607
+ match_params = self.match_parameters(self.request)
608
+ job_id = match_params.get('id') or qs.get('job_id')
609
+ if not job_id:
610
+ # get from json body as fallback
611
+ data = await self.request.json()
612
+ job_id = data.get('job_id')
613
+
614
+ if not job_id:
615
+ return self.error(
616
+ response={"message": "job_id is required"},
617
+ status=400
618
+ )
619
+
620
+ # Get job
621
+ job = self.job_manager.get_job(job_id)
622
+ if not job:
623
+ return self.error(
624
+ response={"message": f"Job '{job_id}' not found"},
625
+ status=404
626
+ )
627
+
628
+ # Return job status
629
+ response_data = {
630
+ "job_id": job.job_id,
631
+ "crew_id": job.obj_id,
632
+ "status": job.status.value,
633
+ "elapsed_time": job.elapsed_time,
634
+ "created_at": job.created_at.isoformat(),
635
+ "metadata": job.metadata,
636
+ "execution_mode": job.execution_mode
637
+ }
638
+
639
+ # Add result if completed
640
+ if job.status == JobStatus.COMPLETED:
641
+ response_data["result"] = job.result
642
+ response_data["completed_at"] = job.completed_at.isoformat()
643
+ elif job.status == JobStatus.FAILED:
644
+ response_data["error"] = job.error
645
+ response_data["completed_at"] = job.completed_at.isoformat()
646
+ elif job.status == JobStatus.RUNNING:
647
+ response_data["started_at"] = job.started_at.isoformat()
648
+
649
+ return self.json_response(response_data)
650
+ except web.HTTPError:
651
+ raise
652
+ except Exception as e:
653
+ self.logger.error(f"Error getting job status: {e}", exc_info=True)
654
+ return self.error(
655
+ response={"message": f"Error: {str(e)}"},
656
+ status=500
657
+ )
658
+
659
+ async def delete(self):
660
+ """
661
+ Delete a crew.
662
+
663
+ Query parameters:
664
+ - name: Crew name (optional)
665
+ - crew_id: Crew ID (optional)
666
+
667
+ Returns:
668
+ 200: Crew deleted successfully
669
+ 404: Crew not found
670
+ 500: Server error
671
+ """
672
+ try:
673
+ match_params = self.match_parameters(self.request)
674
+ qs = self.get_arguments(self.request)
675
+ crew_id = match_params.get('id') or qs.get('crew_id')
676
+ crew_name = qs.get('name')
677
+
678
+ if not crew_name and not crew_id:
679
+ return self.error(
680
+ response={"message": "name or crew_id is required"},
681
+ status=400
682
+ )
683
+
684
+ if not self.bot_manager:
685
+ return self.error(
686
+ response={"message": "BotManager not available"},
687
+ status=500
688
+ )
689
+
690
+ identifier = crew_name or crew_id
691
+ success = await self.bot_manager.remove_crew(identifier)
692
+
693
+ if success:
694
+ return self.json_response({
695
+ "message": f"Crew '{identifier}' deleted successfully"
696
+ })
697
+ else:
698
+ return self.error(
699
+ response={"message": f"Crew '{identifier}' not found"},
700
+ status=404
701
+ )
702
+ except web.HTTPError:
703
+ raise
704
+ except Exception as e:
705
+ self.logger.error(f"Error deleting crew: {e}", exc_info=True)
706
+ return self.error(
707
+ response={"message": f"Error: {str(e)}"},
708
+ status=500
709
+ )
710
+
711
+ async def _create_crew_from_definition(
712
+ self,
713
+ crew_def: CrewDefinition
714
+ ) -> AgentCrew:
715
+ """
716
+ Create an AgentCrew instance from a CrewDefinition.
717
+
718
+ Args:
719
+ crew_def: Crew definition
720
+
721
+ Returns:
722
+ AgentCrew instance
723
+ """
724
+ # Create agents
725
+ agents = []
726
+ for agent_def in crew_def.agents:
727
+ # Get agent class
728
+ agent_class = self.bot_manager.get_bot_class(agent_def.agent_class)
729
+
730
+ tools = []
731
+ if agent_def.tools:
732
+ tools.extend(iter(agent_def.tools))
733
+
734
+ # Create agent instance
735
+ agent = agent_class(
736
+ name=agent_def.name or agent_def.agent_id,
737
+ tools=tools,
738
+ **agent_def.config
739
+ )
740
+
741
+ # Set system prompt if provided
742
+ if agent_def.system_prompt:
743
+ agent.system_prompt = agent_def.system_prompt
744
+
745
+ agents.append(agent)
746
+
747
+ # Create crew
748
+ crew = AgentCrew(
749
+ name=crew_def.name,
750
+ agents=agents,
751
+ max_parallel_tasks=crew_def.max_parallel_tasks
752
+ )
753
+
754
+ # Add shared tools
755
+ for tool_name in crew_def.shared_tools:
756
+ if tool := self.bot_manager.get_tool(tool_name):
757
+ crew.add_shared_tool(tool, tool_name)
758
+
759
+ # Setup flow relations if in flow mode
760
+ if crew_def.execution_mode == ExecutionMode.FLOW and crew_def.flow_relations:
761
+ for relation in crew_def.flow_relations:
762
+ # Convert agent IDs to agent objects
763
+ source_agents = self._get_agents_by_ids(
764
+ crew,
765
+ relation.source if isinstance(relation.source, list) else [relation.source]
766
+ )
767
+ target_agents = self._get_agents_by_ids(
768
+ crew,
769
+ relation.target if isinstance(relation.target, list) else [relation.target]
770
+ )
771
+
772
+ # Setup flow
773
+ crew.task_flow(
774
+ source_agents if len(source_agents) > 1 else source_agents[0],
775
+ target_agents if len(target_agents) > 1 else target_agents[0]
776
+ )
777
+
778
+ return crew
779
+
780
+ def _get_agents_by_ids(
781
+ self,
782
+ crew: AgentCrew,
783
+ agent_ids: List[str]
784
+ ) -> List[Any]:
785
+ """
786
+ Get agent objects from crew by their IDs.
787
+
788
+ Args:
789
+ crew: AgentCrew instance
790
+ agent_ids: List of agent IDs
791
+
792
+ Returns:
793
+ List of agent objects
794
+ """
795
+ agents = []
796
+ for agent_id in agent_ids:
797
+ if agent := crew.agents.get(agent_id):
798
+ agents.append(agent)
799
+ else:
800
+ self.logger.warning(f"Agent '{agent_id}' not found in crew")
801
+ return agents