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,703 @@
1
+ """
2
+ AI-Parrot gVisor Sandbox Tool
3
+
4
+ Secure Python execution tool using gVisor (runsc) for complete kernel-level isolation.
5
+ This tool provides safe code execution for untrusted LLM-generated code.
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ import os
11
+ import tempfile
12
+ import uuid
13
+ import shutil
14
+ import subprocess
15
+ import logging
16
+ from pathlib import Path
17
+ from typing import Any, Dict, Optional, List, Tuple, Union
18
+ from dataclasses import dataclass, field
19
+ from contextlib import contextmanager
20
+ import base64
21
+ import pickle
22
+ import pandas as pd
23
+ import numpy as np
24
+
25
+ from parrot.tools.abstract import AbstractTool, ToolResult
26
+ from parrot.tools.pythonpandas import PythonPandasTool
27
+
28
+
29
+ @dataclass
30
+ class SandboxConfig:
31
+ """Configuration for gVisor sandbox"""
32
+ runtime: str = "runsc"
33
+ network: str = "none" # Disable network by default
34
+ max_memory: str = "2G"
35
+ max_cpu: float = 2.0
36
+ timeout: int = 30
37
+ python_image: str = "python:3.11-slim"
38
+ enable_gpu: bool = False
39
+ mount_paths: List[str] = field(default_factory=list)
40
+ pip_packages: List[str] = field(default_factory=lambda: [
41
+ "pandas", "numpy", "matplotlib", "seaborn", "scikit-learn",
42
+ "scipy", "plotly", "jupyterlab", "ipykernel"
43
+ ])
44
+
45
+
46
+ @dataclass
47
+ class ExecutionResult:
48
+ """Result from sandbox execution"""
49
+ success: bool
50
+ stdout: str
51
+ stderr: str
52
+ exit_code: int
53
+ execution_time_ms: float
54
+ files_created: Dict[str, bytes] = field(default_factory=dict)
55
+ dataframes: Dict[str, pd.DataFrame] = field(default_factory=dict)
56
+ plots: List[Dict[str, Any]] = field(default_factory=list)
57
+ notebook_path: Optional[str] = None
58
+ error_message: Optional[str] = None
59
+
60
+
61
+ class SandboxTool(AbstractTool):
62
+ """
63
+ Secure Python execution using gVisor sandbox.
64
+
65
+ This tool provides kernel-level isolation for executing untrusted code
66
+ generated by LLMs, preventing escape attempts and resource exhaustion.
67
+ """
68
+
69
+ name = "gvisor_python_sandbox"
70
+ description = "Execute Python code in a secure gVisor sandbox with kernel isolation"
71
+
72
+ def __init__(
73
+ self,
74
+ config: Optional[SandboxConfig] = None,
75
+ workspace_dir: Optional[str] = None,
76
+ dataframes: Optional[Dict[str, pd.DataFrame]] = None,
77
+ enable_jupyter: bool = False,
78
+ logger: Optional[logging.Logger] = None
79
+ ):
80
+ """
81
+ Initialize gVisor sandbox tool.
82
+
83
+ Args:
84
+ config: Sandbox configuration
85
+ workspace_dir: Directory for temporary files
86
+ dataframes: Initial dataframes to make available
87
+ enable_jupyter: Enable Jupyter notebook creation
88
+ logger: Logger instance
89
+ """
90
+ super().__init__()
91
+ self.config = config or SandboxConfig()
92
+ self.workspace_dir = Path(workspace_dir or tempfile.mkdtemp(prefix="gvisor_"))
93
+ self.workspace_dir.mkdir(parents=True, exist_ok=True)
94
+
95
+ self.dataframes = dataframes or {}
96
+ self.enable_jupyter = enable_jupyter
97
+ self.logger = logger or logging.getLogger(__name__)
98
+
99
+ # Verify gVisor installation
100
+ self._verify_installation()
101
+
102
+ # Prepare base container image
103
+ self._prepare_base_image()
104
+
105
+ def _verify_installation(self):
106
+ """Verify gVisor and containerd are installed"""
107
+ try:
108
+ # Check runsc
109
+ result = subprocess.run(
110
+ ["runsc", "--version"],
111
+ capture_output=True,
112
+ text=True
113
+ )
114
+ if result.returncode != 0:
115
+ raise RuntimeError("runsc not found. Please install gVisor.")
116
+
117
+ self.logger.info(f"gVisor version: {result.stdout.strip()}")
118
+
119
+ # Check containerd
120
+ result = subprocess.run(
121
+ ["ctr", "--version"],
122
+ capture_output=True,
123
+ text=True
124
+ )
125
+ if result.returncode != 0:
126
+ self.logger.warning("containerd not found. Using Docker as fallback.")
127
+ self.use_docker = True
128
+ else:
129
+ self.use_docker = False
130
+
131
+ except FileNotFoundError as e:
132
+ raise RuntimeError(f"Required tools not installed: {e}")
133
+
134
+ def _prepare_base_image(self):
135
+ """Prepare base container image with required packages"""
136
+ dockerfile_content = f"""
137
+ FROM {self.config.python_image}
138
+
139
+ # Install system dependencies
140
+ RUN apt-get update && apt-get install -y \\
141
+ gcc \\
142
+ g++ \\
143
+ make \\
144
+ libssl-dev \\
145
+ libffi-dev \\
146
+ && rm -rf /var/lib/apt/lists/*
147
+
148
+ # Install Python packages
149
+ RUN pip install --no-cache-dir \\
150
+ {' '.join(self.config.pip_packages)}
151
+
152
+ # Create working directory
153
+ WORKDIR /workspace
154
+
155
+ # Create sandbox user (non-root)
156
+ RUN useradd -m -s /bin/bash sandbox && \\
157
+ chown -R sandbox:sandbox /workspace
158
+
159
+ USER sandbox
160
+
161
+ # Set Python to unbuffered mode
162
+ ENV PYTHONUNBUFFERED=1
163
+ ENV PYTHONDONTWRITEBYTECODE=1
164
+ """
165
+
166
+ # Build image
167
+ image_name = "ai-parrot-gvisor-sandbox"
168
+ dockerfile_path = self.workspace_dir / "Dockerfile"
169
+ dockerfile_path.write_text(dockerfile_content)
170
+
171
+ try:
172
+ subprocess.run(
173
+ ["docker", "build", "-t", image_name, "-f", str(dockerfile_path), "."],
174
+ cwd=self.workspace_dir,
175
+ check=True,
176
+ capture_output=True
177
+ )
178
+ self.image_name = image_name
179
+ self.logger.info(f"Built sandbox image: {image_name}")
180
+ except subprocess.CalledProcessError as e:
181
+ self.logger.error(f"Failed to build image: {e.stderr.decode()}")
182
+ raise
183
+
184
+ @contextmanager
185
+ def _create_sandbox_container(self, code: str, session_id: str):
186
+ """Create and manage a gVisor sandbox container"""
187
+ container_name = f"sandbox-{session_id}"
188
+ exec_dir = self.workspace_dir / session_id
189
+ exec_dir.mkdir(parents=True, exist_ok=True)
190
+
191
+ try:
192
+ # Prepare execution script
193
+ script_path = exec_dir / "execute.py"
194
+ script_path.write_text(self._prepare_execution_script(code))
195
+
196
+ # Prepare data files
197
+ self._prepare_data_files(exec_dir)
198
+
199
+ # Create container with gVisor runtime
200
+ run_cmd = [
201
+ "docker", "run",
202
+ "--runtime", self.config.runtime, # Use gVisor runtime
203
+ "--name", container_name,
204
+ "-d", # Detached
205
+ "--rm", # Auto-remove
206
+ "--memory", self.config.max_memory,
207
+ "--cpus", str(self.config.max_cpu),
208
+ "--network", self.config.network,
209
+ "--security-opt", "no-new-privileges",
210
+ "--cap-drop", "ALL", # Drop all capabilities
211
+ "-v", f"{exec_dir}:/workspace:ro", # Read-only mount
212
+ "-v", f"{exec_dir}/output:/output:rw", # Output directory
213
+ self.image_name,
214
+ "python", "/workspace/execute.py"
215
+ ]
216
+
217
+ # Start container
218
+ subprocess.run(run_cmd, check=True, capture_output=True)
219
+
220
+ yield container_name
221
+
222
+ finally:
223
+ # Cleanup container
224
+ try:
225
+ subprocess.run(
226
+ ["docker", "stop", container_name],
227
+ capture_output=True,
228
+ timeout=5
229
+ )
230
+ except:
231
+ subprocess.run(
232
+ ["docker", "kill", container_name],
233
+ capture_output=True
234
+ )
235
+
236
+ def _prepare_execution_script(self, code: str) -> str:
237
+ """Prepare the Python script for execution in sandbox"""
238
+ return f'''
239
+ import sys
240
+ import os
241
+ import json
242
+ import pickle
243
+ import base64
244
+ import traceback
245
+ import pandas as pd
246
+ import numpy as np
247
+ import matplotlib
248
+ matplotlib.use('Agg') # Non-interactive backend
249
+ import matplotlib.pyplot as plt
250
+ from datetime import datetime
251
+
252
+ # Load serialized dataframes
253
+ dataframes_file = '/workspace/dataframes.pkl'
254
+ if os.path.exists(dataframes_file):
255
+ with open(dataframes_file, 'rb') as f:
256
+ dataframes = pickle.load(f)
257
+ # Inject dataframes into global namespace
258
+ for name, df in dataframes.items():
259
+ globals()[name] = df
260
+ print(f"Loaded dataframe: {{name}} with shape {{df.shape}}")
261
+
262
+ # Execution metadata
263
+ execution_start = datetime.now()
264
+ created_files = {{}}
265
+ output_dataframes = {{}}
266
+ plots = []
267
+
268
+ # Redirect stdout to capture prints
269
+ import io
270
+ from contextlib import redirect_stdout, redirect_stderr
271
+
272
+ stdout_capture = io.StringIO()
273
+ stderr_capture = io.StringIO()
274
+
275
+ # Custom figure save wrapper
276
+ original_savefig = plt.savefig
277
+ def wrapped_savefig(fname, **kwargs):
278
+ fname = f"/output/{{fname}}"
279
+ original_savefig(fname, **kwargs)
280
+ with open(fname, 'rb') as f:
281
+ created_files[os.path.basename(fname)] = base64.b64encode(f.read()).decode()
282
+ plots.append({{"type": "matplotlib", "filename": os.path.basename(fname)}})
283
+ return fname
284
+ plt.savefig = wrapped_savefig
285
+
286
+ try:
287
+ with redirect_stdout(stdout_capture), redirect_stderr(stderr_capture):
288
+ # Execute user code
289
+ exec("""
290
+ {code}
291
+ """)
292
+
293
+ # Capture any created dataframes
294
+ for name, obj in list(globals().items()):
295
+ if isinstance(obj, pd.DataFrame) and name not in ['dataframes', 'pd']:
296
+ if name not in dataframes or not obj.equals(dataframes.get(name, pd.DataFrame())):
297
+ output_dataframes[name] = obj
298
+
299
+ execution_time = (datetime.now() - execution_start).total_seconds() * 1000
300
+
301
+ # Save results
302
+ result = {{
303
+ "success": True,
304
+ "stdout": stdout_capture.getvalue(),
305
+ "stderr": stderr_capture.getvalue(),
306
+ "exit_code": 0,
307
+ "execution_time_ms": execution_time,
308
+ "files_created": created_files,
309
+ "dataframes": {{name: df.to_dict('records') for name, df in output_dataframes.items()}},
310
+ "plots": plots
311
+ }}
312
+
313
+ except Exception as e:
314
+ result = {{
315
+ "success": False,
316
+ "stdout": stdout_capture.getvalue(),
317
+ "stderr": stderr_capture.getvalue() + "\\n" + traceback.format_exc(),
318
+ "exit_code": 1,
319
+ "execution_time_ms": (datetime.now() - execution_start).total_seconds() * 1000,
320
+ "error_message": str(e)
321
+ }}
322
+
323
+ # Write result
324
+ with open('/output/result.json', 'w') as f:
325
+ json.dump(result, f)
326
+ '''
327
+
328
+ def _prepare_data_files(self, exec_dir: Path):
329
+ """Prepare data files for the sandbox"""
330
+ # Create output directory
331
+ output_dir = exec_dir / "output"
332
+ output_dir.mkdir(parents=True, exist_ok=True)
333
+
334
+ # Serialize dataframes
335
+ if self.dataframes:
336
+ with open(exec_dir / "dataframes.pkl", 'wb') as f:
337
+ pickle.dump(self.dataframes, f)
338
+
339
+ async def execute(
340
+ self,
341
+ code: str,
342
+ description: str = "Execute Python code in gVisor sandbox",
343
+ create_notebook: bool = False,
344
+ **kwargs
345
+ ) -> ToolResult:
346
+ """
347
+ Execute Python code in gVisor sandbox.
348
+
349
+ Args:
350
+ code: Python code to execute
351
+ description: Description of execution
352
+ create_notebook: Create Jupyter notebook of execution
353
+ **kwargs: Additional parameters
354
+
355
+ Returns:
356
+ ToolResult with execution results
357
+ """
358
+ session_id = str(uuid.uuid4())[:8]
359
+ self.logger.info(f"Starting sandbox execution: {session_id}")
360
+
361
+ try:
362
+ # Execute in sandbox
363
+ result = await self._execute_in_sandbox(code, session_id)
364
+
365
+ # Optionally create notebook
366
+ if create_notebook and self.enable_jupyter:
367
+ notebook_path = await self._create_notebook(code, result, session_id)
368
+ result.notebook_path = notebook_path
369
+
370
+ # Format response
371
+ response = self._format_response(result)
372
+
373
+ return ToolResult(
374
+ result=response,
375
+ status="success" if result.success else "error",
376
+ error=result.error_message,
377
+ metadata={
378
+ "session_id": session_id,
379
+ "execution_time_ms": result.execution_time_ms,
380
+ "files_created": list(result.files_created.keys()),
381
+ "dataframes_created": list(result.dataframes.keys()),
382
+ "notebook_path": result.notebook_path
383
+ }
384
+ )
385
+
386
+ except Exception as e:
387
+ self.logger.error(f"Sandbox execution failed: {e}")
388
+ return ToolResult(
389
+ result=None,
390
+ status="error",
391
+ error=str(e)
392
+ )
393
+ finally:
394
+ # Cleanup session files
395
+ if not kwargs.get("keep_files", False):
396
+ self._cleanup_session(session_id)
397
+
398
+ async def _execute_in_sandbox(self, code: str, session_id: str) -> ExecutionResult:
399
+ """Execute code in gVisor sandbox container"""
400
+ exec_dir = self.workspace_dir / session_id
401
+
402
+ with self._create_sandbox_container(code, session_id) as container_name:
403
+ # Wait for execution with timeout
404
+ try:
405
+ result = subprocess.run(
406
+ ["docker", "wait", container_name],
407
+ capture_output=True,
408
+ text=True,
409
+ timeout=self.config.timeout
410
+ )
411
+
412
+ # Get logs
413
+ logs = subprocess.run(
414
+ ["docker", "logs", container_name],
415
+ capture_output=True,
416
+ text=True
417
+ )
418
+
419
+ except subprocess.TimeoutExpired:
420
+ # Kill container on timeout
421
+ subprocess.run(["docker", "kill", container_name], capture_output=True)
422
+ return ExecutionResult(
423
+ success=False,
424
+ stdout="",
425
+ stderr="Execution timeout exceeded",
426
+ exit_code=-1,
427
+ execution_time_ms=self.config.timeout * 1000,
428
+ error_message=f"Code execution exceeded {self.config.timeout}s timeout"
429
+ )
430
+
431
+ # Read results
432
+ result_file = exec_dir / "output" / "result.json"
433
+ if result_file.exists():
434
+ with open(result_file, 'r') as f:
435
+ result_data = json.load(f)
436
+
437
+ # Decode file contents
438
+ files_created = {}
439
+ for filename, content in result_data.get("files_created", {}).items():
440
+ files_created[filename] = base64.b64decode(content)
441
+
442
+ # Reconstruct dataframes
443
+ dataframes = {}
444
+ for name, records in result_data.get("dataframes", {}).items():
445
+ dataframes[name] = pd.DataFrame(records)
446
+
447
+ return ExecutionResult(
448
+ success=result_data["success"],
449
+ stdout=result_data["stdout"],
450
+ stderr=result_data["stderr"],
451
+ exit_code=result_data["exit_code"],
452
+ execution_time_ms=result_data["execution_time_ms"],
453
+ files_created=files_created,
454
+ dataframes=dataframes,
455
+ plots=result_data.get("plots", []),
456
+ error_message=result_data.get("error_message")
457
+ )
458
+ else:
459
+ return ExecutionResult(
460
+ success=False,
461
+ stdout=logs.stdout,
462
+ stderr=logs.stderr,
463
+ exit_code=result.returncode,
464
+ execution_time_ms=0,
465
+ error_message="Failed to read execution results"
466
+ )
467
+
468
+ async def _create_notebook(
469
+ self,
470
+ code: str,
471
+ result: ExecutionResult,
472
+ session_id: str
473
+ ) -> str:
474
+ """Create Jupyter notebook from execution"""
475
+ import nbformat
476
+ from nbformat.v4 import new_notebook, new_code_cell, new_markdown_cell
477
+
478
+ # Create notebook
479
+ nb = new_notebook()
480
+
481
+ # Add header cell
482
+ nb.cells.append(new_markdown_cell(
483
+ f"# gVisor Sandbox Execution\n"
484
+ f"Session: {session_id}\n"
485
+ f"Execution Time: {result.execution_time_ms:.2f}ms"
486
+ ))
487
+
488
+ # Add code cell
489
+ code_cell = new_code_cell(code)
490
+ if result.stdout:
491
+ code_cell.outputs = [{
492
+ "output_type": "stream",
493
+ "name": "stdout",
494
+ "text": result.stdout
495
+ }]
496
+ nb.cells.append(code_cell)
497
+
498
+ # Add results cell
499
+ if result.dataframes:
500
+ nb.cells.append(new_markdown_cell("## Created DataFrames"))
501
+ for name, df in result.dataframes.items():
502
+ nb.cells.append(new_code_cell(f"# DataFrame: {name}\n{df.to_string()}"))
503
+
504
+ if result.plots:
505
+ nb.cells.append(new_markdown_cell("## Generated Plots"))
506
+ for plot in result.plots:
507
+ nb.cells.append(new_markdown_cell(f"![{plot['filename']}]({plot['filename']})"))
508
+
509
+ # Save notebook
510
+ notebook_path = self.workspace_dir / f"notebook_{session_id}.ipynb"
511
+ with open(notebook_path, 'w') as f:
512
+ nbformat.write(nb, f)
513
+
514
+ return str(notebook_path)
515
+
516
+ def _format_response(self, result: ExecutionResult) -> str:
517
+ """Format execution result for display"""
518
+ parts = []
519
+
520
+ if result.success:
521
+ parts.append("✓ Code executed successfully")
522
+ parts.append(f"Execution time: {result.execution_time_ms:.2f}ms")
523
+ else:
524
+ parts.append("✗ Code execution failed")
525
+ parts.append(f"Error: {result.error_message}")
526
+
527
+ if result.stdout:
528
+ parts.append("\n--- Output ---")
529
+ parts.append(result.stdout)
530
+
531
+ if result.stderr and not result.success:
532
+ parts.append("\n--- Errors ---")
533
+ parts.append(result.stderr)
534
+
535
+ if result.files_created:
536
+ parts.append(f"\n--- Files Created ({len(result.files_created)}) ---")
537
+ for filename in result.files_created.keys():
538
+ parts.append(f" • {filename}")
539
+
540
+ if result.dataframes:
541
+ parts.append(f"\n--- DataFrames Created ({len(result.dataframes)}) ---")
542
+ for name, df in result.dataframes.items():
543
+ parts.append(f" • {name}: {df.shape[0]} rows × {df.shape[1]} columns")
544
+
545
+ if result.notebook_path:
546
+ parts.append(f"\n--- Notebook ---")
547
+ parts.append(f" 📓 {result.notebook_path}")
548
+
549
+ return "\n".join(parts)
550
+
551
+ def _cleanup_session(self, session_id: str):
552
+ """Clean up session files"""
553
+ session_dir = self.workspace_dir / session_id
554
+ if session_dir.exists():
555
+ shutil.rmtree(session_dir)
556
+
557
+ def add_dataframe(self, name: str, df: pd.DataFrame):
558
+ """Add a dataframe to be available in the sandbox"""
559
+ self.dataframes[name] = df
560
+
561
+ def set_timeout(self, timeout: int):
562
+ """Set execution timeout in seconds"""
563
+ self.config.timeout = timeout
564
+
565
+ def set_memory_limit(self, memory: str):
566
+ """Set memory limit (e.g., '1G', '512M')"""
567
+ self.config.max_memory = memory
568
+
569
+ def cleanup(self):
570
+ """Clean up all resources"""
571
+ if self.workspace_dir.exists():
572
+ shutil.rmtree(self.workspace_dir)
573
+
574
+
575
+ class SandboxPandasTool(SandboxTool):
576
+ """
577
+ Specialized version for Pandas operations with enhanced data handling.
578
+ Drop-in replacement for PythonPandasTool with security.
579
+ """
580
+
581
+ name = "sandbox_pandas_tool"
582
+ description = "Secure Pandas operations in gVisor sandbox"
583
+
584
+ def __init__(self, dataframes: Optional[Dict[str, pd.DataFrame]] = None, **kwargs):
585
+ """Initialize with Pandas-specific configuration"""
586
+ config = SandboxConfig(
587
+ pip_packages=[
588
+ "pandas", "numpy", "matplotlib", "seaborn",
589
+ "plotly", "scikit-learn", "scipy", "statsmodels",
590
+ "openpyxl", "xlrd", "pyarrow", "fastparquet"
591
+ ]
592
+ )
593
+ super().__init__(config=config, dataframes=dataframes, **kwargs)
594
+
595
+ async def analyze_dataframe(
596
+ self,
597
+ df_name: str,
598
+ analysis_type: str = "summary"
599
+ ) -> ToolResult:
600
+ """
601
+ Perform automated DataFrame analysis.
602
+
603
+ Args:
604
+ df_name: Name of dataframe to analyze
605
+ analysis_type: Type of analysis (summary, correlation, distribution)
606
+ """
607
+ if df_name not in self.dataframes:
608
+ return ToolResult(
609
+ result=None,
610
+ status="error",
611
+ error=f"DataFrame '{df_name}' not found"
612
+ )
613
+
614
+ analysis_code = {
615
+ "summary": f"""
616
+ import pandas as pd
617
+ df = {df_name}
618
+ print("=== DataFrame Summary ===")
619
+ print(f"Shape: {{df.shape}}")
620
+ print(f"\\nData Types:\\n{{df.dtypes}}")
621
+ print(f"\\nSummary Statistics:\\n{{df.describe()}}")
622
+ print(f"\\nMissing Values:\\n{{df.isnull().sum()}}")
623
+ print(f"\\nMemory Usage:\\n{{df.memory_usage(deep=True)}}")
624
+ """,
625
+
626
+ "correlation": f"""
627
+ import pandas as pd
628
+ import matplotlib.pyplot as plt
629
+ import seaborn as sns
630
+
631
+ df = {df_name}
632
+ numeric_cols = df.select_dtypes(include=['number']).columns
633
+ if len(numeric_cols) > 1:
634
+ corr_matrix = df[numeric_cols].corr()
635
+ print("=== Correlation Matrix ===")
636
+ print(corr_matrix)
637
+
638
+ plt.figure(figsize=(10, 8))
639
+ sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0)
640
+ plt.title('Correlation Heatmap')
641
+ plt.tight_layout()
642
+ plt.savefig('correlation_heatmap.png')
643
+ else:
644
+ print("Not enough numeric columns for correlation analysis")
645
+ """,
646
+
647
+ "distribution": f"""
648
+ import pandas as pd
649
+ import matplotlib.pyplot as plt
650
+ import seaborn as sns
651
+
652
+ df = {df_name}
653
+ numeric_cols = df.select_dtypes(include=['number']).columns
654
+
655
+ for i, col in enumerate(numeric_cols[:6]): # Limit to first 6 columns
656
+ plt.figure(figsize=(12, 4))
657
+
658
+ plt.subplot(1, 3, 1)
659
+ df[col].hist(bins=30, edgecolor='black')
660
+ plt.title(f'{{col}} - Histogram')
661
+
662
+ plt.subplot(1, 3, 2)
663
+ df.boxplot(column=col)
664
+ plt.title(f'{{col}} - Boxplot')
665
+
666
+ plt.subplot(1, 3, 3)
667
+ df[col].plot(kind='kde')
668
+ plt.title(f'{{col}} - KDE')
669
+
670
+ plt.tight_layout()
671
+ plt.savefig(f'distribution_{{col}}.png')
672
+ plt.close()
673
+
674
+ print(f"Generated distribution plots for {{len(numeric_cols)}} numeric columns")
675
+ """
676
+ }
677
+
678
+ code = analysis_code.get(analysis_type, analysis_code["summary"])
679
+ return await self.execute(
680
+ code,
681
+ description=f"Analyze DataFrame '{df_name}' - {analysis_type}"
682
+ )
683
+
684
+
685
+ # Factory function for easy instantiation
686
+ def create_sandbox_tool(
687
+ tool_type: str = "sandbox",
688
+ **kwargs
689
+ ) -> Union[SandboxTool, SandboxPandasTool]:
690
+ """
691
+ Factory function to create gVisor tools.
692
+
693
+ Args:
694
+ tool_type: Type of tool ('sandbox' or 'pandas')
695
+ **kwargs: Configuration parameters
696
+
697
+ Returns:
698
+ Configured gVisor tool instance
699
+ """
700
+ if tool_type == "pandas":
701
+ return SandboxPandasTool(**kwargs)
702
+ else:
703
+ return SandboxTool(**kwargs)