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,861 @@
1
+ """
2
+ AgentTalk - HTTP Handler for Agent Conversations
3
+ =================================================
4
+ Provides a flexible HTTP interface for talking with agents/bots using the ask() method
5
+ with support for multiple output modes and MCP server integration.
6
+ """
7
+ from typing import Dict, Any, List, Union
8
+ import tempfile
9
+ import os
10
+ import json
11
+ import inspect
12
+ from aiohttp import web
13
+ import pandas as pd
14
+ from datamodel.parsers.json import json_encoder # noqa pylint: disable=E0611
15
+ from navconfig.logging import logging
16
+ from navigator_auth.decorators import is_authenticated, user_session
17
+ from navigator.views import BaseView
18
+ from ..bots.abstract import AbstractBot
19
+ from ..bots.data import PandasAgent
20
+ from ..models.responses import AIMessage, AgentResponse
21
+ from ..outputs import OutputMode, OutputFormatter
22
+ from ..mcp.integration import MCPServerConfig
23
+
24
+
25
+ @is_authenticated()
26
+ @user_session()
27
+ class AgentTalk(BaseView):
28
+ """
29
+ AgentTalk Handler - Universal agent conversation interface.
30
+
31
+ Endpoints:
32
+ POST /api/v1/agents/chat/ - Main chat endpoint with format negotiation
33
+
34
+ Features:
35
+ - POST to /api/v1/agents/chat/ to interact with agents
36
+ - Uses BotManager to retrieve the agent
37
+ - Supports multiple output formats (JSON, HTML, Markdown, Terminal)
38
+ - Can add MCP servers dynamically via POST attributes
39
+ - Leverages OutputMode for consistent formatting
40
+ - Session-based conversation management
41
+ """
42
+ _logger_name: str = "Parrot.AgentTalk"
43
+
44
+ def post_init(self, *args, **kwargs):
45
+ self.logger = logging.getLogger(self._logger_name)
46
+ self.logger.setLevel(logging.DEBUG)
47
+
48
+ def _get_output_format(
49
+ self,
50
+ data: Dict[str, Any],
51
+ qs: Dict[str, Any]
52
+ ) -> str:
53
+ """
54
+ Determine the output format from request.
55
+
56
+ Priority:
57
+ 1. Explicit 'output_format' in request body or query string
58
+ 2. Content-Type header from Accept header
59
+ 3. Default to 'json'
60
+
61
+ Args:
62
+ data: Request body data
63
+ qs: Query string parameters
64
+
65
+ Returns:
66
+ Output format string: 'json', 'html', 'markdown', or 'text'
67
+ """
68
+ # Check explicit output_format parameter
69
+ output_format = data.pop('output_format', None) or qs.get('output_format')
70
+ if output_format:
71
+ return output_format.lower()
72
+
73
+ # Check Accept header
74
+ accept_header = self.request.headers.get('Accept', 'application/json')
75
+
76
+ if 'text/html' in accept_header:
77
+ return 'html'
78
+ elif 'text/markdown' in accept_header:
79
+ return 'markdown'
80
+ elif 'text/plain' in accept_header:
81
+ return 'text'
82
+ else:
83
+ return 'json'
84
+
85
+ def _get_output_mode(self, request: web.Request) -> OutputMode:
86
+ """
87
+ Determine output mode from request headers and parameters.
88
+
89
+ Priority:
90
+ 1. Query parameter 'output_mode'
91
+ 2. Content-Type header
92
+ 3. Accept header
93
+ 4. Default to OutputMode.DEFAULT
94
+ """
95
+ # Check query parameters first
96
+ qs = self.query_parameters(request)
97
+ if 'output_mode' in qs:
98
+ mode = qs['output_mode'].lower()
99
+ if mode in ['json', 'html', 'terminal', 'markdown', 'default']:
100
+ return OutputMode(mode if mode != 'markdown' else 'default')
101
+
102
+ # Check Content-Type header
103
+ content_type = request.headers.get('Content-Type', '').lower()
104
+ if 'application/json' in content_type:
105
+ return OutputMode.JSON
106
+ elif 'text/html' in content_type:
107
+ return OutputMode.HTML
108
+
109
+ # Check Accept header
110
+ accept = request.headers.get('Accept', '').lower()
111
+ if 'application/json' in accept:
112
+ return OutputMode.JSON
113
+ elif 'text/html' in accept:
114
+ return OutputMode.HTML
115
+ elif 'text/plain' in accept:
116
+ return OutputMode.DEFAULT
117
+
118
+ return OutputMode.DEFAULT
119
+
120
+ def _format_to_output_mode(self, format_str: str) -> OutputMode:
121
+ """
122
+ Convert format string to OutputMode enum.
123
+
124
+ Args:
125
+ format_str: Format string (json, html, markdown, text, terminal)
126
+
127
+ Returns:
128
+ OutputMode enum value
129
+ """
130
+ format_map = {
131
+ 'json': OutputMode.JSON,
132
+ 'html': OutputMode.HTML,
133
+ 'markdown': OutputMode.DEFAULT,
134
+ 'text': OutputMode.DEFAULT,
135
+ 'terminal': OutputMode.TERMINAL,
136
+ 'default': OutputMode.DEFAULT
137
+ }
138
+ return format_map.get(format_str.lower(), OutputMode.DEFAULT)
139
+
140
+ def _prepare_response(
141
+ self,
142
+ ai_message: AIMessage,
143
+ output_mode: OutputMode,
144
+ format_kwargs: Dict[str, Any] = None
145
+ ):
146
+ """
147
+ Format and return the response based on output mode.
148
+
149
+ Args:
150
+ ai_message: The AIMessage response from the agent
151
+ output_mode: The desired output format
152
+ format_kwargs: Additional formatting options
153
+ """
154
+ formatter = OutputFormatter()
155
+
156
+ if output_mode == OutputMode.JSON:
157
+ # Return structured JSON response
158
+ response_data = {
159
+ "content": ai_message.content,
160
+ "metadata": {
161
+ "session_id": getattr(ai_message, 'session_id', None),
162
+ "user_id": getattr(ai_message, 'user_id', None),
163
+ "timestamp": getattr(ai_message, 'timestamp', None),
164
+ },
165
+ "tool_calls": getattr(ai_message, 'tool_calls', []),
166
+ "sources": getattr(ai_message, 'documents', []) if hasattr(ai_message, 'documents') else []
167
+ }
168
+
169
+ if hasattr(ai_message, 'error') and ai_message.error:
170
+ response_data['error'] = ai_message.error
171
+ return self.json_response(response_data, status=400)
172
+
173
+ return self.json_response(response_data)
174
+
175
+ elif output_mode == OutputMode.HTML:
176
+ # Return formatted HTML
177
+ formatted_content = formatter.format(
178
+ mode=output_mode,
179
+ data=ai_message,
180
+ **(format_kwargs or {})
181
+ )
182
+
183
+ # Create complete HTML page
184
+ html_template = f"""
185
+ <!DOCTYPE html>
186
+ <html>
187
+ <head>
188
+ <meta charset="UTF-8">
189
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
190
+ <title>Agent Response</title>
191
+ <style>
192
+ body {{
193
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
194
+ max-width: 900px;
195
+ margin: 40px auto;
196
+ padding: 20px;
197
+ line-height: 1.6;
198
+ background-color: #f5f5f5;
199
+ }}
200
+ .response-container {{
201
+ background: white;
202
+ padding: 30px;
203
+ border-radius: 8px;
204
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
205
+ }}
206
+ .metadata {{
207
+ font-size: 0.9em;
208
+ color: #666;
209
+ margin-bottom: 20px;
210
+ padding-bottom: 15px;
211
+ border-bottom: 1px solid #eee;
212
+ }}
213
+ .content {{
214
+ color: #333;
215
+ }}
216
+ .sources {{
217
+ margin-top: 30px;
218
+ padding-top: 20px;
219
+ border-top: 1px solid #eee;
220
+ font-size: 0.9em;
221
+ }}
222
+ code {{
223
+ background: #f4f4f4;
224
+ padding: 2px 6px;
225
+ border-radius: 3px;
226
+ font-family: 'Courier New', monospace;
227
+ }}
228
+ pre {{
229
+ background: #f4f4f4;
230
+ padding: 15px;
231
+ border-radius: 5px;
232
+ overflow-x: auto;
233
+ }}
234
+ </style>
235
+ </head>
236
+ <body>
237
+ <div class="response-container">
238
+ <div class="metadata">
239
+ <strong>Agent Response</strong>
240
+ </div>
241
+ <div class="content">
242
+ {formatted_content}
243
+ </div>
244
+ </div>
245
+ </body>
246
+ </html>
247
+ """
248
+ return web.Response(
249
+ text=html_template,
250
+ content_type='text/html',
251
+ charset='utf-8'
252
+ )
253
+
254
+ else:
255
+ # Return markdown/plain text
256
+ formatted_content = formatter.format(ai_message, **(format_kwargs or {}))
257
+ return web.Response(
258
+ text=str(formatted_content),
259
+ content_type='text/plain',
260
+ charset='utf-8'
261
+ )
262
+
263
+ async def _add_mcp_servers(self, agent: AbstractBot, mcp_configs: list):
264
+ """
265
+ Add MCP servers to the agent if it supports MCP.
266
+
267
+ Args:
268
+ agent: The agent instance
269
+ mcp_configs: List of MCP server configurations
270
+ """
271
+ if not hasattr(agent, 'add_mcp_server'):
272
+ self.logger.warning(
273
+ f"Agent {agent.name} does not support MCP servers. "
274
+ "Ensure BasicAgent has MCPEnabledMixin."
275
+ )
276
+ return
277
+
278
+ for config_dict in mcp_configs:
279
+ try:
280
+ # Create MCPServerConfig from dict
281
+ config = MCPServerConfig(
282
+ name=config_dict.get('name'),
283
+ url=config_dict.get('url'),
284
+ auth_type=config_dict.get('auth_type'),
285
+ auth_config=config_dict.get('auth_config', {}),
286
+ headers=config_dict.get('headers', {}),
287
+ allowed_tools=config_dict.get('allowed_tools'),
288
+ blocked_tools=config_dict.get('blocked_tools'),
289
+ )
290
+
291
+ tools = await agent.add_mcp_server(config)
292
+ self.logger.info(
293
+ f"Added MCP server '{config.name}' with {len(tools)} tools to agent {agent.name}"
294
+ )
295
+ except Exception as e:
296
+ self.logger.error(f"Failed to add MCP server: {e}")
297
+
298
+ def _check_methods(self, bot: AbstractBot, method_name: str):
299
+ """Check if the method exists in the bot and is callable."""
300
+ forbidden_methods = {
301
+ '__init__', '__del__', '__getattribute__', '__setattr__',
302
+ 'configure', '_setup_database_tools', 'save', 'delete',
303
+ 'update', 'insert', '__dict__', '__class__', 'retrieval',
304
+ '_define_prompt', 'configure_llm', 'configure_store', 'default_tools'
305
+ }
306
+ if not method_name:
307
+ return None
308
+ if method_name.startswith('_') or method_name in forbidden_methods:
309
+ raise AttributeError(
310
+ f"Method {method_name} error, not found or forbidden."
311
+ )
312
+ if not hasattr(bot, method_name):
313
+ raise AttributeError(
314
+ f"Method {method_name} error, not found or forbidden."
315
+ )
316
+ method = getattr(bot, method_name)
317
+ if not callable(method):
318
+ raise TypeError(
319
+ f"Attribute {method_name} is not callable in bot {bot.name}."
320
+ )
321
+ return method
322
+
323
+ async def _execute_agent_method(
324
+ self,
325
+ bot: AbstractBot,
326
+ method_name: str,
327
+ data: Dict[str, Any],
328
+ attachments: Dict[str, Any],
329
+ use_background: bool,
330
+ ) -> web.Response:
331
+ """Resolve and invoke an agent method safely."""
332
+ try:
333
+ method = self._check_methods(bot, method_name)
334
+ except (AttributeError, TypeError) as exc:
335
+ self.logger.error(f"Method {method_name} not available: {exc}")
336
+ return self.json_response(
337
+ {"error": f"Method {method_name} not available."},
338
+ status=400,
339
+ )
340
+
341
+ sig = inspect.signature(method)
342
+ method_params: Dict[str, Any] = {}
343
+ missing_required: List[str] = []
344
+ remaining_kwargs = dict(data)
345
+
346
+ for param_name, param in sig.parameters.items():
347
+ if param_name == 'self' or param_name == 'kwargs':
348
+ continue
349
+
350
+ if param.kind == inspect.Parameter.VAR_POSITIONAL:
351
+ continue
352
+ if param.kind == inspect.Parameter.VAR_KEYWORD:
353
+ continue
354
+
355
+ if param_name in remaining_kwargs:
356
+ method_params[param_name] = remaining_kwargs.pop(param_name)
357
+ elif param.default == inspect.Parameter.empty:
358
+ missing_required.append(param_name)
359
+
360
+ if param_name in attachments:
361
+ method_params[param_name] = attachments[param_name]
362
+ remaining_kwargs.pop(param_name, None)
363
+
364
+ if missing_required:
365
+ return self.json_response(
366
+ {
367
+ "message": (
368
+ "Required parameters missing: "
369
+ f"{', '.join(missing_required)}"
370
+ ),
371
+ "required_params": [
372
+ p for p in sig.parameters.keys() if p != 'self'
373
+ ],
374
+ },
375
+ status=400,
376
+ )
377
+
378
+ final_kwargs = {**method_params, **remaining_kwargs}
379
+
380
+ try:
381
+ if use_background:
382
+ self.request.app.loop.create_task(method(**final_kwargs))
383
+ return self.json_response(
384
+ {"message": "Request is being processed in the background."}
385
+ )
386
+
387
+ response = await method(**final_kwargs)
388
+ if isinstance(response, web.Response):
389
+ return response
390
+
391
+ return self.json_response(
392
+ {
393
+ "message": (
394
+ f"Method {method_name} was executed successfully."
395
+ ),
396
+ "response": str(response),
397
+ }
398
+ )
399
+ except Exception as exc: # pylint: disable=broad-except
400
+ self.logger.error(
401
+ f"Error calling method {method_name}: {exc}",
402
+ exc_info=True,
403
+ )
404
+ return self.json_response(
405
+ {"error": f"Error calling method {method_name}: {exc}"},
406
+ status=500,
407
+ )
408
+
409
+ async def post(self):
410
+ """
411
+ POST handler for agent interaction.
412
+
413
+ Endpoint: POST /api/v1/agents/chat/
414
+
415
+ Request body:
416
+ {
417
+ "agent_name": "my_agent",
418
+ "query": "What is the weather like?",
419
+ "session_id": "optional-session-id",
420
+ "user_id": "optional-user-id",
421
+ "output_mode": "json|html|markdown|terminal|default",
422
+ "search_type": str, # Optional: "similarity", "mmr", "ensemble"
423
+ "use_vector_context": bool, # Optional: Use vector store context
424
+ "format_kwargs": {
425
+ "show_metadata": true,
426
+ "show_sources": true
427
+ },
428
+ "mcp_servers": [
429
+ {
430
+ "name": "weather_api",
431
+ "url": "https://api.example.com/mcp",
432
+ "auth_type": "api_key",
433
+ "auth_config": {"api_key": "xxx"},
434
+ "headers": {"User-Agent": "AI-Parrot/1.0"}
435
+ }
436
+ ]
437
+ }
438
+
439
+ Returns:
440
+ - JSON response if output_mode is 'json' or Accept header is application/json
441
+ - HTML page if output_mode is 'html' or Accept header is text/html
442
+ - Markdown/plain text otherwise
443
+ """
444
+ try:
445
+ qs = self.query_parameters(self.request)
446
+ app = self.request.app
447
+ method_name = self.request.match_info.get('method_name', None)
448
+ try:
449
+ attachments, data = await self.handle_upload()
450
+ except web.HTTPUnsupportedMediaType:
451
+ # if no file is provided, then is a JSON request:
452
+ data = await self.request.json()
453
+ attachments = {}
454
+
455
+ # Support method invocation via body or query parameter in addition to the
456
+ # /{agent_id}/{method_name} route so clients don't need to construct a
457
+ # different URL for maintenance operations like refresh_data.
458
+ method_name = (
459
+ method_name
460
+ or data.pop('method_name', None)
461
+ or qs.get('method_name')
462
+ )
463
+ # Get BotManager
464
+ manager = self.request.app.get('bot_manager')
465
+ if not manager:
466
+ return self.json_response(
467
+ {"error": "BotManager is not installed."},
468
+ status=500
469
+ )
470
+
471
+ # Extract agent name
472
+ agent_name = self.request.match_info.get('agent_id', None)
473
+ if not agent_name:
474
+ agent_name = data.pop('agent_name', None) or qs.get('agent_name')
475
+ if not agent_name:
476
+ return self.error(
477
+ "Missing Agent Name",
478
+ status=400
479
+ )
480
+ query = data.pop('query', None)
481
+ # Get the agent
482
+ try:
483
+ agent: AbstractBot = await manager.get_bot(agent_name)
484
+ if not agent:
485
+ return self.error(
486
+ f"Agent '{agent_name}' not found.",
487
+ status=404
488
+ )
489
+ except Exception as e:
490
+ self.logger.error(f"Error retrieving agent {agent_name}: {e}")
491
+ return self.error(
492
+ f"Error retrieving agent: {e}",
493
+ status=500
494
+ )
495
+
496
+ # task background:
497
+ use_background = data.pop('background', False)
498
+
499
+ # Add MCP servers if provided
500
+ mcp_servers = data.pop('mcp_servers', [])
501
+ if mcp_servers and isinstance(mcp_servers, list):
502
+ await self._add_mcp_servers(agent, mcp_servers)
503
+
504
+ # TODO: Get session information
505
+ session_id = data.pop('session_id', None)
506
+ user_id = data.pop('user_id', None)
507
+
508
+ # Try to get from request session if not provided
509
+ try:
510
+ request_session = self.request.session
511
+ if not session_id:
512
+ session_id = request_session.get('session_id')
513
+ if not user_id:
514
+ user_id = request_session.get('user_id')
515
+ except AttributeError:
516
+ pass
517
+
518
+ # Determine output mode
519
+ # output_mode = self._get_output_mode(self.request)
520
+ # Determine output format
521
+ output_format = self._get_output_format(data, qs)
522
+ output_mode = data.pop('output_mode', OutputMode.DEFAULT)
523
+
524
+ # Extract parameters for ask()
525
+ search_type = data.pop('search_type', 'similarity')
526
+ return_sources = data.pop('return_sources', True)
527
+ use_vector_context = data.pop('use_vector_context', True)
528
+ use_conversation_history = data.pop('use_conversation_history', True)
529
+ followup_turn_id = data.pop('turn_id', None)
530
+ followup_data = data.pop('data', None)
531
+
532
+ # Override with explicit parameter if provided
533
+ if 'output_mode' in data:
534
+ try:
535
+ output_mode = OutputMode(data.pop('output_mode'))
536
+ except ValueError:
537
+ pass
538
+
539
+ # Prepare ask() parameters
540
+ format_kwargs = data.pop('format_kwargs', {})
541
+ response = None
542
+ async with agent.retrieval(self.request, app=app) as bot:
543
+ if method_name:
544
+ return await self._execute_agent_method(
545
+ bot=bot,
546
+ method_name=method_name,
547
+ data=data,
548
+ attachments=attachments,
549
+ use_background=use_background,
550
+ )
551
+ else:
552
+ if not query:
553
+ return self.json_response(
554
+ {"error": "query is required"},
555
+ status=400
556
+ )
557
+ if isinstance(bot, PandasAgent) and followup_turn_id and followup_data is not None:
558
+ response: AIMessage = await bot.followup(
559
+ question=query,
560
+ turn_id=followup_turn_id,
561
+ data=followup_data,
562
+ session_id=session_id,
563
+ user_id=user_id,
564
+ use_conversation_history=use_conversation_history,
565
+ output_mode=output_mode,
566
+ format_kwargs=format_kwargs,
567
+ **data,
568
+ )
569
+ else:
570
+ response: AIMessage = await bot.ask(
571
+ question=query,
572
+ session_id=session_id,
573
+ user_id=user_id,
574
+ search_type=search_type,
575
+ return_sources=return_sources,
576
+ use_vector_context=use_vector_context,
577
+ use_conversation_history=use_conversation_history,
578
+ output_mode=output_mode,
579
+ format_kwargs=format_kwargs,
580
+ **data,
581
+ )
582
+
583
+ # Return formatted response
584
+ return self._format_response(
585
+ response,
586
+ output_format,
587
+ format_kwargs
588
+ )
589
+
590
+ except json.JSONDecodeError:
591
+ return self.json_response(
592
+ {"error": "Invalid JSON in request body"},
593
+ status=400
594
+ )
595
+ except Exception as e:
596
+ self.logger.error(
597
+ f"Error in AgentTalk: {e}", exc_info=True
598
+ )
599
+ return self.json_response(
600
+ {
601
+ "error": "Internal server error",
602
+ "message": str(e)
603
+ },
604
+ status=500
605
+ )
606
+
607
+ async def get(self):
608
+ """
609
+ GET /api/v1/agents/chat/
610
+
611
+ Returns information about the AgentTalk endpoint.
612
+ """
613
+ method_name = self.request.match_info.get('method_name', None)
614
+ if method_name == 'debug':
615
+ agent_name = self.request.match_info.get('agent_id', None)
616
+ if not agent_name:
617
+ return self.error(
618
+ "Missing Agent Name for debug.",
619
+ status=400
620
+ )
621
+ manager = self.request.app.get('bot_manager')
622
+ if not manager:
623
+ return self.json_response(
624
+ {"error": "BotManager is not installed."},
625
+ status=500
626
+ )
627
+ try:
628
+ agent: AbstractBot = await manager.get_bot(agent_name)
629
+ if not agent:
630
+ return self.error(
631
+ f"Agent '{agent_name}' not found.",
632
+ status=404
633
+ )
634
+ except Exception as e:
635
+ self.logger.error(f"Error retrieving agent {agent_name}: {e}")
636
+ return self.error(
637
+ f"Error retrieving agent: {e}",
638
+ status=500
639
+ )
640
+ debug_info = await self.debug_agent(agent)
641
+ return self.json_response(debug_info)
642
+
643
+ return self.json_response({
644
+ "message": "AgentTalk - Universal Agent Conversation Interface",
645
+ "version": "1.0",
646
+ "usage": {
647
+ "method": "POST",
648
+ "endpoint": "/api/v1/agents/chat/",
649
+ "required_fields": ["agent_name", "query"],
650
+ "optional_fields": [
651
+ "session_id",
652
+ "user_id",
653
+ "output_mode",
654
+ "format_kwargs",
655
+ "mcp_servers",
656
+ "ask_kwargs"
657
+ ],
658
+ "output_modes": ["json", "html", "markdown", "terminal", "default"]
659
+ }
660
+ })
661
+
662
+ def _format_response(
663
+ self,
664
+ response: Union[AIMessage, AgentResponse],
665
+ output_format: str,
666
+ format_kwargs: Dict[str, Any]
667
+ ) -> web.Response:
668
+ """
669
+ Format the response based on the requested output format.
670
+
671
+ Args:
672
+ response: AIMessage from agent
673
+ output_format: Requested format
674
+ format_kwargs: Additional formatting options
675
+
676
+ Returns:
677
+ web.Response with appropriate content type
678
+ """
679
+
680
+ if isinstance(response, AgentResponse):
681
+ response = response.response
682
+
683
+
684
+ output = response.output
685
+
686
+ if output_format == 'json':
687
+ # Return structured JSON response
688
+ if isinstance(output, pd.DataFrame):
689
+ # Convert DataFrame to dict
690
+ output = output.to_dict(orient='records')
691
+ elif hasattr(output, 'explanation'):
692
+ output = output.explanation
693
+ output_mode = response.output_mode or 'json'
694
+ obj_response = {
695
+ "input": response.input,
696
+ "output": output,
697
+ "data": response.data,
698
+ "response": response.response,
699
+ "output_mode": output_mode,
700
+ "code": str(response.code) if response.code else None,
701
+ "metadata": {
702
+ "model": getattr(response, 'model', None),
703
+ "provider": getattr(response, 'provider', None),
704
+ "session_id": str(getattr(response, 'session_id', '')),
705
+ "turn_id": str(getattr(response, 'turn_id', '')),
706
+ "response_time": getattr(response, 'response_time', None),
707
+ },
708
+ "sources": [
709
+ {
710
+ "content": source.content,
711
+ "metadata": source.metadata
712
+ }
713
+ for source in getattr(response, 'sources', [])
714
+ ] if format_kwargs.get('include_sources', True) else [],
715
+ "tool_calls": [
716
+ {
717
+ "name": getattr(tool, 'name', 'unknown'),
718
+ "status": getattr(tool, 'status', 'completed'),
719
+ "output": getattr(tool, 'output', None),
720
+ 'arguments': getattr(tool, 'arguments', None)
721
+ }
722
+ for tool in getattr(response, 'tool_calls', [])
723
+ ] if format_kwargs.get('include_tool_calls', True) else []
724
+ }
725
+ print(obj_response)
726
+ return web.json_response(
727
+ obj_response, dumps=json_encoder
728
+ )
729
+
730
+ elif output_format == 'html':
731
+ interactive = format_kwargs.get('interactive', False)
732
+ if interactive:
733
+ return self._serve_panel_dashboard(response)
734
+
735
+ # Return HTML response
736
+ html_content = response.response
737
+ if isinstance(html_content, str):
738
+ html_str = html_content
739
+ elif hasattr(html_content, '_repr_html_'):
740
+ # Panel/IPython displayable object (for HTML mode)
741
+ html_str = html_content._repr_html_()
742
+ elif hasattr(html_content, '__str__'):
743
+ # Other objects with string representation
744
+ html_str = str(html_content)
745
+ else:
746
+ html_str = str(html_content)
747
+
748
+ return web.Response(
749
+ text=html_str,
750
+ content_type='text/html',
751
+ charset='utf-8'
752
+ )
753
+
754
+ else: # markdown or text
755
+ # Return plain text/markdown response
756
+ content = response.content
757
+
758
+ # Ensure it's a string
759
+ if not isinstance(content, str):
760
+ content = str(content)
761
+
762
+ # Optionally append sources
763
+ if format_kwargs.get('include_sources', False) and hasattr(response, 'sources'):
764
+ content += "\n\n## Sources\n"
765
+ for idx, source in enumerate(response.sources, 1):
766
+ content += f"\n{idx}. {source.content[:200]}...\n"
767
+
768
+ return web.Response(
769
+ text=content,
770
+ content_type='text/plain' if output_format == 'text' else 'text/markdown',
771
+ charset='utf-8'
772
+ )
773
+
774
+ return html_template
775
+
776
+ def _serve_panel_dashboard(self, response: AIMessage) -> web.Response:
777
+ """
778
+ Serve an interactive Panel dashboard.
779
+
780
+ This converts the Panel object to a standalone HTML application
781
+ with embedded JavaScript for interactivity.
782
+
783
+ Args:
784
+ response: AIMessage with Panel object in .content
785
+
786
+ Returns:
787
+ web.Response with interactive HTML
788
+ """
789
+ try:
790
+ panel_obj = response.response
791
+ # Create temporary file for the Panel HTML
792
+ with tempfile.NamedTemporaryFile(
793
+ mode='w',
794
+ suffix='.html',
795
+ delete=False
796
+ ) as tmp:
797
+ tmp_path = tmp.name
798
+
799
+ try:
800
+ # Save Panel to HTML with all resources embedded
801
+ panel_obj.save(
802
+ tmp_path,
803
+ embed=True, # Embed all JS/CSS resources
804
+ title=f"AI Agent Response - {response.session_id[:8] if response.session_id else 'interactive'}",
805
+ resources='inline' # Inline all resources
806
+ )
807
+
808
+ # Read the HTML content
809
+ with open(tmp_path, 'r', encoding='utf-8') as f:
810
+ html_content = f.read()
811
+
812
+ # Return as HTML response
813
+ return web.Response(
814
+ text=html_content,
815
+ content_type='text/html',
816
+ charset='utf-8'
817
+ )
818
+
819
+ finally:
820
+ # Clean up temporary file
821
+ if os.path.exists(tmp_path):
822
+ try:
823
+ os.unlink(tmp_path)
824
+ except Exception as e:
825
+ self.logger.warning(f"Failed to delete temp file {tmp_path}: {e}")
826
+
827
+ except ImportError:
828
+ self.logger.error(
829
+ "Panel library not available for interactive dashboards"
830
+ )
831
+ # Fallback to static HTML
832
+ return web.Response(
833
+ text=str(response.content),
834
+ content_type='text/html',
835
+ charset='utf-8'
836
+ )
837
+ except Exception as e:
838
+ self.logger.error(f"Error serving Panel dashboard: {e}", exc_info=True)
839
+ # Fallback to error response
840
+ return self.error(
841
+ f"Error rendering interactive dashboard: {e}",
842
+ status=500
843
+ )
844
+
845
+ async def debug_agent(self, agent):
846
+ return {
847
+ "dataframes": list(agent.dataframes.keys()),
848
+ "df_metadata": {k: v['shape'] for k, v in agent.df_metadata.items()},
849
+ "pandas_tool": {
850
+ "exists": agent._get_python_pandas_tool() is not None,
851
+ "dataframes": list(agent._get_python_pandas_tool().dataframes.keys())
852
+ if agent._get_python_pandas_tool() else []
853
+ },
854
+ "metadata_tool": {
855
+ "exists": agent._get_metadata_tool() is not None,
856
+ "dataframes": list(agent._get_metadata_tool().dataframes.keys())
857
+ if agent._get_metadata_tool() else [],
858
+ "metadata": list(agent._get_metadata_tool().metadata.keys())
859
+ if agent._get_metadata_tool() else []
860
+ }
861
+ }