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,627 @@
1
+ """
2
+ JobManagerMixin: A mixin class to add asynchronous job execution capabilities to views.
3
+
4
+ This mixin provides:
5
+ - A decorator to enqueue functions to be executed by a job manager
6
+ - GET method override to check and retrieve job results by job_id
7
+ """
8
+ from typing import Any, Callable, Optional, Dict, Awaitable
9
+ import functools
10
+ import inspect
11
+ import asyncio
12
+ from aiohttp import web
13
+ from .job import JobManager
14
+
15
+
16
+ class JobManagerMixin:
17
+ """
18
+ Mixin class to add job manager functionality to any BaseView.
19
+
20
+ This mixin allows view methods to be executed asynchronously via a job manager,
21
+ and provides automatic handling of job status/result retrieval via GET requests.
22
+
23
+ Attributes:
24
+ job_manager: An instance of JobManager that handles async job execution
25
+ job_id_param: The query parameter name for job IDs (default: 'job_id')
26
+ """
27
+
28
+ job_manager: Optional[Any] = None
29
+ job_id_param: str = "job_id"
30
+
31
+ def __init__(self, *args, **kwargs):
32
+ """Initialize the mixin with job manager instance."""
33
+ super().__init__(*args, **kwargs)
34
+ if not hasattr(self, 'job_manager') or self.job_manager is None:
35
+ raise ValueError(
36
+ "JobManagerMixin requires a 'job_manager' attribute. "
37
+ "Please set it in your view class."
38
+ )
39
+
40
+ @staticmethod
41
+ def as_job(
42
+ queue: str = "default",
43
+ timeout: Optional[int] = None,
44
+ result_ttl: Optional[int] = 500,
45
+ return_job_id: bool = True
46
+ ) -> Callable:
47
+ """
48
+ Decorator to enqueue a method to be executed by the job manager.
49
+
50
+ Args:
51
+ queue: The queue name for job execution (default: 'default')
52
+ timeout: Maximum execution time in seconds
53
+ result_ttl: Time to live for job results in seconds
54
+ return_job_id: If True, returns job_id; if False, returns job result
55
+
56
+ Returns:
57
+ Decorated function that enqueues the job and returns job_id
58
+
59
+ Example:
60
+ @JobManagerMixin.as_job(queue="ml_tasks", timeout=3600)
61
+ def process_large_dataset(self, request):
62
+ # This will be executed asynchronously
63
+ result = heavy_computation()
64
+ return result
65
+ """
66
+ def decorator(func: Callable) -> Callable:
67
+ @functools.wraps(func)
68
+ def wrapper(self_arg, *args, **kwargs):
69
+ # self_arg is the instance (self)
70
+ instance = self_arg
71
+
72
+ # Extract request object if present in args
73
+ request = None
74
+ if args and hasattr(args[0], 'GET'):
75
+ request = args[0]
76
+
77
+ # Enqueue the job with all arguments including self
78
+ job = instance.job_manager.enqueue(
79
+ func,
80
+ args=(self_arg,) + args, # Include self in args
81
+ kwargs=kwargs,
82
+ queue=queue,
83
+ timeout=timeout,
84
+ result_ttl=result_ttl
85
+ )
86
+
87
+ # Store job metadata
88
+ job_metadata = {
89
+ 'job_id': job.id,
90
+ 'queue': queue,
91
+ 'function': func.__name__,
92
+ 'status': 'enqueued'
93
+ }
94
+
95
+ if return_job_id:
96
+ return instance._create_job_response(job_metadata, request)
97
+ else:
98
+ # Wait for job to complete and return result
99
+ return job.result
100
+
101
+ # Mark function as async job
102
+ wrapper._is_async_job = True
103
+ wrapper._job_config = {
104
+ 'queue': queue,
105
+ 'timeout': timeout,
106
+ 'result_ttl': result_ttl
107
+ }
108
+
109
+ return wrapper
110
+ return decorator
111
+
112
+ def get(self, request, *args, **kwargs):
113
+ """
114
+ Override GET method to handle job_id parameter.
115
+
116
+ If request contains job_id parameter, retrieves and returns job status/result.
117
+ Otherwise, delegates to the original GET method of the view.
118
+
119
+ Args:
120
+ request: The HTTP request object
121
+ *args: Additional positional arguments
122
+ **kwargs: Additional keyword arguments
123
+
124
+ Returns:
125
+ Job status/result if job_id is present, otherwise original GET response
126
+ """
127
+ if (job_id := self._get_job_id_from_request(request)):
128
+ return self._handle_job_status_request(job_id, request)
129
+
130
+ # Call the original GET method if it exists
131
+ if hasattr(super(), 'get'):
132
+ return super().get(request, *args, **kwargs)
133
+ else:
134
+ return self._default_get_response(request)
135
+
136
+ def _get_job_id_from_request(self, request) -> Optional[str]:
137
+ """
138
+ Extract job_id from request parameters.
139
+
140
+ Checks both query parameters (GET) and request data (POST).
141
+
142
+ Args:
143
+ request: The HTTP request object
144
+
145
+ Returns:
146
+ job_id string if found, None otherwise
147
+ """
148
+ # Check GET parameters
149
+ if hasattr(request, 'GET') and self.job_id_param in request.GET:
150
+ return request.GET.get(self.job_id_param)
151
+
152
+ # Check POST/request data
153
+ if hasattr(request, 'data') and self.job_id_param in request.data:
154
+ return request.data.get(self.job_id_param)
155
+
156
+ return None
157
+
158
+ def _handle_job_status_request(self, job_id: str, request) -> Dict[str, Any]:
159
+ """
160
+ Handle request for job status and results.
161
+
162
+ Args:
163
+ job_id: The unique job identifier
164
+ request: The HTTP request object
165
+
166
+ Returns:
167
+ Dictionary containing job status, result, or error information
168
+ """
169
+ try:
170
+ job = self.job_manager.fetch_job(job_id)
171
+
172
+ if job is None:
173
+ return self._create_error_response(
174
+ f"Job with id '{job_id}' not found",
175
+ status_code=404
176
+ )
177
+
178
+ job_status = {
179
+ 'job_id': job.id,
180
+ 'status': job.get_status(),
181
+ 'created_at': str(job.created_at) if hasattr(job, 'created_at') else None,
182
+ 'started_at': str(job.started_at) if hasattr(job, 'started_at') else None,
183
+ 'ended_at': str(job.ended_at) if hasattr(job, 'ended_at') else None,
184
+ }
185
+
186
+ # Add result if job is finished
187
+ if job.is_finished:
188
+ job_status['result'] = job.result
189
+ job_status['success'] = True
190
+
191
+ # Add error if job failed
192
+ elif job.is_failed:
193
+ job_status['error'] = str(job.exc_info) if hasattr(job, 'exc_info') else "Unknown error"
194
+ job_status['success'] = False
195
+
196
+ # Job is still in progress
197
+ else:
198
+ job_status['message'] = "Job is still in progress"
199
+ job_status['progress'] = job.meta.get('progress') if hasattr(job, 'meta') else None
200
+
201
+ return self._create_success_response(job_status)
202
+
203
+ except Exception as e:
204
+ return self._create_error_response(
205
+ f"Error fetching job: {str(e)}",
206
+ status_code=500
207
+ )
208
+
209
+ def _create_job_response(
210
+ self,
211
+ job_metadata: Dict[str, Any],
212
+ request
213
+ ) -> Dict[str, Any]:
214
+ """
215
+ Create standardized response for job creation.
216
+
217
+ Args:
218
+ job_metadata: Dictionary containing job information
219
+ request: The HTTP request object
220
+
221
+ Returns:
222
+ Formatted response with job details and status URL
223
+ """
224
+ response = {
225
+ 'success': True,
226
+ 'job_id': job_metadata['job_id'],
227
+ 'status': job_metadata['status'],
228
+ 'message': f"Job enqueued successfully on queue '{job_metadata['queue']}'",
229
+ }
230
+
231
+ # Add status URL if request is available
232
+ if request and hasattr(request, 'build_absolute_uri'):
233
+ status_url = self._build_status_url(request, job_metadata['job_id'])
234
+ response['status_url'] = status_url
235
+
236
+ return response
237
+
238
+ def _build_status_url(self, request, job_id: str) -> str:
239
+ """
240
+ Build URL for checking job status.
241
+
242
+ Args:
243
+ request: The HTTP request object
244
+ job_id: The unique job identifier
245
+
246
+ Returns:
247
+ Full URL for job status endpoint
248
+ """
249
+ base_url = request.build_absolute_uri(request.path)
250
+ separator = '&' if '?' in base_url else '?'
251
+ return f"{base_url}{separator}{self.job_id_param}={job_id}"
252
+
253
+ def _create_success_response(self, data: Dict[str, Any]) -> Dict[str, Any]:
254
+ """Create standardized success response."""
255
+ return {
256
+ 'success': True,
257
+ **data
258
+ }
259
+
260
+ def _create_error_response(
261
+ self,
262
+ message: str,
263
+ status_code: int = 400
264
+ ) -> Dict[str, Any]:
265
+ """Create standardized error response."""
266
+ return {
267
+ 'success': False,
268
+ 'error': message,
269
+ 'status_code': status_code
270
+ }
271
+
272
+ def _default_get_response(self, request) -> Dict[str, Any]:
273
+ """Default GET response when no job_id is provided and no parent GET exists."""
274
+ return {
275
+ 'message': 'No job_id provided. Use POST to create jobs or GET with job_id to check status.',
276
+ 'usage': {
277
+ 'create_job': 'POST to endpoint with required parameters',
278
+ 'check_status': f'GET to endpoint with ?{self.job_id_param}=<job_id>'
279
+ }
280
+ }
281
+
282
+ @classmethod
283
+ def get_async_methods(cls) -> Dict[str, Dict[str, Any]]:
284
+ """
285
+ Get all methods decorated with @as_job in the class.
286
+
287
+ Returns:
288
+ Dictionary mapping method names to their job configurations
289
+ """
290
+ return {
291
+ name: method._job_config
292
+ for name, method in inspect.getmembers(
293
+ cls, predicate=inspect.isfunction
294
+ )
295
+ if hasattr(method, '_is_async_job') and method._is_async_job
296
+ }
297
+
298
+
299
+ class AsyncJobManagerMixin:
300
+ """
301
+ Async-native mixin for aiohttp views with job manager functionality.
302
+
303
+ Unlike the sync JobManagerMixin (designed for RQ), this version:
304
+ - Works natively with aiohttp's async request handlers
305
+ - Supports both your asyncio JobManager and RQ Queue
306
+ - Provides async get() method
307
+ - Handles aiohttp request objects
308
+
309
+ Usage with aiohttp:
310
+ class MyView(AsyncJobManagerMixin, web.View):
311
+ def __init__(self, request):
312
+ super().__init__(request)
313
+ # Use either RQ Queue or adapted JobManager
314
+ self.job_manager = request.app['job_queue']
315
+
316
+ @AsyncJobManagerMixin.as_job(queue="tasks", timeout=3600)
317
+ async def post(self):
318
+ # Your async handler
319
+ return {"result": "success"}
320
+
321
+ async def get(self):
322
+ # Automatically handles job_id parameter
323
+ return await super().get()
324
+ """
325
+
326
+ job_manager: Optional[Any] = None
327
+ job_id_param: str = "job_id"
328
+
329
+ def __init__(self, *args, **kwargs):
330
+ """Initialize the mixin."""
331
+ super().__init__(*args, **kwargs)
332
+
333
+ def _get_jobmanager(self, request: web.Request) -> Any:
334
+ """
335
+ Retrieve the job manager from the aiohttp request.
336
+
337
+ Args:
338
+ request: aiohttp Request object
339
+ Returns:
340
+ Job manager instance (RQ Queue or your JobManager)
341
+ """
342
+ return request.app['job_manager'] if 'job_manager' in request.app else JobManager()
343
+
344
+ @staticmethod
345
+ def as_job(
346
+ queue: str = "default",
347
+ timeout: Optional[int] = None,
348
+ result_ttl: Optional[int] = 500,
349
+ return_job_id: bool = True,
350
+ async_execution: bool = True
351
+ ) -> Callable:
352
+ """
353
+ Decorator to enqueue an async method for job execution.
354
+
355
+ Args:
356
+ queue: Queue name for job execution
357
+ timeout: Maximum execution time in seconds
358
+ result_ttl: Time to live for job results
359
+ return_job_id: If True, returns job_id immediately
360
+ async_execution: If True, expects async function
361
+
362
+ Returns:
363
+ Decorated async function
364
+
365
+ Example:
366
+ @AsyncJobManagerMixin.as_job(queue="ml_tasks", timeout=3600)
367
+ async def process_data(self):
368
+ # This executes asynchronously
369
+ result = await heavy_computation()
370
+ return result
371
+ """
372
+ def decorator(func: Callable) -> Callable:
373
+ @functools.wraps(func)
374
+ async def async_wrapper(self_arg, *args, **kwargs):
375
+ instance = self_arg
376
+
377
+ if not hasattr(instance, 'job_manager') or instance.job_manager is None:
378
+ raise ValueError(
379
+ "job_manager not set. Set it in your view's __init__ method."
380
+ )
381
+
382
+ # Extract request if available
383
+ request = None
384
+ if hasattr(instance, 'request'):
385
+ request = instance.request
386
+ elif args and isinstance(args[0], web.Request):
387
+ request = args[0]
388
+
389
+ # Enqueue the job
390
+ job = instance.job_manager.enqueue(
391
+ func,
392
+ args=(self_arg,) + args,
393
+ kwargs=kwargs,
394
+ queue=queue,
395
+ timeout=timeout,
396
+ result_ttl=result_ttl
397
+ )
398
+
399
+ # Create job metadata
400
+ job_metadata = {
401
+ 'job_id': job.id,
402
+ 'queue': queue,
403
+ 'function': func.__name__,
404
+ 'status': 'enqueued'
405
+ }
406
+
407
+ if return_job_id:
408
+ response_data = instance._create_job_response(job_metadata, request)
409
+ return web.json_response(response_data)
410
+ else:
411
+ # Wait for job to complete
412
+ # This is async-friendly
413
+ while not (job.is_finished or job.is_failed):
414
+ await asyncio.sleep(0.1)
415
+ job.refresh() if hasattr(job, 'refresh') else None
416
+
417
+ if job.is_failed:
418
+ return web.json_response(
419
+ {'error': str(job.exc_info)},
420
+ status=500
421
+ )
422
+ return web.json_response({'result': job.result})
423
+
424
+ # Mark as async job
425
+ async_wrapper._is_async_job = True
426
+ async_wrapper._job_config = {
427
+ 'queue': queue,
428
+ 'timeout': timeout,
429
+ 'result_ttl': result_ttl,
430
+ 'async': async_execution
431
+ }
432
+
433
+ return async_wrapper
434
+ return decorator
435
+
436
+ async def get(self) -> web.Response:
437
+ """
438
+ Async GET method to handle job status requests.
439
+
440
+ If request contains job_id parameter, returns job status/result.
441
+ Otherwise, delegates to parent GET method or returns default response.
442
+
443
+ Returns:
444
+ web.Response with job status or default response
445
+ """
446
+ # Get request object
447
+ request = self.request if hasattr(self, 'request') else None
448
+
449
+ if not request:
450
+ return web.json_response({
451
+ 'error': 'Request object not available'
452
+ }, status=500)
453
+
454
+ # Check for job_id parameter
455
+ if (job_id := self._get_job_id_from_request(request)):
456
+ response_data = await self._handle_job_status_request(job_id, request)
457
+ status_code = response_data.pop('status_code', 200)
458
+ return web.json_response(response_data, status=status_code)
459
+
460
+ # Call parent get if it exists
461
+ if hasattr(super(), 'get'):
462
+ return await super().get()
463
+
464
+ # Return default response
465
+ return web.json_response(self._default_get_response(request))
466
+
467
+ def _get_job_id_from_request(self, request: web.Request) -> Optional[str]:
468
+ """
469
+ Extract job_id from aiohttp request.
470
+
471
+ Args:
472
+ request: aiohttp Request object
473
+
474
+ Returns:
475
+ job_id if found, None otherwise
476
+ """
477
+ # Check query parameters
478
+ if self.job_id_param in request.query:
479
+ return request.query.get(self.job_id_param)
480
+
481
+ # Check match_info (URL path parameters)
482
+ if self.job_id_param in request.match_info:
483
+ return request.match_info.get(self.job_id_param)
484
+
485
+ return None
486
+
487
+ async def _handle_job_status_request(
488
+ self,
489
+ job_id: str,
490
+ request: web.Request
491
+ ) -> Dict[str, Any]:
492
+ """
493
+ Handle async job status request.
494
+
495
+ Args:
496
+ job_id: Job identifier
497
+ request: aiohttp Request object
498
+
499
+ Returns:
500
+ Dictionary with job status/result
501
+ """
502
+ try:
503
+ # Fetch job (works with both RQ and your JobManager)
504
+ job = self.job_manager.fetch_job(job_id)
505
+
506
+ if job is None:
507
+ return {
508
+ 'success': False,
509
+ 'error': f"Job with id '{job_id}' not found",
510
+ 'status_code': 404
511
+ }
512
+
513
+ # Build status response
514
+ job_status = {
515
+ 'job_id': job.id,
516
+ 'status': job.get_status(),
517
+ 'created_at': str(job.created_at) if hasattr(job, 'created_at') else None,
518
+ 'started_at': str(job.started_at) if hasattr(job, 'started_at') else None,
519
+ 'ended_at': str(job.ended_at) if hasattr(job, 'ended_at') else None,
520
+ }
521
+
522
+ # Add elapsed time if available
523
+ if hasattr(job, 'elapsed_time') and job.elapsed_time:
524
+ job_status['elapsed_time'] = job.elapsed_time
525
+
526
+ # Handle completed jobs
527
+ if job.is_finished:
528
+ job_status['result'] = job.result
529
+ job_status['success'] = True
530
+
531
+ # Handle failed jobs
532
+ elif job.is_failed:
533
+ job_status['error'] = str(job.exc_info) if hasattr(job, 'exc_info') else "Unknown error"
534
+ job_status['success'] = False
535
+
536
+ # Job still in progress
537
+ else:
538
+ job_status['message'] = "Job is still in progress"
539
+ if hasattr(job, 'meta'):
540
+ job_status['progress'] = job.meta.get('progress')
541
+
542
+ return self._create_success_response(job_status)
543
+
544
+ except Exception as e:
545
+ return {
546
+ 'success': False,
547
+ 'error': f"Error fetching job: {str(e)}",
548
+ 'status_code': 500
549
+ }
550
+
551
+ def _create_job_response(
552
+ self,
553
+ job_metadata: Dict[str, Any],
554
+ request: Optional[web.Request]
555
+ ) -> Dict[str, Any]:
556
+ """
557
+ Create standardized job creation response for aiohttp.
558
+
559
+ Args:
560
+ job_metadata: Job information
561
+ request: aiohttp Request object
562
+
563
+ Returns:
564
+ Response dictionary
565
+ """
566
+ response = {
567
+ 'success': True,
568
+ 'job_id': job_metadata['job_id'],
569
+ 'status': job_metadata['status'],
570
+ 'message': f"Job enqueued successfully on queue '{job_metadata['queue']}'",
571
+ }
572
+
573
+ # Add status URL
574
+ if request:
575
+ status_url = self._build_status_url(request, job_metadata['job_id'])
576
+ response['status_url'] = status_url
577
+
578
+ return response
579
+
580
+ def _build_status_url(self, request: web.Request, job_id: str) -> str:
581
+ """
582
+ Build status URL for aiohttp request.
583
+
584
+ Args:
585
+ request: aiohttp Request object
586
+ job_id: Job identifier
587
+
588
+ Returns:
589
+ Full URL for checking job status
590
+ """
591
+ # Build URL with job_id parameter
592
+ scheme = request.scheme
593
+ host = request.host
594
+ path = request.path
595
+
596
+ return f"{scheme}://{host}{path}?{self.job_id_param}={job_id}"
597
+
598
+ def _create_success_response(self, data: Dict[str, Any]) -> Dict[str, Any]:
599
+ """Create standardized success response."""
600
+ return {
601
+ 'success': True,
602
+ **data
603
+ }
604
+
605
+ def _default_get_response(self, request: web.Request) -> Dict[str, Any]:
606
+ """Default GET response for aiohttp."""
607
+ return {
608
+ 'message': 'No job_id provided. Use POST to create jobs or GET with job_id to check status.',
609
+ 'usage': {
610
+ 'create_job': f'POST to {request.path}',
611
+ 'check_status': f'GET to {request.path}?{self.job_id_param}=<job_id>'
612
+ }
613
+ }
614
+
615
+ @classmethod
616
+ def get_async_methods(cls) -> Dict[str, Dict[str, Any]]:
617
+ """
618
+ Get all methods decorated with @as_job.
619
+
620
+ Returns:
621
+ Dictionary mapping method names to configurations
622
+ """
623
+ return {
624
+ name: method._job_config
625
+ for name, method in inspect.getmembers(cls)
626
+ if (hasattr(method, '_is_async_job') and method._is_async_job)
627
+ }