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,761 @@
1
+ """
2
+ FlowtaskToolkit for AI-Parrot - Execute Flowtask components and tasks dynamically.
3
+
4
+ This toolkit provides tools for:
5
+ - Running individual Flowtask components with custom input data
6
+ - Executing local Flowtask tasks
7
+ - Calling remote Flowtask API endpoints
8
+ - Running tasks from JSON/YAML code definitions
9
+ """
10
+ import os
11
+ import re
12
+ import io
13
+ import uuid
14
+ import json
15
+ import asyncio
16
+ import traceback
17
+ import importlib
18
+ from typing import Any, Dict, List, Optional, Union, Type
19
+ from enum import Enum
20
+ from contextlib import redirect_stdout
21
+ from pydantic import BaseModel, Field
22
+ import pandas as pd
23
+ from ..toolkit import AbstractToolkit
24
+ from ..decorators import tool_schema
25
+
26
+
27
+ # -----------------------------
28
+ # Input models (schemas)
29
+ # -----------------------------
30
+
31
+ class FlowtaskComponentInput(BaseModel):
32
+ """Input schema for component_call tool."""
33
+
34
+ component_name: str = Field(
35
+ description="Name of the Flowtask component to execute (e.g., 'GooglePlaces', 'GoogleGeoCoding')"
36
+ )
37
+
38
+ attributes: Dict[str, Any] = Field(
39
+ default_factory=dict,
40
+ description="Dictionary of attributes to pass to the component (e.g., {'use_proxies': True, 'type': 'traffic'})"
41
+ )
42
+
43
+ input_data: Union[Dict[str, Any], List[Dict[str, Any]], str] = Field(
44
+ description="Input data for the component - can be a dictionary, list of dictionaries, or JSON string"
45
+ )
46
+
47
+ structured_output: Optional[Dict[str, Any]] = Field(
48
+ default=None,
49
+ description="Optional structured output schema to format the results"
50
+ )
51
+
52
+ return_as_dataframe: bool = Field(
53
+ default=False,
54
+ description="Whether to return the result as a pandas DataFrame (if possible)"
55
+ )
56
+
57
+
58
+ class FlowtaskTaskExecutionInput(BaseModel):
59
+ """Input schema for task_execution tool."""
60
+
61
+ program: str = Field(
62
+ description="Program name/slug for the task (e.g., 'nextstop', 'test')"
63
+ )
64
+
65
+ task_name: str = Field(
66
+ description="Name of the task to execute (e.g., 'employees_report')"
67
+ )
68
+
69
+ debug: bool = Field(
70
+ default=True,
71
+ description="Whether to run in debug mode"
72
+ )
73
+
74
+
75
+ class FlowtaskRemoteExecutionInput(BaseModel):
76
+ """Input schema for remote_execution tool."""
77
+
78
+ program: str = Field(
79
+ description="Program name/slug for the task"
80
+ )
81
+
82
+ task_name: str = Field(
83
+ description="Name of the task to execute"
84
+ )
85
+
86
+ long_running: bool = Field(
87
+ default=False,
88
+ description="If True, task is enqueued and returns immediately with status. "
89
+ "If False, waits for task completion."
90
+ )
91
+
92
+ timeout: float = Field(
93
+ default=300.0,
94
+ description="Timeout in seconds for the API call (only applies when long_running=False)"
95
+ )
96
+
97
+ max_retries: int = Field(
98
+ default=3,
99
+ description="Maximum number of retry attempts on failure"
100
+ )
101
+
102
+ backoff_factor: float = Field(
103
+ default=1.0,
104
+ description="Backoff factor for exponential retry delay (delay = backoff_factor * 2^attempt)"
105
+ )
106
+
107
+
108
+ class TaskCodeFormat(str, Enum):
109
+ """Format of the task code."""
110
+ JSON = "json"
111
+ YAML = "yaml"
112
+
113
+
114
+ class FlowtaskCodeExecutionInput(BaseModel):
115
+ """Input schema for code_execution tool."""
116
+
117
+ task_code: str = Field(
118
+ description="The task definition as JSON or YAML string"
119
+ )
120
+
121
+ format: TaskCodeFormat = Field(
122
+ default=TaskCodeFormat.YAML,
123
+ description="Format of the task code: 'json' or 'yaml'"
124
+ )
125
+
126
+
127
+ # -----------------------------
128
+ # Toolkit implementation
129
+ # -----------------------------
130
+
131
+ class FlowtaskToolkit(AbstractToolkit):
132
+ """
133
+ Toolkit for executing Flowtask components and tasks dynamically.
134
+
135
+ This toolkit provides multiple tools for:
136
+ - Running individual Flowtask components with custom input data
137
+ - Executing local Flowtask tasks by program/task name
138
+ - Calling remote Flowtask API endpoints
139
+ - Running tasks from JSON/YAML code definitions
140
+
141
+ Example usage:
142
+ toolkit = FlowtaskToolkit()
143
+ tools = toolkit.get_tools()
144
+
145
+ # Execute a component
146
+ result = await toolkit.flowtask_component_call(
147
+ component_name="GooglePlaces",
148
+ input_data=[{"address": "123 Main St"}]
149
+ )
150
+
151
+ # Run a local task
152
+ result = await toolkit.flowtask_task_execution(
153
+ program="nextstop",
154
+ task_name="employees_report"
155
+ )
156
+ """
157
+
158
+ def __init__(self, **kwargs):
159
+ """Initialize the FlowtaskToolkit."""
160
+ super().__init__(**kwargs)
161
+
162
+ # Component cache to avoid repeated imports
163
+ self._component_cache: Dict[str, Type] = {}
164
+
165
+ # Known components (can be extended)
166
+ self.known_components = {
167
+ 'GooglePlaces',
168
+ }
169
+
170
+ # ANSI escape pattern for cleaning stdout
171
+ self._ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
172
+
173
+ # -----------------------------
174
+ # Helper methods
175
+ # -----------------------------
176
+
177
+ def _import_component(self, component_name: str) -> Type:
178
+ """
179
+ Dynamically import a Flowtask component.
180
+
181
+ Args:
182
+ component_name: Name of the component to import
183
+
184
+ Returns:
185
+ Component class
186
+
187
+ Raises:
188
+ ImportError: If component cannot be imported
189
+ """
190
+ # Check cache first
191
+ if component_name in self._component_cache:
192
+ return self._component_cache[component_name]
193
+
194
+ try:
195
+ # Import from flowtask.components
196
+ module_path = f"flowtask.components.{component_name}"
197
+ module = importlib.import_module(module_path)
198
+ component_class = getattr(module, component_name)
199
+
200
+ # Cache the component
201
+ self._component_cache[component_name] = component_class
202
+ return component_class
203
+
204
+ except ImportError as e:
205
+ raise ImportError(
206
+ f"Could not import component '{component_name}': {str(e)}"
207
+ )
208
+ except AttributeError as e:
209
+ raise ImportError(
210
+ f"Component '{component_name}' not found in module: {str(e)}"
211
+ )
212
+
213
+ def _prepare_input_data(
214
+ self,
215
+ input_data: Union[Dict, List, str]
216
+ ) -> Union[pd.DataFrame, Dict, List]:
217
+ """
218
+ Prepare input data for the component.
219
+
220
+ Args:
221
+ input_data: Raw input data
222
+
223
+ Returns:
224
+ Processed input data (DataFrame, dict, or list)
225
+ """
226
+ try:
227
+ # Handle string input (assume JSON)
228
+ if isinstance(input_data, str):
229
+ input_data = json.loads(input_data)
230
+
231
+ # Convert list of dictionaries to DataFrame
232
+ if isinstance(input_data, list) and len(input_data) > 0:
233
+ if isinstance(input_data[0], dict):
234
+ return pd.DataFrame(input_data)
235
+ else:
236
+ return input_data
237
+
238
+ # Convert dictionary to DataFrame if it has list values
239
+ if isinstance(input_data, dict):
240
+ if all(isinstance(v, list) for v in input_data.values()):
241
+ try:
242
+ return pd.DataFrame(input_data)
243
+ except ValueError:
244
+ return input_data
245
+ else:
246
+ # Single row dictionary
247
+ return pd.DataFrame([input_data])
248
+
249
+ return input_data
250
+
251
+ except Exception:
252
+ return input_data
253
+
254
+ def _format_output(
255
+ self,
256
+ result: Any,
257
+ structured_output: Optional[Dict[str, Any]] = None,
258
+ return_as_dataframe: bool = False
259
+ ) -> Any:
260
+ """
261
+ Format the component output according to specifications.
262
+
263
+ Args:
264
+ result: Raw component result
265
+ structured_output: Optional output structure
266
+ return_as_dataframe: Whether to return as DataFrame
267
+
268
+ Returns:
269
+ Formatted result
270
+ """
271
+ try:
272
+ # If result is already a DataFrame
273
+ if isinstance(result, pd.DataFrame):
274
+ if return_as_dataframe:
275
+ return {
276
+ "data": result.to_dict(orient='records'),
277
+ "columns": list(result.columns),
278
+ "shape": result.shape,
279
+ "type": "dataframe"
280
+ }
281
+ else:
282
+ return result.to_dict(orient='records')
283
+
284
+ # If result is a list and we want DataFrame format
285
+ if isinstance(result, list) and return_as_dataframe:
286
+ if result and isinstance(result[0], dict):
287
+ df = pd.DataFrame(result)
288
+ return {
289
+ "data": result,
290
+ "columns": list(df.columns),
291
+ "shape": df.shape,
292
+ "type": "dataframe"
293
+ }
294
+
295
+ # Apply structured output if specified
296
+ if structured_output:
297
+ return self._apply_structured_output(result, structured_output)
298
+
299
+ return result
300
+
301
+ except Exception:
302
+ return result
303
+
304
+ def _apply_structured_output(
305
+ self,
306
+ result: Any,
307
+ structure: Dict[str, Any]
308
+ ) -> Dict[str, Any]:
309
+ """
310
+ Apply structured output formatting to the result.
311
+
312
+ Args:
313
+ result: Raw result data
314
+ structure: Desired output structure
315
+
316
+ Returns:
317
+ Structured result
318
+ """
319
+ try:
320
+ if isinstance(result, pd.DataFrame):
321
+ data = result.to_dict(orient='records')
322
+ elif isinstance(result, list):
323
+ data = result
324
+ else:
325
+ data = [result] if not isinstance(result, list) else result
326
+
327
+ structured_result = {}
328
+ for key, mapping in structure.items():
329
+ if isinstance(mapping, str):
330
+ if isinstance(data, list) and data:
331
+ structured_result[key] = [
332
+ item.get(mapping) for item in data if isinstance(item, dict)
333
+ ]
334
+ else:
335
+ structured_result[key] = data.get(mapping) if isinstance(data, dict) else None
336
+ elif isinstance(mapping, dict):
337
+ structured_result[key] = self._apply_structured_output(data, mapping)
338
+ else:
339
+ structured_result[key] = mapping
340
+
341
+ return structured_result
342
+
343
+ except Exception:
344
+ return result
345
+
346
+ def _format_task_result(self, result: Any) -> Dict[str, Any]:
347
+ """
348
+ Format task execution result for consistent output.
349
+
350
+ Args:
351
+ result: Task execution result (typically DataFrame)
352
+
353
+ Returns:
354
+ Formatted result dictionary
355
+ """
356
+ if isinstance(result, pd.DataFrame):
357
+ return {
358
+ "type": "dataframe",
359
+ "data": result.to_dict(orient='records'),
360
+ "columns": list(result.columns),
361
+ "shape": list(result.shape),
362
+ "row_count": len(result)
363
+ }
364
+ elif isinstance(result, dict):
365
+ return {"type": "dict", "data": result}
366
+ elif isinstance(result, list):
367
+ return {"type": "list", "data": result, "count": len(result)}
368
+ else:
369
+ return {"type": type(result).__name__, "data": str(result)}
370
+
371
+ # -----------------------------
372
+ # Tools (public async methods)
373
+ # -----------------------------
374
+
375
+ @tool_schema(FlowtaskComponentInput)
376
+ async def flowtask_component_call(
377
+ self,
378
+ component_name: str,
379
+ input_data: Union[Dict[str, Any], List[Dict[str, Any]], str],
380
+ attributes: Optional[Dict[str, Any]] = None,
381
+ structured_output: Optional[Dict[str, Any]] = None,
382
+ return_as_dataframe: bool = False
383
+ ) -> Dict[str, Any]:
384
+ """
385
+ Execute a single Flowtask component with custom input data and attributes.
386
+
387
+ This tool imports and runs any Flowtask component dynamically, allowing
388
+ flexible data processing with custom configurations.
389
+
390
+ Example:
391
+ result = await flowtask_component_call(
392
+ component_name="GooglePlaces",
393
+ input_data=[{"address": "123 Main St"}],
394
+ attributes={"use_proxies": True}
395
+ )
396
+ """
397
+ attributes = attributes or {}
398
+
399
+ try:
400
+ # Import the component
401
+ component_cls = self._import_component(component_name)
402
+
403
+ # Prepare input data
404
+ processed_input = self._prepare_input_data(input_data)
405
+
406
+ # Create component instance with attributes
407
+ component_kwargs = attributes.copy()
408
+ component_kwargs['input'] = processed_input
409
+
410
+ try:
411
+ component = component_cls(**component_kwargs)
412
+ except TypeError as e:
413
+ return {
414
+ "status": "error",
415
+ "error": f"Failed to initialize component '{component_name}': {str(e)}",
416
+ "component_name": component_name
417
+ }
418
+
419
+ # Execute the component using async context manager
420
+ async with component as comp:
421
+ result = await comp.run()
422
+
423
+ # Format the output
424
+ formatted_result = self._format_output(
425
+ result,
426
+ structured_output,
427
+ return_as_dataframe
428
+ )
429
+
430
+ return {
431
+ "status": "success",
432
+ "result": formatted_result,
433
+ "metadata": {
434
+ "component_name": component_name,
435
+ "attributes": attributes,
436
+ "input_type": type(processed_input).__name__,
437
+ "output_type": type(result).__name__
438
+ }
439
+ }
440
+
441
+ except ImportError as e:
442
+ return {
443
+ "status": "error",
444
+ "error": str(e),
445
+ "component_name": component_name
446
+ }
447
+ except Exception as e:
448
+ return {
449
+ "status": "error",
450
+ "error": f"Failed to execute component '{component_name}': {str(e)}",
451
+ "error_type": type(e).__name__,
452
+ "component_name": component_name
453
+ }
454
+
455
+ @tool_schema(FlowtaskTaskExecutionInput)
456
+ async def flowtask_task_execution(
457
+ self,
458
+ program: str,
459
+ task_name: str,
460
+ debug: bool = True
461
+ ) -> Dict[str, Any]:
462
+ """
463
+ Execute a Flowtask Task locally by program and task name.
464
+
465
+ This runs the task using the local Flowtask Task instance,
466
+ which processes the DAG-based workflow defined in the task configuration.
467
+
468
+ Example:
469
+ result = await flowtask_task_execution(
470
+ program="nextstop",
471
+ task_name="employees_report",
472
+ debug=True
473
+ )
474
+ """
475
+ try:
476
+ from flowtask.tasks.task import Task
477
+
478
+ task = Task(program=program, task=task_name, debug=debug)
479
+
480
+ async with task as t:
481
+ result = await t.run()
482
+
483
+ return {
484
+ "status": "success",
485
+ "program": program,
486
+ "task": task_name,
487
+ "result": self._format_task_result(result)
488
+ }
489
+
490
+ except ImportError as e:
491
+ return {
492
+ "status": "error",
493
+ "error": f"Flowtask not installed or import error: {str(e)}",
494
+ "program": program,
495
+ "task": task_name
496
+ }
497
+ except Exception as e:
498
+ return {
499
+ "status": "error",
500
+ "error": str(e),
501
+ "error_type": type(e).__name__,
502
+ "program": program,
503
+ "task": task_name
504
+ }
505
+
506
+ @tool_schema(FlowtaskRemoteExecutionInput)
507
+ async def flowtask_remote_execution(
508
+ self,
509
+ program: str,
510
+ task_name: str,
511
+ long_running: bool = False,
512
+ timeout: float = 300.0,
513
+ max_retries: int = 3,
514
+ backoff_factor: float = 1.0
515
+ ) -> Dict[str, Any]:
516
+ """
517
+ Execute a Flowtask Task remotely via the Flowtask API.
518
+
519
+ Calls the Flowtask API endpoint to run a task. If long_running is True,
520
+ the task is enqueued and returns immediately with status. Otherwise,
521
+ waits for task completion.
522
+
523
+ Uses exponential backoff retry on transient failures.
524
+
525
+ Example:
526
+ result = await flowtask_remote_execution(
527
+ program="nextstop",
528
+ task_name="employees_report",
529
+ long_running=False,
530
+ timeout=600.0
531
+ )
532
+ """
533
+ try:
534
+ import httpx
535
+ except ImportError:
536
+ return {
537
+ "status": "error",
538
+ "error": "httpx package not installed. Install with: pip install httpx"
539
+ }
540
+
541
+ # Get TASK_DOMAIN from environment - required
542
+ task_domain = os.getenv("TASK_DOMAIN")
543
+ if not task_domain:
544
+ return {
545
+ "status": "error",
546
+ "error": "TASK_DOMAIN environment variable is not set. "
547
+ "Please set it to the Flowtask API base URL."
548
+ }
549
+
550
+ url = f"{task_domain.rstrip('/')}/api/v2/task/{program}/{task_name}"
551
+ payload = {"long_running": long_running}
552
+
553
+ last_error = None
554
+
555
+ for attempt in range(max_retries):
556
+ try:
557
+ async with httpx.AsyncClient(timeout=timeout) as client:
558
+ response = await client.post(url, json=payload)
559
+
560
+ # Handle different response codes
561
+ if response.status_code == 200:
562
+ return {
563
+ "status": "success",
564
+ "program": program,
565
+ "task": task_name,
566
+ "response": response.json()
567
+ }
568
+ elif response.status_code == 202:
569
+ # Task queued (long_running=True)
570
+ return {
571
+ "status": "queued",
572
+ "program": program,
573
+ "task": task_name,
574
+ "response": response.json()
575
+ }
576
+ elif response.status_code == 400:
577
+ # Task execution error
578
+ return {
579
+ "status": "task_error",
580
+ "program": program,
581
+ "task": task_name,
582
+ "response": response.json()
583
+ }
584
+ elif response.status_code == 406:
585
+ # Result not acceptable (known Flowtask bug)
586
+ return {
587
+ "status": "result_error",
588
+ "program": program,
589
+ "task": task_name,
590
+ "response": response.json(),
591
+ "note": "406 error - result data format issue (known Flowtask behavior)"
592
+ }
593
+ else:
594
+ # Other errors - may be transient, retry
595
+ last_error = f"HTTP {response.status_code}: {response.text}"
596
+ if attempt < max_retries - 1:
597
+ delay = backoff_factor * (2 ** attempt)
598
+ await asyncio.sleep(delay)
599
+ continue
600
+ return {
601
+ "status": "error",
602
+ "error": last_error,
603
+ "program": program,
604
+ "task": task_name
605
+ }
606
+
607
+ except httpx.TimeoutException:
608
+ last_error = f"Request timed out after {timeout} seconds"
609
+ if attempt < max_retries - 1:
610
+ delay = backoff_factor * (2 ** attempt)
611
+ await asyncio.sleep(delay)
612
+ continue
613
+
614
+ except httpx.RequestError as e:
615
+ last_error = f"Request error: {str(e)}"
616
+ if attempt < max_retries - 1:
617
+ delay = backoff_factor * (2 ** attempt)
618
+ await asyncio.sleep(delay)
619
+ continue
620
+
621
+ return {
622
+ "status": "error",
623
+ "error": last_error or "Max retries exceeded",
624
+ "program": program,
625
+ "task": task_name,
626
+ "retries": max_retries
627
+ }
628
+
629
+ @tool_schema(FlowtaskCodeExecutionInput)
630
+ async def flowtask_code_execution(
631
+ self,
632
+ task_code: str,
633
+ format: TaskCodeFormat = TaskCodeFormat.YAML
634
+ ) -> Dict[str, Any]:
635
+ """
636
+ Execute a Flowtask Task from a JSON or YAML code definition.
637
+
638
+ This allows running ad-hoc task definitions without requiring them to be
639
+ saved as files. The task code should follow the standard Flowtask task
640
+ definition format with name, description, and steps.
641
+
642
+ Example:
643
+ result = await flowtask_code_execution(
644
+ task_code='''
645
+ name: My Task
646
+ steps:
647
+ - GooglePlaces:
648
+ input: [{"address": "123 Main St"}]
649
+ ''',
650
+ format="yaml"
651
+ )
652
+ """
653
+ try:
654
+ from flowtask.storages import MemoryTaskStorage
655
+ from flowtask.tasks.task import Task
656
+ except ImportError as e:
657
+ return {
658
+ "status": "error",
659
+ "error": f"Flowtask not installed or import error: {str(e)}"
660
+ }
661
+
662
+ # Parse task code
663
+ try:
664
+ if format == TaskCodeFormat.YAML or format == "yaml":
665
+ import yaml
666
+ body_task = yaml.safe_load(task_code)
667
+ else:
668
+ body_task = json.loads(task_code)
669
+ except Exception as e:
670
+ return {
671
+ "status": "error",
672
+ "error": f"Failed to parse task code as {format}: {str(e)}"
673
+ }
674
+
675
+ task_id = str(uuid.uuid4())
676
+ error = None
677
+ stacktrace = None
678
+ captured_stdout = None
679
+ stats = None
680
+ result = None
681
+
682
+ try:
683
+ task = Task(task=task_id)
684
+
685
+ async with task as t:
686
+ t.taskstore = MemoryTaskStorage()
687
+ stdout = io.StringIO()
688
+
689
+ if await t.start(payload=body_task):
690
+ try:
691
+ with redirect_stdout(stdout):
692
+ result = await t.run()
693
+ except Exception as e:
694
+ result = None
695
+ stacktrace = traceback.format_exc()
696
+ error = str(e)
697
+
698
+ captured_stdout = stdout.getvalue()
699
+ stats = t.get_stats()
700
+ else:
701
+ error = "Failed to start task with provided payload"
702
+
703
+ except Exception as e:
704
+ error = str(e)
705
+ stacktrace = traceback.format_exc()
706
+
707
+ # Clean ANSI escape codes from stdout
708
+ clean_stdout = None
709
+ if captured_stdout:
710
+ clean_stdout = self._ansi_escape.sub('', captured_stdout)
711
+
712
+ return {
713
+ "status": "success" if error is None else "error",
714
+ "task_id": task_id,
715
+ "result": self._format_task_result(result) if result is not None else None,
716
+ "error": error,
717
+ "stacktrace": stacktrace,
718
+ "stdout": clean_stdout,
719
+ "stats": stats
720
+ }
721
+
722
+ # -----------------------------
723
+ # Utility methods
724
+ # -----------------------------
725
+
726
+ def list_known_components(self) -> List[str]:
727
+ """
728
+ Get a list of known Flowtask components.
729
+
730
+ Returns:
731
+ List of component names
732
+ """
733
+ return sorted(list(self.known_components))
734
+
735
+ def add_known_component(self, component_name: str) -> None:
736
+ """
737
+ Add a component to the known components list.
738
+
739
+ Args:
740
+ component_name: Name of the component to add
741
+ """
742
+ self.known_components.add(component_name)
743
+
744
+ def clear_component_cache(self) -> None:
745
+ """Clear the component import cache."""
746
+ self._component_cache.clear()
747
+
748
+
749
+ # Backward compatibility alias
750
+ FlowtaskTool = FlowtaskToolkit
751
+
752
+
753
+ __all__ = [
754
+ "FlowtaskToolkit",
755
+ "FlowtaskTool", # Backward compatibility
756
+ "FlowtaskComponentInput",
757
+ "FlowtaskTaskExecutionInput",
758
+ "FlowtaskRemoteExecutionInput",
759
+ "FlowtaskCodeExecutionInput",
760
+ "TaskCodeFormat",
761
+ ]