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
parrot/tools/ddgo.py ADDED
@@ -0,0 +1,370 @@
1
+ """
2
+ DuckDuckGo Search Toolkit for AI-Parrot.
3
+
4
+ This toolkit provides web search capabilities using the ddgs library directly,
5
+ removing all Langchain dependencies and implementing proper backoff retry for rate limiting.
6
+ """
7
+ import asyncio
8
+ from typing import Dict, Any, List, Optional
9
+ from pydantic import BaseModel, Field
10
+ import backoff
11
+ from ddgs import DDGS
12
+ from ddgs.exceptions import (
13
+ DDGSException,
14
+ RatelimitException,
15
+ TimeoutException,
16
+ )
17
+ from navconfig.logging import logging
18
+ from .toolkit import AbstractToolkit
19
+ from .abstract import ToolResult
20
+
21
+
22
+
23
+ # Pydantic schemas for tool arguments
24
+ class WebSearchArgs(BaseModel):
25
+ """Arguments for web search."""
26
+ query: str = Field(description="Search query")
27
+ region: str = Field(default="us-en", description="Search region (e.g., us-en, uk-en, ru-ru)")
28
+ safesearch: str = Field(default="moderate", description="Safe search level: on, moderate, off")
29
+ timelimit: Optional[str] = Field(default=None, description="Time limit: d(day), w(week), m(month), y(year)")
30
+ max_results: int = Field(default=10, description="Maximum number of results to return")
31
+ page: int = Field(default=1, description="Page number for results")
32
+
33
+
34
+ class NewsSearchArgs(BaseModel):
35
+ """Arguments for news search."""
36
+ query: str = Field(description="News search query")
37
+ region: str = Field(default="us-en", description="Search region")
38
+ safesearch: str = Field(default="moderate", description="Safe search level")
39
+ timelimit: Optional[str] = Field(default=None, description="Time limit for news")
40
+ max_results: int = Field(default=10, description="Maximum number of news results")
41
+
42
+
43
+ class ImageSearchArgs(BaseModel):
44
+ """Arguments for image search."""
45
+ query: str = Field(description="Image search query")
46
+ region: str = Field(default="us-en", description="Search region")
47
+ safesearch: str = Field(default="moderate", description="Safe search level")
48
+ size: Optional[str] = Field(default=None, description="Image size filter: Small, Medium, Large, Wallpaper")
49
+ color: Optional[str] = Field(default=None, description="Color filter: color, Monochrome, Red, Orange, etc.")
50
+ type_image: Optional[str] = Field(default=None, description="Image type: photo, clipart, gif, transparent, line")
51
+ layout: Optional[str] = Field(default=None, description="Layout: Square, Tall, Wide")
52
+ license_image: Optional[str] = Field(default=None, description="License: any, Public, Share, ShareCommercially, Modify")
53
+ max_results: int = Field(default=10, description="Maximum number of image results")
54
+
55
+
56
+ class VideoSearchArgs(BaseModel):
57
+ """Arguments for video search."""
58
+ query: str = Field(description="Video search query")
59
+ region: str = Field(default="us-en", description="Search region")
60
+ safesearch: str = Field(default="moderate", description="Safe search level")
61
+ timelimit: Optional[str] = Field(default=None, description="Time limit for videos")
62
+ resolution: Optional[str] = Field(default=None, description="Video resolution: high, standard")
63
+ duration: Optional[str] = Field(default=None, description="Video duration: short, medium, long")
64
+ license_videos: Optional[str] = Field(default=None, description="Video license filter")
65
+ max_results: int = Field(default=10, description="Maximum number of video results")
66
+
67
+
68
+ class DuckDuckGoToolkit(AbstractToolkit):
69
+ """
70
+ DuckDuckGo Search Toolkit providing comprehensive search capabilities.
71
+
72
+ This toolkit uses the ddgs library directly for improved performance and reliability,
73
+ with built-in backoff retry mechanisms for handling rate limits.
74
+ """
75
+
76
+ def __init__(self, **kwargs):
77
+ """Initialize the DuckDuckGo toolkit."""
78
+ super().__init__(**kwargs)
79
+ self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
80
+
81
+ # Backoff configuration
82
+ self.max_retries = kwargs.get('max_retries', 3)
83
+ self.backoff_factor = kwargs.get('backoff_factor', 2.0)
84
+ self.max_wait_time = kwargs.get('max_wait_time', 60.0)
85
+
86
+ def _get_backoff_decorator(self):
87
+ """Get the backoff decorator for retry logic."""
88
+ return backoff.on_exception(
89
+ backoff.expo,
90
+ (RatelimitException, TimeoutException, DDGSException),
91
+ max_tries=self.max_retries,
92
+ factor=self.backoff_factor,
93
+ max_time=self.max_wait_time,
94
+ logger=self.logger
95
+ )
96
+
97
+ async def web_search(
98
+ self,
99
+ query: str,
100
+ region: str = "us-en",
101
+ safesearch: str = "moderate",
102
+ timelimit: Optional[str] = None,
103
+ max_results: int = 10,
104
+ page: int = 1
105
+ ) -> ToolResult:
106
+ """
107
+ Search the web using DuckDuckGo.
108
+
109
+ Args:
110
+ query: Search query
111
+ region: Search region (e.g., us-en, uk-en, ru-ru)
112
+ safesearch: Safe search level (on, moderate, off)
113
+ timelimit: Time limit (d, w, m, y)
114
+ max_results: Maximum number of results
115
+ page: Page number for results
116
+
117
+ Returns:
118
+ ToolResult containing search results
119
+ """
120
+ try:
121
+ # Create backoff-wrapped search function
122
+ @self._get_backoff_decorator()
123
+ def _search():
124
+ ddgs = DDGS()
125
+ return ddgs.text(
126
+ query=query,
127
+ region=region,
128
+ safesearch=safesearch,
129
+ timelimit=timelimit,
130
+ max_results=max_results,
131
+ page=page,
132
+ backend="auto"
133
+ )
134
+
135
+ # Execute search in thread pool to avoid blocking
136
+ loop = asyncio.get_event_loop()
137
+ results = await loop.run_in_executor(None, _search)
138
+
139
+ return ToolResult(
140
+ status="success",
141
+ result={
142
+ "query": query,
143
+ "total_results": len(results),
144
+ "results": results,
145
+ "search_type": "web"
146
+ },
147
+ metadata={
148
+ "region": region,
149
+ "safesearch": safesearch,
150
+ "timelimit": timelimit,
151
+ "page": page
152
+ }
153
+ )
154
+
155
+ except Exception as e:
156
+ self.logger.error(f"Web search failed for query '{query}': {str(e)}")
157
+ return ToolResult(
158
+ status="error",
159
+ result=[],
160
+ error=f"Search failed: {str(e)}",
161
+ metadata={"query": query}
162
+ )
163
+
164
+ async def news_search(
165
+ self,
166
+ query: str,
167
+ region: str = "us-en",
168
+ safesearch: str = "moderate",
169
+ timelimit: Optional[str] = None,
170
+ max_results: int = 10
171
+ ) -> ToolResult:
172
+ """
173
+ Search for news using DuckDuckGo.
174
+
175
+ Args:
176
+ query: News search query
177
+ region: Search region
178
+ safesearch: Safe search level
179
+ timelimit: Time limit for news
180
+ max_results: Maximum number of results
181
+
182
+ Returns:
183
+ ToolResult containing news results
184
+ """
185
+ try:
186
+ @self._get_backoff_decorator()
187
+ def _search():
188
+ ddgs = DDGS()
189
+ return ddgs.news(
190
+ query=query,
191
+ region=region,
192
+ safesearch=safesearch,
193
+ timelimit=timelimit,
194
+ max_results=max_results
195
+ )
196
+
197
+ loop = asyncio.get_event_loop()
198
+ results = await loop.run_in_executor(None, _search)
199
+
200
+ return ToolResult(
201
+ status="success",
202
+ result={
203
+ "query": query,
204
+ "total_results": len(results),
205
+ "results": results,
206
+ "search_type": "news"
207
+ },
208
+ metadata={
209
+ "region": region,
210
+ "safesearch": safesearch,
211
+ "timelimit": timelimit
212
+ }
213
+ )
214
+
215
+ except Exception as e:
216
+ self.logger.error(f"News search failed for query '{query}': {str(e)}")
217
+ return ToolResult(
218
+ status="error",
219
+ result=[],
220
+ error=f"News search failed: {str(e)}",
221
+ metadata={"query": query}
222
+ )
223
+
224
+ async def image_search(
225
+ self,
226
+ query: str,
227
+ region: str = "us-en",
228
+ safesearch: str = "moderate",
229
+ size: Optional[str] = None,
230
+ color: Optional[str] = None,
231
+ type_image: Optional[str] = None,
232
+ layout: Optional[str] = None,
233
+ license_image: Optional[str] = None,
234
+ max_results: int = 10
235
+ ) -> ToolResult:
236
+ """
237
+ Search for images using DuckDuckGo.
238
+
239
+ Args:
240
+ query: Image search query
241
+ region: Search region
242
+ safesearch: Safe search level
243
+ size: Image size filter
244
+ color: Color filter
245
+ type_image: Image type filter
246
+ layout: Layout filter
247
+ license_image: License filter
248
+ max_results: Maximum number of results
249
+
250
+ Returns:
251
+ ToolResult containing image results
252
+ """
253
+ try:
254
+ @self._get_backoff_decorator()
255
+ def _search():
256
+ ddgs = DDGS()
257
+ return ddgs.images(
258
+ query=query,
259
+ region=region,
260
+ safesearch=safesearch,
261
+ size=size,
262
+ color=color,
263
+ type_image=type_image,
264
+ layout=layout,
265
+ license_image=license_image,
266
+ max_results=max_results
267
+ )
268
+
269
+ loop = asyncio.get_event_loop()
270
+ results = await loop.run_in_executor(None, _search)
271
+
272
+ return ToolResult(
273
+ status="success",
274
+ result={
275
+ "query": query,
276
+ "total_results": len(results),
277
+ "results": results,
278
+ "search_type": "images"
279
+ },
280
+ metadata={
281
+ "region": region,
282
+ "safesearch": safesearch,
283
+ "size": size,
284
+ "color": color,
285
+ "type_image": type_image,
286
+ "layout": layout,
287
+ "license_image": license_image
288
+ }
289
+ )
290
+
291
+ except Exception as e:
292
+ self.logger.error(f"Image search failed for query '{query}': {str(e)}")
293
+ return ToolResult(
294
+ status="error",
295
+ result=[],
296
+ error=f"Image search failed: {str(e)}",
297
+ metadata={"query": query}
298
+ )
299
+
300
+ async def video_search(
301
+ self,
302
+ query: str,
303
+ region: str = "us-en",
304
+ safesearch: str = "moderate",
305
+ timelimit: Optional[str] = None,
306
+ resolution: Optional[str] = None,
307
+ duration: Optional[str] = None,
308
+ license_videos: Optional[str] = None,
309
+ max_results: int = 10
310
+ ) -> ToolResult:
311
+ """
312
+ Search for videos using DuckDuckGo.
313
+
314
+ Args:
315
+ query: Video search query
316
+ region: Search region
317
+ safesearch: Safe search level
318
+ timelimit: Time limit for videos
319
+ resolution: Video resolution filter
320
+ duration: Video duration filter
321
+ license_videos: Video license filter
322
+ max_results: Maximum number of results
323
+
324
+ Returns:
325
+ ToolResult containing video results
326
+ """
327
+ try:
328
+ @self._get_backoff_decorator()
329
+ def _search():
330
+ ddgs = DDGS()
331
+ return ddgs.videos(
332
+ query=query,
333
+ region=region,
334
+ safesearch=safesearch,
335
+ timelimit=timelimit,
336
+ resolution=resolution,
337
+ duration=duration,
338
+ license_videos=license_videos,
339
+ max_results=max_results
340
+ )
341
+
342
+ loop = asyncio.get_event_loop()
343
+ results = await loop.run_in_executor(None, _search)
344
+
345
+ return ToolResult(
346
+ status="success",
347
+ result={
348
+ "query": query,
349
+ "total_results": len(results),
350
+ "results": results,
351
+ "search_type": "videos"
352
+ },
353
+ metadata={
354
+ "region": region,
355
+ "safesearch": safesearch,
356
+ "timelimit": timelimit,
357
+ "resolution": resolution,
358
+ "duration": duration,
359
+ "license_videos": license_videos
360
+ }
361
+ )
362
+
363
+ except Exception as e:
364
+ self.logger.error(f"Video search failed for query '{query}': {str(e)}")
365
+ return ToolResult(
366
+ status="error",
367
+ result=[],
368
+ error=f"Video search failed: {str(e)}",
369
+ metadata={"query": query}
370
+ )
@@ -0,0 +1,271 @@
1
+ from typing import Callable, Optional, Dict, Any, Type, Union, get_args, get_origin, get_type_hints
2
+ from functools import wraps
3
+ import inspect
4
+ import re
5
+ from enum import Enum
6
+ from pydantic import BaseModel
7
+
8
+
9
+ # Decorator for custom argument schemas
10
+ def tool_schema(schema: Type[BaseModel], description: Optional[str] = None):
11
+ """
12
+ Decorator to specify a custom argument schema for a toolkit method.
13
+
14
+ Usage:
15
+ @tool_schema(MyCustomSchema)
16
+ async def my_tool(self, arg1: str, arg2: int) -> str:
17
+ '''My custom tool.'''
18
+ return result
19
+ """
20
+ def decorator(func):
21
+ # print(f"Decorating {func.__name__} with {schema}")
22
+ func._args_schema = schema
23
+ func._tool_description = description or func.__doc__ or f"Tool: {func.__name__}"
24
+ return func
25
+ return decorator
26
+
27
+
28
+ def tool(
29
+ name: Optional[str] = None,
30
+ description: Optional[str] = None,
31
+ schema: Optional[Dict[str, Any]] = None,
32
+ auto_register: bool = False
33
+ ):
34
+ """
35
+ Decorator to mark a function as a tool with automatic schema generation.
36
+
37
+ Automatically extracts:
38
+ - Name from function name (or use custom name)
39
+ - Description from docstring (or use custom description)
40
+ - Input schema from type hints (or use custom schema)
41
+
42
+ Args:
43
+ name: Optional custom tool name (defaults to function name)
44
+ description: Optional custom description (defaults to docstring)
45
+ schema: Optional custom input schema (auto-generated from type hints if not provided)
46
+ auto_register: If True, automatically register with active client/bot
47
+
48
+ Usage:
49
+ @tool()
50
+ def get_weather(location: str) -> str:
51
+ '''Get weather for a location.'''
52
+ return f"Weather in {location}"
53
+
54
+ @tool(name="custom_name", description="Custom description")
55
+ def my_function(param: int) -> str:
56
+ return str(param)
57
+ """
58
+ def decorator(func: Callable) -> Callable:
59
+ # Extract metadata
60
+ tool_name = name or func.__name__
61
+ tool_description = description or _extract_description(func)
62
+
63
+ # Generate schema from type hints if not provided
64
+ if schema is None:
65
+ tool_schema = _generate_schema_from_function(func)
66
+ else:
67
+ tool_schema = schema
68
+
69
+ # Store metadata on the function
70
+ func._tool_metadata = {
71
+ 'name': tool_name,
72
+ 'description': tool_description,
73
+ 'schema': tool_schema,
74
+ 'function': func,
75
+ 'auto_register': auto_register
76
+ }
77
+
78
+ # Mark as a tool
79
+ func._is_tool = True
80
+
81
+ @wraps(func)
82
+ def wrapper(*args, **kwargs):
83
+ return func(*args, **kwargs)
84
+
85
+ # Preserve metadata on wrapper
86
+ wrapper._tool_metadata = func._tool_metadata
87
+ wrapper._is_tool = True
88
+
89
+ return wrapper
90
+
91
+ return decorator
92
+
93
+ def _extract_description(func: Callable) -> str:
94
+ """
95
+ Extract description from function docstring.
96
+ Takes the first line or paragraph of the docstring.
97
+ """
98
+ if not func.__doc__:
99
+ return f"Tool: {func.__name__}"
100
+
101
+ # Get first line or first paragraph
102
+ docstring = func.__doc__.strip()
103
+
104
+ # Split by newlines and get first non-empty line
105
+ lines = [line.strip() for line in docstring.split('\n')]
106
+ non_empty = [line for line in lines if line]
107
+
108
+ if non_empty:
109
+ return non_empty[0]
110
+
111
+ return f"Tool: {func.__name__}"
112
+
113
+
114
+ def _generate_schema_from_function(func: Callable) -> Dict[str, Any]:
115
+ """
116
+ Generate JSON schema from function signature and type hints.
117
+
118
+ Args:
119
+ func: The function to generate schema for
120
+
121
+ Returns:
122
+ JSON schema dictionary
123
+ """
124
+ sig = inspect.signature(func)
125
+
126
+ # Get type hints
127
+ try:
128
+ type_hints = get_type_hints(func)
129
+ except Exception:
130
+ # If get_type_hints fails, fall back to annotations
131
+ type_hints = func.__annotations__ or {}
132
+
133
+ properties = {}
134
+ required = []
135
+
136
+ for param_name, param in sig.parameters.items():
137
+ # Skip self and cls
138
+ if param_name in ('self', 'cls'):
139
+ continue
140
+
141
+ # Get type hint (default to string if not specified)
142
+ param_type = type_hints.get(param_name, str)
143
+
144
+ # Convert Python types to JSON schema types
145
+ json_type = _python_type_to_json_type(param_type)
146
+
147
+ # Get description from docstring if available
148
+ param_description = _extract_param_description(func, param_name)
149
+
150
+ # Build property definition
151
+ if isinstance(json_type, dict):
152
+ # Complex type (List, Optional, Union, etc.)
153
+ prop_def = json_type.copy()
154
+ if param_description:
155
+ prop_def['description'] = param_description
156
+ else:
157
+ prop_def['description'] = f"The {param_name} parameter"
158
+ else:
159
+ # Simple type
160
+ prop_def = {
161
+ 'type': json_type,
162
+ 'description': param_description or f"The {param_name} parameter"
163
+ }
164
+
165
+ properties[param_name] = prop_def
166
+
167
+ # Check if parameter is required (no default value)
168
+ if param.default == inspect.Parameter.empty:
169
+ required.append(param_name)
170
+
171
+ return {
172
+ 'type': 'object',
173
+ 'properties': properties,
174
+ 'required': required
175
+ }
176
+
177
+ def _extract_param_description(func: Callable, param_name: str) -> Optional[str]:
178
+ """
179
+ Extract parameter description from docstring.
180
+ Looks for Google, NumPy, or Sphinx style docstrings.
181
+ """
182
+ if not func.__doc__:
183
+ return None
184
+
185
+ docstring = func.__doc__
186
+
187
+ # Google style: Args: section
188
+ google_pattern = rf'{param_name}\s*:\s*(.+?)(?:\n|$)'
189
+ match = re.search(google_pattern, docstring)
190
+ if match:
191
+ return match.group(1).strip()
192
+
193
+ # Sphinx style: :param name: description
194
+ sphinx_pattern = rf':param\s+{param_name}\s*:\s*(.+?)(?:\n|$)'
195
+ match = re.search(sphinx_pattern, docstring)
196
+ if match:
197
+ return match.group(1).strip()
198
+
199
+ return None
200
+
201
+
202
+ def _python_type_to_json_type(python_type: Any) -> Union[str, Dict[str, Any]]:
203
+ """
204
+ Convert Python type hints to JSON schema types.
205
+
206
+ Handles:
207
+ - Basic types (str, int, float, bool)
208
+ - Optional types
209
+ - List types
210
+ - Dict types
211
+ - Union types
212
+ - Enum types
213
+ """
214
+ # Handle None type
215
+ if python_type is type(None):
216
+ return "null"
217
+
218
+ # Get origin for generic types (List, Dict, Optional, etc.)
219
+ origin = get_origin(python_type)
220
+
221
+ # Handle Optional[T] -> Union[T, None]
222
+ if origin is Union:
223
+ args = get_args(python_type)
224
+ # Check if it's Optional (Union with None)
225
+ if type(None) in args:
226
+ # It's Optional, get the non-None type
227
+ non_none_types = [t for t in args if t is not type(None)]
228
+ if len(non_none_types) == 1:
229
+ # Optional[T] - return the type with nullable
230
+ base_type = _python_type_to_json_type(non_none_types[0])
231
+ if isinstance(base_type, dict):
232
+ return base_type
233
+ return {"type": [base_type, "null"]}
234
+ # Regular Union - return anyOf
235
+ return {
236
+ "anyOf": [_python_type_to_json_type(t) for t in args]
237
+ }
238
+
239
+ # Handle List[T]
240
+ if origin is list or python_type is list:
241
+ args = get_args(python_type)
242
+ if args:
243
+ item_type = _python_type_to_json_type(args[0])
244
+ return {
245
+ "type": "array",
246
+ "items": {"type": item_type} if isinstance(item_type, str) else item_type
247
+ }
248
+ return "array"
249
+
250
+ # Handle Dict[K, V]
251
+ if origin is dict or python_type is dict:
252
+ return "object"
253
+
254
+ # Handle Enum
255
+ if inspect.isclass(python_type) and issubclass(python_type, Enum):
256
+ return {
257
+ "type": "string",
258
+ "enum": [e.value for e in python_type]
259
+ }
260
+
261
+ # Basic types
262
+ type_mapping = {
263
+ str: "string",
264
+ int: "integer",
265
+ float: "number",
266
+ bool: "boolean",
267
+ list: "array",
268
+ dict: "object",
269
+ }
270
+
271
+ return type_mapping.get(python_type, "string")