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
File without changes
@@ -0,0 +1,197 @@
1
+ from typing import List, Dict, Any, Tuple, Optional
2
+ from dataclasses import dataclass
3
+ import re
4
+ import numpy as np
5
+
6
+
7
+ @dataclass
8
+ class ChunkInfo:
9
+ """Information about a document chunk"""
10
+ chunk_id: str
11
+ parent_document_id: str
12
+ chunk_index: int
13
+ chunk_text: str
14
+ start_position: int
15
+ end_position: int
16
+ chunk_embedding: np.ndarray
17
+ metadata: Dict[str, Any]
18
+
19
+
20
+ class LateChunkingProcessor:
21
+ """
22
+ Late Chunking processor integrated with PgVectorStore.
23
+
24
+ Late chunking generates embeddings for the full document first, then creates
25
+ contextually-aware chunk embeddings that preserve the global document context.
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ vector_store,
31
+ chunk_size: int = 8192,
32
+ chunk_overlap: int = 200,
33
+ preserve_sentences: bool = True,
34
+ min_chunk_size: int = 100
35
+ ):
36
+ self.vector_store = vector_store
37
+ self.chunk_size = chunk_size
38
+ self.chunk_overlap = chunk_overlap
39
+ self.preserve_sentences = preserve_sentences
40
+ self.min_chunk_size = min_chunk_size
41
+
42
+ async def process_document_late_chunking(
43
+ self,
44
+ document_text: str,
45
+ document_id: str,
46
+ metadata: Optional[Dict[str, Any]] = None
47
+ ) -> Tuple[np.ndarray, List[ChunkInfo]]:
48
+ """
49
+ Process document with late chunking strategy.
50
+
51
+ Args:
52
+ document_text: Full document text
53
+ document_id: Unique document identifier
54
+ metadata: Optional metadata for the document
55
+
56
+ Returns:
57
+ Tuple of (full_document_embedding, list_of_chunk_info)
58
+ """
59
+ # Step 1: Generate full-document embedding for global context
60
+ full_embedding = self.vector_store._embed_.embed_query(document_text)
61
+
62
+ # Step 2: Split into semantic chunks
63
+ chunks = self._semantic_chunk_split(document_text)
64
+
65
+ # Step 3: Generate contextual embeddings for each chunk
66
+ chunk_infos = []
67
+
68
+ for chunk_idx, (chunk_text, start_pos, end_pos) in enumerate(chunks):
69
+ # Create contextual prompt that includes document context
70
+ contextual_text = self._create_contextual_text(
71
+ document_text, chunk_text, start_pos, end_pos
72
+ )
73
+
74
+ # Generate embedding with context
75
+ chunk_embedding = self.vector_store._embed_.embed_query(contextual_text)
76
+
77
+ # Create chunk ID
78
+ chunk_id = f"{document_id}_chunk_{chunk_idx:04d}"
79
+
80
+ # Prepare chunk metadata
81
+ chunk_metadata = {
82
+ **(metadata or {}),
83
+ 'parent_document_id': document_id,
84
+ 'chunk_index': chunk_idx,
85
+ 'total_chunks': len(chunks),
86
+ 'start_position': start_pos,
87
+ 'end_position': end_pos,
88
+ 'chunk_size': len(chunk_text),
89
+ 'is_chunk': True,
90
+ 'chunk_type': 'late_chunking',
91
+ 'context_preserved': True
92
+ }
93
+
94
+ chunk_info = ChunkInfo(
95
+ chunk_id=chunk_id,
96
+ parent_document_id=document_id,
97
+ chunk_index=chunk_idx,
98
+ chunk_text=chunk_text,
99
+ start_position=start_pos,
100
+ end_position=end_pos,
101
+ chunk_embedding=chunk_embedding,
102
+ metadata=chunk_metadata
103
+ )
104
+
105
+ chunk_infos.append(chunk_info)
106
+
107
+ return np.array(full_embedding), chunk_infos
108
+
109
+ def _semantic_chunk_split(self, text: str) -> List[Tuple[str, int, int]]:
110
+ """
111
+ Split text preserving semantic boundaries.
112
+
113
+ Returns:
114
+ List of (chunk_text, start_position, end_position) tuples
115
+ """
116
+ if self.preserve_sentences:
117
+ return self._sentence_aware_chunking(text)
118
+ else:
119
+ return self._simple_chunking(text)
120
+
121
+ def _sentence_aware_chunking(self, text: str) -> List[Tuple[str, int, int]]:
122
+ """Split text while preserving sentence boundaries."""
123
+ # Split by sentences (basic approach - could use spaCy for better results)
124
+ sentence_endings = re.finditer(r'[.!?]+\s+', text)
125
+ sentence_positions = [0] + [m.end() for m in sentence_endings] + [len(text)]
126
+
127
+ chunks = []
128
+ current_start = 0
129
+
130
+ for i in range(1, len(sentence_positions)):
131
+ current_end = sentence_positions[i]
132
+ current_size = current_end - current_start
133
+
134
+ # If current chunk is too large, create chunk at previous boundary
135
+ if current_size > self.chunk_size and len(chunks) > 0:
136
+ # Find the last good break point
137
+ prev_end = sentence_positions[i-1]
138
+ if prev_end - current_start >= self.min_chunk_size:
139
+ chunk_text = text[current_start:prev_end].strip()
140
+ chunks.append((chunk_text, current_start, prev_end))
141
+
142
+ # Start new chunk with overlap
143
+ overlap_start = max(current_start, prev_end - self.chunk_overlap)
144
+ current_start = overlap_start
145
+
146
+ # If we're at the end, add final chunk
147
+ if i == len(sentence_positions) - 1:
148
+ chunk_text = text[current_start:current_end].strip()
149
+ if len(chunk_text) >= self.min_chunk_size:
150
+ chunks.append((chunk_text, current_start, current_end))
151
+
152
+ return chunks if chunks else [(text, 0, len(text))]
153
+
154
+ def _simple_chunking(self, text: str) -> List[Tuple[str, int, int]]:
155
+ """Simple character-based chunking with overlap."""
156
+ chunks = []
157
+ start = 0
158
+
159
+ while start < len(text):
160
+ end = min(start + self.chunk_size, len(text))
161
+ chunk_text = text[start:end].strip()
162
+
163
+ if len(chunk_text) >= self.min_chunk_size:
164
+ chunks.append((chunk_text, start, end))
165
+
166
+ # Move start position with overlap
167
+ start += self.chunk_size - self.chunk_overlap
168
+
169
+ if end == len(text):
170
+ break
171
+
172
+ return chunks
173
+
174
+ def _create_contextual_text(
175
+ self,
176
+ full_text: str,
177
+ chunk_text: str,
178
+ start_pos: int,
179
+ end_pos: int
180
+ ) -> str:
181
+ """
182
+ Create contextual text that includes surrounding context for better embeddings.
183
+ """
184
+ # Get surrounding context (e.g., 200 chars before and after)
185
+ context_window = 200
186
+
187
+ context_start = max(0, start_pos - context_window)
188
+ context_end = min(len(full_text), end_pos + context_window)
189
+
190
+ # Extract context
191
+ before_context = full_text[context_start:start_pos] if context_start < start_pos else ""
192
+ after_context = full_text[end_pos:context_end] if end_pos < context_end else ""
193
+
194
+ # Create contextual text with clear boundaries
195
+ contextual_text = f"{before_context.strip()} [FOCUS] {chunk_text} [/FOCUS] {after_context.strip()}" # noqa
196
+
197
+ return contextual_text.strip()
@@ -0,0 +1,3 @@
1
+ from .mixin import TelemetryMixin
2
+
3
+ __all__ = ["TelemetryMixin"]
@@ -0,0 +1,111 @@
1
+ # parrot/telemetry/__init__.py
2
+ from typing import Optional, Dict, Any
3
+ from contextlib import contextmanager
4
+ import time
5
+ import openlit
6
+ from opentelemetry import trace, metrics
7
+ from opentelemetry.sdk.trace import TracerProvider
8
+ from opentelemetry.sdk.metrics import MeterProvider
9
+
10
+
11
+ class TelemetryMixin:
12
+ """Mixin to add observability to LLM clients"""
13
+
14
+ def __init__(self, *args, **kwargs):
15
+ super().__init__(*args, **kwargs)
16
+ self._telemetry_enabled = kwargs.get('enable_telemetry', True)
17
+
18
+ if self._telemetry_enabled:
19
+ # Get tracer and meter for this client
20
+ self.tracer = trace.get_tracer(f"parrot.client.{self.client_name}")
21
+ self.meter = metrics.get_meter(f"parrot.client.{self.client_name}")
22
+
23
+ # Create metrics
24
+ self.request_counter = self.meter.create_counter(
25
+ name="llm.requests",
26
+ description="Total LLM requests",
27
+ unit="1"
28
+ )
29
+ self.token_counter = self.meter.create_counter(
30
+ name="llm.tokens",
31
+ description="Total tokens used",
32
+ unit="1"
33
+ )
34
+ self.latency_histogram = self.meter.create_histogram(
35
+ name="llm.request.duration",
36
+ description="LLM request duration",
37
+ unit="ms"
38
+ )
39
+ self.error_counter = self.meter.create_counter(
40
+ name="llm.errors",
41
+ description="LLM errors",
42
+ unit="1"
43
+ )
44
+
45
+ @contextmanager
46
+ def track_request(self, operation: str, **attributes):
47
+ """Context manager for tracking LLM requests"""
48
+ if not self._telemetry_enabled:
49
+ yield {}
50
+ return
51
+
52
+ start_time = time.time()
53
+ span_attributes = {
54
+ "llm.provider": self.client_name,
55
+ "llm.operation": operation,
56
+ **attributes
57
+ }
58
+
59
+ with self.tracer.start_as_current_span(
60
+ f"{self.client_name}.{operation}",
61
+ attributes=span_attributes
62
+ ) as span:
63
+ metrics = {
64
+ "start_time": start_time,
65
+ "span": span
66
+ }
67
+
68
+ try:
69
+ yield metrics
70
+ # Success tracking
71
+ self.request_counter.add(1, {
72
+ "provider": self.client_name,
73
+ "operation": operation,
74
+ "status": "success"
75
+ })
76
+ except Exception as e:
77
+ # Error tracking
78
+ self.error_counter.add(1, {
79
+ "provider": self.client_name,
80
+ "operation": operation,
81
+ "error_type": type(e).__name__
82
+ })
83
+ span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
84
+ span.record_exception(e)
85
+ raise
86
+ finally:
87
+ # Always track latency
88
+ duration_ms = (time.time() - start_time) * 1000
89
+ self.latency_histogram.record(duration_ms, {
90
+ "provider": self.client_name,
91
+ "operation": operation
92
+ })
93
+
94
+ def track_tokens(self, usage: Dict[str, int], model: str):
95
+ """Track token usage"""
96
+ if not self._telemetry_enabled:
97
+ return
98
+
99
+ if "input_tokens" in usage:
100
+ self.token_counter.add(usage["input_tokens"], {
101
+ "provider": self.client_name,
102
+ "model": model,
103
+ "token_type": "input"
104
+ })
105
+
106
+ if "output_tokens" in usage:
107
+ self.token_counter.add(usage["output_tokens"], {
108
+ "provider": self.client_name,
109
+ "model": model,
110
+ "token_type": "output"
111
+ })
@@ -0,0 +1,3 @@
1
+ from .engine import TemplateEngine, JinjaConfig
2
+
3
+ __all__ = ["TemplateEngine", "JinjaConfig"]
@@ -0,0 +1,259 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from pathlib import Path
5
+ from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Union
6
+ import datetime
7
+ from navconfig.logging import logging
8
+
9
+ from jinja2 import (
10
+ BaseLoader,
11
+ ChoiceLoader,
12
+ DictLoader,
13
+ Environment,
14
+ FileSystemBytecodeCache,
15
+ FileSystemLoader,
16
+ TemplateError,
17
+ TemplateNotFound,
18
+ StrictUndefined,
19
+ select_autoescape,
20
+ )
21
+
22
+ PathLike = Union[str, Path]
23
+
24
+
25
+ @dataclass
26
+ class JinjaConfig:
27
+ """Configuration for the async Jinja2 Environment."""
28
+ template_dirs: list[Path] = field(default_factory=list)
29
+ extensions: list[str] = field(default_factory=lambda: [
30
+ "jinja2.ext.i18n",
31
+ "jinja2.ext.loopcontrols",
32
+ "jinja2_time.TimeExtension",
33
+ "jinja2_iso8601.ISO8601Extension",
34
+ "jinja2.ext.do",
35
+ "jinja2_humanize_extension.HumanizeExtension",
36
+ # "jinja2.ext.debug", # enable in dev if desired
37
+ ])
38
+ bytecode_cache_dir: Optional[Path] = None
39
+ bytecode_cache_pattern: str = "%s.cache"
40
+ autoescape: Any = select_autoescape(["html", "xml", "j2", "jinja", "jinja2"])
41
+ undefined: Any = StrictUndefined # raise on missing variables
42
+ keep_trailing_newline: bool = True
43
+ trim_blocks: bool = True
44
+ lstrip_blocks: bool = True
45
+
46
+
47
+ class TemplateEngine:
48
+ """
49
+ Async-only Jinja2 template engine with:
50
+ - multiple directories
51
+ - in-memory templates
52
+ - pluggable extensions/filters/globals
53
+ - optional bytecode cache
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ template_dirs: Optional[Union[PathLike, Sequence[PathLike]]] = None,
59
+ *,
60
+ extensions: Optional[Sequence[str]] = None,
61
+ bytecode_cache_dir: Optional[PathLike] = None,
62
+ filters: Optional[Mapping[str, Any]] = None,
63
+ globals_: Optional[Mapping[str, Any]] = None,
64
+ config: Optional[JinjaConfig] = None,
65
+ debug: bool = False,
66
+ ) -> None:
67
+ cfg = config or JinjaConfig()
68
+ self.logger = logging.getLogger(__name__)
69
+
70
+ # Normalize directories
71
+ if template_dirs is not None:
72
+ if isinstance(template_dirs, (str, Path)):
73
+ cfg.template_dirs.append(Path(template_dirs).resolve())
74
+ else:
75
+ cfg.template_dirs.extend(Path(p).resolve() for p in template_dirs)
76
+
77
+ # Validate & store directories
78
+ self._fs_dirs: list[Path] = []
79
+ for d in cfg.template_dirs:
80
+ if not d.exists():
81
+ raise ValueError(f"Template directory not found: {d}")
82
+ if not d.is_dir():
83
+ raise ValueError(f"Template path is not a directory: {d}")
84
+ self._fs_dirs.append(d)
85
+
86
+ # Extensions
87
+ self._configure_extensions(cfg, extensions, debug)
88
+
89
+ # Optional bytecode cache
90
+ self._bytecode_cache = None
91
+ if bytecode_cache_dir is not None:
92
+ bdir = Path(bytecode_cache_dir).resolve()
93
+ bdir.mkdir(parents=True, exist_ok=True)
94
+ self._bytecode_cache = FileSystemBytecodeCache(str(bdir), cfg.bytecode_cache_pattern)
95
+ elif cfg.bytecode_cache_dir:
96
+ bdir = Path(cfg.bytecode_cache_dir).resolve()
97
+ bdir.mkdir(parents=True, exist_ok=True)
98
+ self._bytecode_cache = FileSystemBytecodeCache(str(bdir), cfg.bytecode_cache_pattern)
99
+
100
+ # Loaders: FileSystem + (optional) in-memory DictLoader
101
+ self._dict_loader = DictLoader({})
102
+ fs_loader = FileSystemLoader([str(p) for p in self._fs_dirs]) if self._fs_dirs else None
103
+
104
+ if fs_loader:
105
+ loader: BaseLoader = ChoiceLoader([self._dict_loader, fs_loader])
106
+ else:
107
+ loader = self._dict_loader # still works with only in-memory templates
108
+
109
+ # Build the environment (async-only)
110
+ self.env = Environment(
111
+ loader=loader,
112
+ enable_async=True,
113
+ extensions=self._extensions,
114
+ bytecode_cache=self._bytecode_cache,
115
+ autoescape=cfg.autoescape,
116
+ undefined=cfg.undefined,
117
+ keep_trailing_newline=cfg.keep_trailing_newline,
118
+ trim_blocks=cfg.trim_blocks,
119
+ lstrip_blocks=cfg.lstrip_blocks,
120
+ )
121
+
122
+ # Useful default filters/globals
123
+ self.env.filters.setdefault("datetime", datetime.datetime.fromtimestamp)
124
+ # Add user-supplied
125
+ if filters:
126
+ for name, fn in filters.items():
127
+ self.env.filters[name] = fn
128
+ if globals_:
129
+ for name, val in globals_.items():
130
+ self.env.globals[name] = val
131
+
132
+ self.logger.debug(
133
+ "AsyncTemplateEngine initialized: dirs=%s, extensions=%s, bytecode_cache=%s",
134
+ [str(d) for d in self._fs_dirs],
135
+ self._extensions,
136
+ bool(self._bytecode_cache),
137
+ )
138
+
139
+ def _configure_extensions(self, cfg: JinjaConfig, extensions: Optional[Sequence[str]], debug: bool) -> None:
140
+ """Configure Jinja2 extensions."""
141
+ # Merge extensions
142
+ self._extensions: list[str] = list(cfg.extensions)
143
+ if extensions:
144
+ for ext in extensions:
145
+ if ext not in self._extensions:
146
+ self._extensions.append(ext)
147
+ if debug and "jinja2.ext.debug" not in self._extensions:
148
+ self._extensions.append("jinja2.ext.debug")
149
+
150
+ # -------- Public API
151
+ def add_template_dir(self, path: PathLike) -> None:
152
+ """Add a new filesystem directory to the search path at runtime."""
153
+ p = Path(path).resolve()
154
+ if not p.exists() or not p.is_dir():
155
+ raise ValueError(f"Template directory invalid: {p}")
156
+ self._fs_dirs.append(p)
157
+
158
+ # Rebuild loader chain (ChoiceLoader is immutable in practice)
159
+ current_dicts = self._dict_loader.mapping
160
+ self._dict_loader = DictLoader(current_dicts)
161
+ fs_loader = FileSystemLoader([str(d) for d in self._fs_dirs])
162
+ self.env.loader = ChoiceLoader([self._dict_loader, fs_loader])
163
+
164
+ def add_templates(self, templates: Mapping[str, str]) -> None:
165
+ """
166
+ Add/override in-memory templates.
167
+ Example: add_templates({'layout.html': '<html>{{ self.block() }}</html>'})
168
+ """
169
+ for name, content in templates.items():
170
+ self._dict_loader.mapping[name] = content
171
+
172
+ def get_template(self, name: str):
173
+ """Get a compiled template by name (raises FileNotFoundError on miss)."""
174
+ try:
175
+ return self.env.get_template(name)
176
+ except TemplateNotFound as ex:
177
+ raise FileNotFoundError(f"Template not found: {name}") from ex
178
+ except Exception as ex:
179
+ raise RuntimeError(f"Error loading template '{name}': {ex}") from ex
180
+
181
+ async def render(self, name: str, params: Optional[Mapping[str, Any]] = None) -> str:
182
+ """
183
+ Async render of a template by name.
184
+ Only async path is supported (no sync render).
185
+ """
186
+ params = dict(params or {})
187
+ try:
188
+ tmpl = self.get_template(name)
189
+ # MUST use render_async because enable_async=True
190
+ return await tmpl.render_async(**params)
191
+ except TemplateError as ex:
192
+ raise ValueError(f"Template error while rendering '{name}': {ex}") from ex
193
+ except Exception as ex:
194
+ raise RuntimeError(f"Unexpected error rendering '{name}': {ex}") from ex
195
+
196
+ async def render_string(self, source: str, params: Optional[Mapping[str, Any]] = None) -> str:
197
+ """
198
+ Async render from a string (compiled via the current environment).
199
+ Useful for ad-hoc/injected content.
200
+ """
201
+ params = dict(params or {})
202
+ try:
203
+ tmpl = self.env.from_string(source)
204
+ return await tmpl.render_async(**params)
205
+ except TemplateError as ex:
206
+ raise ValueError(f"Template error while rendering string: {ex}") from ex
207
+ except Exception as ex:
208
+ raise RuntimeError(f"Unexpected error rendering string: {ex}") from ex
209
+
210
+ def add_filters(self, filters: Mapping[str, Any]) -> None:
211
+ """Register additional filters (supports async filters too)."""
212
+ for name, fn in filters.items():
213
+ self.env.filters[name] = fn
214
+
215
+ def add_globals(self, globals_: Mapping[str, Any]) -> None:
216
+ """Register additional global variables/functions."""
217
+ for name, val in globals_.items():
218
+ self.env.globals[name] = val
219
+
220
+ def compile_directory(self, target: PathLike, *, zip: Optional[str] = "deflated") -> None:
221
+ """
222
+ Optionally precompile all templates from filesystem loaders into `target`.
223
+ Skips silently if there are no filesystem directories.
224
+ """
225
+ if not self._fs_dirs:
226
+ return
227
+ target_path = Path(target).resolve()
228
+ target_path.mkdir(parents=True, exist_ok=True)
229
+ try:
230
+ self.env.compile_templates(
231
+ target=str(target_path),
232
+ zip=zip
233
+ )
234
+ except Exception as ex:
235
+ # If a transient decode error happens, try once again without failing the app
236
+ self.logger.warning(
237
+ f"Compile templates failed once: {ex}; retrying…"
238
+ )
239
+ self.env.compile_templates(
240
+ target=str(target_path),
241
+ zip=zip
242
+ )
243
+
244
+
245
+ # ------------------------------
246
+ # Minimal usage example (async)
247
+ # ------------------------------
248
+ # engine = TemplateEngine(
249
+ # template_dirs=["/path/to/templates", "/path/to/partials"],
250
+ # extensions=["jinja2.ext.debug"], # optional
251
+ # bytecode_cache_dir="/tmp/jinja-cache", # optional
252
+ # filters={"jsonify": json_encoder}, # e.g. your custom filter
253
+ # globals_={"app_name": "QuerySource"}, # optional
254
+ # )
255
+ #
256
+ # engine.add_templates({"inline.html": "Hello {{ name }}!"})
257
+ #
258
+ # html = await engine.render("index.html", {"user": "Pilar"})
259
+ # text = await engine.render_string("Hi {{ who }}", {"who": "there"})
@@ -0,0 +1,23 @@
1
+ """
2
+ Tools infrastructure for building Agents.
3
+ """
4
+ from parrot.plugins import setup_plugin_importer, dynamic_import_helper
5
+ from .abstract import AbstractTool, ToolResult
6
+ from .toolkit import AbstractToolkit, ToolkitTool
7
+ from .decorators import tool_schema, tool
8
+
9
+ setup_plugin_importer('parrot.tools', 'tools')
10
+
11
+ __all__ = (
12
+ "AbstractTool",
13
+ "ToolResult",
14
+ "AbstractToolkit",
15
+ "ToolkitTool",
16
+ "tool_schema",
17
+ "tool",
18
+ )
19
+
20
+ # Enable dynamic imports
21
+ def __getattr__(name):
22
+ return dynamic_import_helper(__name__, name)
23
+