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,408 @@
1
+ from typing import Any, Dict, List, Optional
2
+ import time
3
+ import shutil
4
+ from pathlib import Path
5
+ import shlex
6
+ from .models import BaseAction, ActionResult
7
+
8
+ # ---------- Concrete actions ----------
9
+
10
+ class RunCommand(BaseAction):
11
+ """Run a shell command via /bin/sh -lc 'command'."""
12
+ async def _run_impl(self) -> ActionResult:
13
+ # Allow complex commands (with pipes, redirects) by invoking through /bin/sh -lc
14
+ argv = ["/bin/sh", "-lc", self.cmd]
15
+ return await self._run_subprocess(argv)
16
+
17
+ class ExecFile(BaseAction):
18
+ """Execute a file/script via /bin/sh {file_or_cmd}."""
19
+ async def _run_impl(self) -> ActionResult:
20
+ # Execute a file/script via /bin/sh {file_or_cmd}
21
+ argv = ["/bin/sh", self.cmd]
22
+ return await self._run_subprocess(argv)
23
+
24
+ class ListFiles(BaseAction):
25
+ """List files in a directory, optionally with flags/args."""
26
+ async def _run_impl(self) -> ActionResult:
27
+ # Simple 'ls' wrapper that accepts the rest of the command flags/args
28
+ parts = shlex.split(self.cmd) if self.cmd else []
29
+ if not parts:
30
+ parts = ["ls", "-la"]
31
+ elif parts[0] != "ls":
32
+ parts = ["ls"] + parts
33
+ argv = parts
34
+ return await self._run_subprocess(argv)
35
+
36
+ class CheckExists(BaseAction):
37
+ """Check if a file/directory exists."""
38
+ async def _run_impl(self) -> ActionResult:
39
+ started = time.time()
40
+ target = self.cmd.strip() or "."
41
+ p = Path(self.work_dir) / target
42
+ exists = p.exists()
43
+ ended = time.time()
44
+ msg = f"EXISTS: {exists} PATH: {str(p)}"
45
+ return ActionResult(
46
+ ok=True,
47
+ exit_code=0 if exists else 1,
48
+ stdout=msg + "\n",
49
+ stderr="",
50
+ started_at=started,
51
+ ended_at=ended,
52
+ duration=ended-started,
53
+ cmd=f"check_exists {target}",
54
+ work_dir=self.work_dir,
55
+ metadata={"exists": exists, "path": str(p)},
56
+ type="check_exists"
57
+ )
58
+
59
+ class ReadFile(BaseAction):
60
+ """Read a file's content, with optional max bytes and encoding."""
61
+ async def _run_impl(self) -> ActionResult:
62
+ started = time.time()
63
+ parts = shlex.split(self.cmd) if self.cmd else []
64
+ target = parts[0] if parts else ""
65
+ p = Path(self.work_dir) / target
66
+ stdout = ""
67
+ stderr = ""
68
+ ok = False
69
+ exit_code = 1
70
+ meta: Dict[str, Any] = {}
71
+ try:
72
+ data = p.read_bytes()
73
+ meta["size"] = len(data)
74
+ max_bytes = None
75
+ if len(parts) > 1:
76
+ # allow "read_file <path> --max N --encoding utf-8"
77
+ # but also support injected settings via metadata; primary path below
78
+ pass
79
+ # Prefer explicit metadata carried on BaseAction via .metadata? keep simple:
80
+ # We'll parse from self.cmd like: "file.txt"
81
+ max_bytes = self.metadata.get("max_bytes") if hasattr(self, "metadata") else None # not set in v1
82
+ # Instead, ReadFile Action will be constructed with self.cmd=path, and we pass options via subclass creation
83
+ # To keep v1 simple: rely on wrapper to limit bytes
84
+ # (we'll set these on the instance attributes for now)
85
+ except Exception as e:
86
+ stderr = f"{type(e).__name__}: {e}\n"
87
+ else:
88
+ # attributes set by wrapper
89
+ try:
90
+ max_b = getattr(self, "_max_bytes", None)
91
+ enc = getattr(self, "_encoding", "utf-8")
92
+ if max_b is not None:
93
+ data = data[:int(max_b)]
94
+ meta["truncated_to"] = int(max_b)
95
+ try:
96
+ stdout = data.decode(enc, errors="replace")
97
+ except Exception:
98
+ # If decoding fails, return as raw bytes repr
99
+ stdout = data.decode("utf-8", errors="replace")
100
+ meta["encoding_used"] = "utf-8 (fallback)"
101
+ else:
102
+ meta["encoding_used"] = enc
103
+ ok = True
104
+ exit_code = 0
105
+ except Exception as e:
106
+ stderr = f"{type(e).__name__}: {e}\n"
107
+
108
+ ended = time.time()
109
+ return ActionResult(
110
+ ok=ok or self.ignore_errors,
111
+ exit_code=exit_code,
112
+ stdout=stdout,
113
+ stderr=stderr,
114
+ started_at=started,
115
+ ended_at=ended,
116
+ duration=ended-started,
117
+ cmd=f"read_file {target}",
118
+ work_dir=self.work_dir,
119
+ metadata=meta,
120
+ type="read_file"
121
+ )
122
+
123
+ # Note: other actions can be added here, e.g., WriteFile, MoveFile, etc.
124
+ class WriteFile(BaseAction):
125
+ """
126
+ Writes text content to a file relative to work_dir.
127
+ Options:
128
+ - append: append instead of overwrite
129
+ - make_dirs: create parent dirs
130
+ - encoding: text encoding
131
+ """
132
+ def __init__(
133
+ self,
134
+ *,
135
+ path: str,
136
+ content: str,
137
+ encoding: str = "utf-8",
138
+ append: bool = False,
139
+ make_dirs: bool = True,
140
+ overwrite: bool = True,
141
+ work_dir: Optional[str] = None,
142
+ ignore_errors: Optional[bool] = None,
143
+ ):
144
+ super().__init__(type_name="write_file", work_dir=work_dir, ignore_errors=ignore_errors)
145
+ self._path = path
146
+ self._content = content or ""
147
+ self._encoding = encoding or "utf-8"
148
+ self._append = bool(append)
149
+ self._make_dirs = bool(make_dirs)
150
+ self._overwrite = bool(overwrite)
151
+
152
+ async def _run_impl(self) -> ActionResult:
153
+ started = time.time()
154
+ target = (Path(self.work_dir) / self._path).resolve()
155
+ ok = False
156
+ err = ""
157
+ meta: Dict[str, Any] = {"path": str(target)}
158
+ try:
159
+ parent = target.parent
160
+ if self._make_dirs:
161
+ parent.mkdir(parents=True, exist_ok=True)
162
+ if target.exists() and (not self._append) and (not self._overwrite):
163
+ raise FileExistsError(f"Refusing to overwrite existing file: {target}")
164
+
165
+ mode = "a" if self._append else "w"
166
+ with open(target, mode, encoding=self._encoding, newline="") as f:
167
+ f.write(self._content)
168
+ ok = True
169
+ meta["bytes_written"] = len(self._content.encode(self._encoding, errors="replace"))
170
+ meta["encoding_used"] = self._encoding
171
+ meta["append"] = self._append
172
+ except Exception as e:
173
+ err = f"{type(e).__name__}: {e}"
174
+
175
+ ended = time.time()
176
+ return ActionResult(
177
+ ok=ok or self.ignore_errors,
178
+ exit_code=0 if ok else 1,
179
+ stdout=str(target) + ("\n" if ok else ""),
180
+ stderr=(err + "\n") if err else "",
181
+ started_at=started,
182
+ ended_at=ended,
183
+ duration=ended - started,
184
+ cmd=f"write_file {self._path}",
185
+ work_dir=self.work_dir,
186
+ metadata=meta,
187
+ type="write_file"
188
+ )
189
+
190
+
191
+ class DeleteFile(BaseAction):
192
+ """
193
+ Deletes a file or directory (with optional recursion).
194
+ Options:
195
+ - recursive: remove directories recursively
196
+ - missing_ok: do not error if path does not exist
197
+ """
198
+ def __init__(
199
+ self,
200
+ *,
201
+ path: str,
202
+ recursive: bool = False,
203
+ missing_ok: bool = True,
204
+ work_dir: Optional[str] = None,
205
+ ignore_errors: Optional[bool] = None,
206
+ ):
207
+ super().__init__(type_name="delete_file", work_dir=work_dir, ignore_errors=ignore_errors)
208
+ self._path = path
209
+ self._recursive = bool(recursive)
210
+ self._missing_ok = bool(missing_ok)
211
+
212
+ async def _run_impl(self) -> ActionResult:
213
+ started = time.time()
214
+ target = (Path(self.work_dir) / self._path).resolve()
215
+ ok = False
216
+ err = ""
217
+ meta: Dict[str, Any] = {"path": str(target), "recursive": self._recursive}
218
+ try:
219
+ if not target.exists():
220
+ if self._missing_ok:
221
+ ok = True
222
+ else:
223
+ raise FileNotFoundError(f"No such file or directory: {target}")
224
+ else:
225
+ if target.is_dir():
226
+ if self._recursive:
227
+ shutil.rmtree(target)
228
+ ok = True
229
+ else:
230
+ # try rmdir (only empty dir)
231
+ target.rmdir()
232
+ ok = True
233
+ else:
234
+ target.unlink()
235
+ ok = True
236
+ except Exception as e:
237
+ err = f"{type(e).__name__}: {e}"
238
+
239
+ ended = time.time()
240
+ return ActionResult(
241
+ ok=ok or self.ignore_errors,
242
+ exit_code=0 if ok else 1,
243
+ stdout=str(target) + ("\n" if ok else ""),
244
+ stderr=(err + "\n") if err else "",
245
+ started_at=started,
246
+ ended_at=ended,
247
+ duration=ended - started,
248
+ cmd=f"delete_file {self._path}",
249
+ work_dir=self.work_dir,
250
+ metadata=meta,
251
+ type="delete_file"
252
+ )
253
+
254
+ class CopyFile(BaseAction):
255
+ """
256
+ Copy a file or directory.
257
+ - If source is a directory, set recursive=True to copy its tree.
258
+ - overwrite=True will replace an existing destination.
259
+ - make_dirs=True will create the destination parent directory.
260
+ """
261
+ def __init__(
262
+ self,
263
+ *,
264
+ src: str,
265
+ dest: str,
266
+ recursive: bool = False,
267
+ overwrite: bool = True,
268
+ make_dirs: bool = True,
269
+ work_dir: Optional[str] = None,
270
+ ignore_errors: Optional[bool] = None,
271
+ ):
272
+ super().__init__(type_name="copy_file", work_dir=work_dir, ignore_errors=ignore_errors)
273
+ self._src = src
274
+ self._dest = dest
275
+ self._recursive = bool(recursive)
276
+ self._overwrite = bool(overwrite)
277
+ self._make_dirs = bool(make_dirs)
278
+
279
+ async def _run_impl(self) -> ActionResult:
280
+ started = time.time()
281
+ src_p = (Path(self.work_dir) / self._src).resolve()
282
+ dest_p = (Path(self.work_dir) / self._dest).resolve()
283
+ ok = False
284
+ err = ""
285
+ meta = {
286
+ "src": str(src_p),
287
+ "dest": str(dest_p),
288
+ "recursive": self._recursive,
289
+ "overwrite": self._overwrite,
290
+ }
291
+ try:
292
+ if not src_p.exists():
293
+ raise FileNotFoundError(f"Source not found: {src_p}")
294
+
295
+ if self._make_dirs:
296
+ dest_p.parent.mkdir(parents=True, exist_ok=True)
297
+
298
+ if dest_p.exists():
299
+ if not self._overwrite:
300
+ raise FileExistsError(f"Destination exists (overwrite=False): {dest_p}")
301
+ # Remove existing dest to mimic replace
302
+ if dest_p.is_dir() and not src_p.is_dir():
303
+ shutil.rmtree(dest_p)
304
+ elif dest_p.is_file():
305
+ dest_p.unlink()
306
+
307
+ if src_p.is_dir():
308
+ if not self._recursive:
309
+ raise IsADirectoryError(f"Source is directory; set recursive=True to copy: {src_p}")
310
+ # shutil.copytree requires dest not exist (we removed above if overwrite)
311
+ shutil.copytree(src_p, dest_p)
312
+ else:
313
+ # copy2 preserves metadata
314
+ shutil.copy2(src_p, dest_p)
315
+
316
+ ok = True
317
+ except Exception as e:
318
+ err = f"{type(e).__name__}: {e}"
319
+
320
+ ended = time.time()
321
+ return ActionResult(
322
+ ok=ok or self.ignore_errors,
323
+ exit_code=0 if ok else 1,
324
+ stdout=(str(dest_p) + "\n") if ok else "",
325
+ stderr=(err + "\n") if err else "",
326
+ started_at=started,
327
+ ended_at=ended,
328
+ duration=ended - started,
329
+ cmd=f"copy_file {self._src} -> {self._dest}",
330
+ work_dir=self.work_dir,
331
+ metadata=meta,
332
+ type="copy_file"
333
+ )
334
+
335
+
336
+ class MoveFile(BaseAction):
337
+ """
338
+ Move/rename a file or directory.
339
+ - recursive flag is accepted for parity (moving dirs is allowed by default).
340
+ - overwrite=True will replace an existing destination.
341
+ - make_dirs=True will create the destination parent directory.
342
+ """
343
+ def __init__(
344
+ self,
345
+ *,
346
+ src: str,
347
+ dest: str,
348
+ recursive: bool = True,
349
+ overwrite: bool = True,
350
+ make_dirs: bool = True,
351
+ work_dir: Optional[str] = None,
352
+ ignore_errors: Optional[bool] = None,
353
+ ):
354
+ super().__init__(type_name="move_file", work_dir=work_dir, ignore_errors=ignore_errors)
355
+ self._src = src
356
+ self._dest = dest
357
+ self._recursive = bool(recursive)
358
+ self._overwrite = bool(overwrite)
359
+ self._make_dirs = bool(make_dirs)
360
+
361
+ async def _run_impl(self) -> ActionResult:
362
+ started = time.time()
363
+ src_p = (Path(self.work_dir) / self._src).resolve()
364
+ dest_p = (Path(self.work_dir) / self._dest).resolve()
365
+ ok = False
366
+ err = ""
367
+ meta = {
368
+ "src": str(src_p),
369
+ "dest": str(dest_p),
370
+ "recursive": self._recursive,
371
+ "overwrite": self._overwrite,
372
+ }
373
+ try:
374
+ if not src_p.exists():
375
+ raise FileNotFoundError(f"Source not found: {src_p}")
376
+
377
+ if self._make_dirs:
378
+ dest_p.parent.mkdir(parents=True, exist_ok=True)
379
+
380
+ if dest_p.exists():
381
+ if not self._overwrite:
382
+ raise FileExistsError(f"Destination exists (overwrite=False): {dest_p}")
383
+ # Remove destination before move (ensures replace semantics)
384
+ if dest_p.is_dir():
385
+ shutil.rmtree(dest_p)
386
+ else:
387
+ dest_p.unlink()
388
+
389
+ # shutil.move handles both files and directories
390
+ shutil.move(str(src_p), str(dest_p))
391
+ ok = True
392
+ except Exception as e:
393
+ err = f"{type(e).__name__}: {e}"
394
+
395
+ ended = time.time()
396
+ return ActionResult(
397
+ ok=ok or self.ignore_errors,
398
+ exit_code=0 if ok else 1,
399
+ stdout=(str(dest_p) + "\n") if ok else "",
400
+ stderr=(err + "\n") if err else "",
401
+ started_at=started,
402
+ ended_at=ended,
403
+ duration=ended - started,
404
+ cmd=f"move_file {self._src} -> {self._dest}",
405
+ work_dir=self.work_dir,
406
+ metadata=meta,
407
+ type="move_file"
408
+ )
@@ -0,0 +1,155 @@
1
+ from typing import Optional, Union, Any
2
+ import time
3
+ import subprocess
4
+ import re
5
+ import json
6
+ from .models import BaseAction, ActionResult
7
+
8
+
9
+ class EvaluationEngine:
10
+ """
11
+ Supports:
12
+ - regex: {"eval_type": "regex", "expr": "pattern", "group": 1}
13
+ - jsonpath (lite): {"eval_type": "jsonpath", "expr": "$.a.b[0]"}
14
+ - jq (requires 'jq' in PATH): {"eval_type": "jq", "expr": ".items[] | .name"}
15
+ """
16
+ @staticmethod
17
+ def eval_regex(text: str, expr: str, group: Optional[Union[int, str]] = None) -> str:
18
+ m = re.search(expr, text, re.MULTILINE | re.DOTALL)
19
+ if not m:
20
+ return ""
21
+ if group is None:
22
+ return m.group(0)
23
+ try:
24
+ return m.group(group)
25
+ except IndexError:
26
+ return ""
27
+
28
+ @staticmethod
29
+ def _jsonpath_lite(obj: Any, path: str) -> Any:
30
+ # Very small subset: $.a.b[0].c
31
+ if not path or not path.startswith("$."):
32
+ return None
33
+ cur = obj
34
+ # Split by '.' but keep indices [n]
35
+ tokens = re.findall(r'\.([A-Za-z0-9_]+)|\[(\d+)\]', path[1:]) # skip leading $
36
+ for key, idx in tokens:
37
+ if key:
38
+ if isinstance(cur, dict) and key in cur:
39
+ cur = cur[key]
40
+ else:
41
+ return None
42
+ elif idx:
43
+ if isinstance(cur, list):
44
+ i = int(idx)
45
+ if 0 <= i < len(cur):
46
+ cur = cur[i]
47
+ else:
48
+ return None
49
+ else:
50
+ return None
51
+ return cur
52
+
53
+ @staticmethod
54
+ def eval_jsonpath(src: Union[str, Any], expr: str, as_json: bool = False) -> str:
55
+ data: Any = src
56
+ if as_json and isinstance(src, str):
57
+ try:
58
+ data = json.loads(src)
59
+ except Exception:
60
+ return ""
61
+ val = EvaluationEngine._jsonpath_lite(data, expr)
62
+ if val is None:
63
+ return ""
64
+ if isinstance(val, (dict, list)):
65
+ return json.dumps(val, ensure_ascii=False)
66
+ return str(val)
67
+
68
+ @staticmethod
69
+ def eval_jq(src: Union[str, Any], expr: str, as_json: bool = False) -> str:
70
+ # Requires 'jq' installed
71
+ if isinstance(src, (dict, list)):
72
+ input_str = json.dumps(src)
73
+ elif isinstance(src, str):
74
+ if as_json:
75
+ try:
76
+ json.loads(src) # validate
77
+ input_str = src
78
+ except Exception:
79
+ input_str = json.dumps(src)
80
+ else:
81
+ input_str = src
82
+ else:
83
+ input_str = json.dumps(src)
84
+
85
+ try:
86
+ p = subprocess.run(
87
+ ["jq", "-c", "-M", expr],
88
+ input=input_str.encode(),
89
+ stdout=subprocess.PIPE,
90
+ stderr=subprocess.PIPE,
91
+ timeout=5
92
+ )
93
+ if p.returncode != 0:
94
+ return ""
95
+ return p.stdout.decode(errors="replace").strip()
96
+ except Exception:
97
+ return ""
98
+
99
+
100
+ class EvalAction(BaseAction):
101
+ """Evaluate an expression using regex, jsonpath, or jq."""
102
+ def __init__(
103
+ self,
104
+ *,
105
+ eval_type: str,
106
+ expr: str,
107
+ group: Optional[Union[int, str]],
108
+ src_text_or_obj: Any,
109
+ as_json: bool,
110
+ work_dir: Optional[str] = None,
111
+ ignore_errors: Optional[bool] = None
112
+ ):
113
+ super().__init__(
114
+ type_name="eval",
115
+ work_dir=work_dir,
116
+ ignore_errors=ignore_errors
117
+ )
118
+ self.eval_type = eval_type
119
+ self.expr = expr
120
+ self.group = group
121
+ self.src = src_text_or_obj
122
+ self.as_json = as_json
123
+
124
+ async def _run_impl(self) -> ActionResult:
125
+ started = time.time()
126
+ out = ""
127
+ err = ""
128
+ ok = True
129
+ try:
130
+ if self.eval_type == "regex":
131
+ out = EvaluationEngine.eval_regex(str(self.src), self.expr or "", self.group)
132
+ elif self.eval_type == "jsonpath":
133
+ out = EvaluationEngine.eval_jsonpath(self.src, self.expr or "", as_json=self.as_json)
134
+ elif self.eval_type == "jq":
135
+ out = EvaluationEngine.eval_jq(self.src, self.expr or "", as_json=self.as_json)
136
+ else:
137
+ ok = False
138
+ err = f"Unsupported eval_type: {self.eval_type}"
139
+ except Exception as e:
140
+ ok = False
141
+ err = f"{type(e).__name__}: {e}"
142
+ ended = time.time()
143
+ return ActionResult(
144
+ ok=ok or self.ignore_errors,
145
+ exit_code=0 if ok else 1,
146
+ stdout=(out + ("\n" if out else "")),
147
+ stderr=(err + ("\n" if err else "")),
148
+ started_at=started,
149
+ ended_at=ended,
150
+ duration=ended-started,
151
+ cmd=f"eval({self.eval_type}) {self.expr}",
152
+ work_dir=self.work_dir,
153
+ metadata={"eval_type": self.eval_type},
154
+ type="eval"
155
+ )