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/bots/basic.py ADDED
@@ -0,0 +1,9 @@
1
+ from .abstract import AbstractBot
2
+
3
+ class BasicBot(AbstractBot):
4
+ """Represents an BasicBot in Navigator.
5
+
6
+ Each BasicBot has a name, a role, a goal, a backstory,
7
+ and an optional language model (llm).
8
+ """
9
+ pass
parrot/bots/chatbot.py ADDED
@@ -0,0 +1,669 @@
1
+ """
2
+ Foundational base of every Chatbot and Agent in ai-parrot.
3
+ """
4
+ from typing import Any, Union, Dict, List, Optional, ClassVar
5
+ from pathlib import Path
6
+ import uuid
7
+ from string import Template
8
+ import importlib
9
+ import asyncio
10
+ from contextlib import asynccontextmanager
11
+ # Navconfig
12
+ from datamodel.exceptions import ValidationError # pylint: disable=E0611
13
+ from navconfig import BASE_DIR
14
+ from navconfig.exceptions import ConfigError # pylint: disable=E0611
15
+ from asyncdb.exceptions import NoDataFound
16
+ from asyncdb import AsyncPool
17
+ from ..conf import (
18
+ default_dsn,
19
+ EMBEDDING_DEFAULT_MODEL,
20
+ KB_DEFAULT_MODEL
21
+ )
22
+ from ..handlers.models import BotModel
23
+ from .abstract import AbstractBot
24
+ from ..tools import (
25
+ AbstractTool,
26
+ )
27
+
28
+ class Chatbot(AbstractBot):
29
+ """Represents an Bot (Chatbot, Agent) in Navigator.
30
+
31
+ This class is the base for all chatbots and agents in the ai-parrot framework.
32
+
33
+ This class can be used in two ways:
34
+ 1. Manual creation: bot = Chatbot(name="MyBot", tools=[...])
35
+ 2. Database loading: bot = Chatbot(name="MyBot", from_database=True)
36
+ """
37
+ company_information: dict = {}
38
+ # Shared database pool for BotModel operations
39
+ _db_pool: ClassVar[Optional[AsyncPool]] = None
40
+ _db_pool_lock: ClassVar[asyncio.Lock] = asyncio.Lock()
41
+
42
+ def __init__(
43
+ self,
44
+ name: str = 'Nav',
45
+ system_prompt: str = None,
46
+ human_prompt: str = None,
47
+ from_database: bool = True,
48
+ tools: List[Union[str, AbstractTool]] = None,
49
+ **kwargs
50
+ ):
51
+ """
52
+ Initialize the Chatbot with manual creation or database loading support.
53
+
54
+ Args:
55
+ name: Bot name
56
+ system_prompt: Custom system prompt
57
+ human_prompt: Custom human prompt
58
+ from_database: Whether to load configuration from database
59
+ tools: List of tools for manual creation
60
+ **kwargs: Additional configuration
61
+ """
62
+ # Other Configuration
63
+ self.confidence_threshold: float = kwargs.get('threshold', 0.5)
64
+ self._from_database: bool = from_database
65
+ self._max_tools: int = kwargs.get('max_tools', 10)
66
+ # Text Documents
67
+ self.documents_dir: Path = kwargs.get(
68
+ 'documents_dir',
69
+ None
70
+ )
71
+ # Company Information:
72
+ self.company_information = kwargs.get(
73
+ 'company_information',
74
+ self.company_information
75
+ )
76
+ # Tool configuration
77
+ self.available_tool_instances: Dict[str, Any] = {}
78
+ super().__init__(
79
+ name=name,
80
+ system_prompt=system_prompt,
81
+ human_prompt=human_prompt,
82
+ tools= tools,
83
+ **kwargs
84
+ )
85
+ if isinstance(self.documents_dir, str):
86
+ self.documents_dir = Path(self.documents_dir)
87
+ if not self.documents_dir:
88
+ self.documents_dir = BASE_DIR.joinpath('documents')
89
+ if not self.documents_dir.exists():
90
+ self.documents_dir.mkdir(
91
+ parents=True,
92
+ exist_ok=True
93
+ )
94
+
95
+ # ------------------------------------------------------------------
96
+ # Database helpers
97
+ # ------------------------------------------------------------------
98
+ @classmethod
99
+ async def _get_db_pool(cls) -> AsyncPool:
100
+ """Return a shared async database pool for bot metadata."""
101
+ if not default_dsn:
102
+ raise ConfigError(
103
+ "Database DSN is not configured; cannot load bots from database"
104
+ )
105
+
106
+ pool = cls._db_pool
107
+ if pool is not None and pool.is_connected() and not pool.event_loop_is_closed():
108
+ return pool
109
+
110
+ async with cls._db_pool_lock:
111
+ pool = cls._db_pool
112
+ if pool is not None and pool.is_connected() and not pool.event_loop_is_closed():
113
+ return pool
114
+
115
+ pool = AsyncPool('pg', dsn=default_dsn)
116
+ await pool.connect() # pylint: disable=E1101 # noqa
117
+ cls._db_pool = pool
118
+ return pool
119
+
120
+ @classmethod
121
+ @asynccontextmanager
122
+ async def _botmodel_connection(cls):
123
+ """Context manager that yields a pooled connection for BotModel operations."""
124
+ pool = await cls._get_db_pool()
125
+ connection = None
126
+ try:
127
+ connection = await pool.acquire()
128
+ yield connection
129
+ finally:
130
+ if connection is not None:
131
+ await pool.release(connection)
132
+
133
+ def __repr__(self):
134
+ return f"<{self.__class__.__name__}:{self.name}>"
135
+
136
+ async def configure(self, app=None) -> None:
137
+ """Load configuration for this Chatbot."""
138
+ if self._from_database:
139
+ bot = None
140
+ try:
141
+ bot = await self.bot_exists(name=self.name, uuid=self.chatbot_id)
142
+ except Exception as exc: # pragma: no cover - defensive logging
143
+ self.logger.error(
144
+ (
145
+ f"Failed to load bot '{self.name}' metadata from database: {exc}. "
146
+ "Falling back to manual configuration."
147
+ ),
148
+ exc_info=True,
149
+ )
150
+ if bot:
151
+ self.logger.notice(
152
+ f"Loading Bot {self.name} from Database: {bot.chatbot_id}"
153
+ )
154
+ # Bot exists on Database, Configure from the Database
155
+ await self.from_database(bot)
156
+ else:
157
+ self.logger.warning(
158
+ f"Bot {self.name} not found or database unavailable, falling back to manual configuration"
159
+ )
160
+ self._from_database = False
161
+ await self.from_manual_config()
162
+ else:
163
+ # Manual configuration
164
+ await self.from_manual_config()
165
+ # Call parent configuration
166
+ await super().configure(app)
167
+
168
+ def _from_bot(self, bot, key, config, default) -> Any:
169
+ value = getattr(bot, key, None)
170
+ file_value = config.get(key, default)
171
+ return value or file_value
172
+
173
+ def _from_db(self, botobj, key, default: str = None) -> Any:
174
+ value = getattr(botobj, key, default)
175
+ return value or default
176
+
177
+ def import_kb_class(self, kb_path: str):
178
+ try:
179
+ # Split the path to get module and class name
180
+ module_path, class_name = kb_path.rsplit('.', 1)
181
+ module = importlib.import_module(module_path)
182
+ return getattr(module, class_name)
183
+ except (ValueError, ImportError, AttributeError) as e:
184
+ self.logger.error(
185
+ f"Failed to import KB class from {kb_path}: {e}"
186
+ )
187
+ return None
188
+
189
+ async def from_manual_config(self) -> None:
190
+ """
191
+ Configure the bot manually without database dependency.
192
+ """
193
+ self.logger.info(f"Configuring bot {self.name} manually")
194
+
195
+ # Set up basic configuration with defaults
196
+ self.pre_instructions: list = getattr(self, 'pre_instructions', [])
197
+ self.description = getattr(self, 'description', f"AI Assistant: {self.name}")
198
+ self.role = getattr(self, 'role', 'AI Assistant')
199
+ self.goal = getattr(self, 'goal', 'Help users accomplish their tasks effectively')
200
+ self.rationale = getattr(self, 'rationale', 'Provide accurate and helpful information to users.')
201
+ self.backstory = getattr(self, 'backstory', 'I am an AI assistant created to help users with various tasks.')
202
+ self.capabilities = getattr(self, 'capabilities', 'I can engage in conversation, answer questions, and use tools when needed.')
203
+
204
+ # LLM Configuration with defaults
205
+ self._llm = getattr(self, '_llm', 'google')
206
+ self._llm_model = getattr(self, '_llm_model', None)
207
+ self._llm_temp = getattr(self, '_llm_temp', 0.1)
208
+ self._max_tokens = getattr(self, '_max_tokens', 8192)
209
+ self._top_k = getattr(self, '_top_k', 41)
210
+ self._top_p = getattr(self, '_top_p', 0.9)
211
+ self._llm_config = getattr(self, '_llm_config', {})
212
+
213
+ # Tool and agent configuration
214
+ self.auto_tool_detection = getattr(self, 'auto_tool_detection', True)
215
+ self.tool_threshold = getattr(self, 'tool_threshold', 0.7)
216
+ self.operation_mode = getattr(self, 'operation_mode', 'adaptive')
217
+ # Embedding Model Configuration
218
+ self.embedding_model: dict = getattr(self, 'embedding_model', {
219
+ 'model_name': EMBEDDING_DEFAULT_MODEL,
220
+ 'model_type': 'huggingface'
221
+ })
222
+
223
+ # Vector store configuration
224
+ self._use_vector = getattr(self, '_use_vector', False)
225
+ self._vector_store = getattr(self, '_vector_store', {})
226
+ self._metric_type = getattr(self, '_metric_type', 'COSINE')
227
+
228
+ # Memory and conversation configuration
229
+ self.memory_type = getattr(self, 'memory_type', 'memory')
230
+ self.memory_config = getattr(self, 'memory_config', {})
231
+ self.max_context_turns = getattr(self, 'max_context_turns', 5)
232
+ self.use_conversation_history = getattr(self, 'use_conversation_history', True)
233
+
234
+ # Context and retrieval settings
235
+ self.context_search_limit = getattr(self, 'context_search_limit', 10)
236
+ self.context_score_threshold = getattr(self, 'context_score_threshold', 0.7)
237
+
238
+ # Security and permissions
239
+ _default = self.default_permissions()
240
+ _permissions = getattr(self, '_permissions', {})
241
+ self._permissions = {**_default, **_permissions}
242
+
243
+ # Other settings
244
+ self.language = getattr(self, 'language', 'en')
245
+ self.disclaimer = getattr(self, 'disclaimer', None)
246
+
247
+ self.logger.info(
248
+ f"Manual configuration complete: "
249
+ f"tools_enabled={self.enable_tools}, "
250
+ f"operation_mode={self.operation_mode}, "
251
+ f"use_vector={self._use_vector}, "
252
+ f"tools_count={self.tool_manager.tool_count()}"
253
+ )
254
+
255
+ async def bot_exists(
256
+ self,
257
+ name: str = None,
258
+ uuid: uuid.UUID = None
259
+ ) -> Union[BotModel, bool]:
260
+ """Check if the Chatbot exists in the Database."""
261
+ try:
262
+ async with self._botmodel_connection() as conn: # pylint: disable=E1101
263
+ BotModel.Meta.connection = conn
264
+ try:
265
+ if self.chatbot_id:
266
+ try:
267
+ bot = await BotModel.get(chatbot_id=uuid, enabled=True)
268
+ except Exception:
269
+ bot = await BotModel.get(name=name, enabled=True)
270
+ else:
271
+ bot = await BotModel.get(name=self.name, enabled=True)
272
+ if bot:
273
+ return bot
274
+ except NoDataFound:
275
+ return False
276
+ except Exception as exc: # pragma: no cover - unexpected database error
277
+ self.logger.error(
278
+ f"Error retrieving bot from database: {exc}",
279
+ exc_info=True,
280
+ )
281
+ except Exception as exc: # pragma: no cover - database unavailable
282
+ self.logger.error(
283
+ f"Database error while checking bot existence: {exc}",
284
+ exc_info=True,
285
+ )
286
+ return False
287
+
288
+ async def from_database(
289
+ self,
290
+ bot: Union[BotModel, None] = None
291
+ ) -> None:
292
+ """
293
+ Load the Chatbot/Agent Configuration from the Database.
294
+ If the bot is not found, it will raise a ConfigError.
295
+ """
296
+ if not bot:
297
+ async with self._botmodel_connection() as conn: # pylint: disable=E1101
298
+ # import model
299
+ BotModel.Meta.connection = conn
300
+ try:
301
+ if self.chatbot_id:
302
+ try:
303
+ bot = await BotModel.get(chatbot_id=self.chatbot_id)
304
+ except Exception:
305
+ bot = await BotModel.get(name=self.name)
306
+ else:
307
+ bot = await BotModel.get(name=self.name)
308
+ except ValidationError as ex:
309
+ # Handle ValidationError
310
+ self.logger.error(f"Validation error: {ex}")
311
+ raise ConfigError(
312
+ f"Chatbot {self.name} with errors: {ex.payload()}."
313
+ )
314
+ except NoDataFound:
315
+ # Fallback to File configuration:
316
+ raise ConfigError(
317
+ f"Chatbot {self.name} not found in the database."
318
+ )
319
+
320
+ # Start Bot configuration from Database:
321
+ self.pre_instructions: list = self._from_db(
322
+ bot, 'pre_instructions', default=[]
323
+ )
324
+ self.name = self._from_db(bot, 'name', default=self.name)
325
+ self.chatbot_id = str(self._from_db(bot, 'chatbot_id', default=self.chatbot_id))
326
+ self.description = self._from_db(bot, 'description', default=self.description)
327
+
328
+ # Bot personality and behavior
329
+ self.role = self._from_db(bot, 'role', default=self.role)
330
+ self.goal = self._from_db(bot, 'goal', default=self.goal)
331
+ self.rationale = self._from_db(bot, 'rationale', default=self.rationale)
332
+ self.backstory = self._from_db(bot, 'backstory', default=self.backstory)
333
+ self.capabilities = self._from_db(bot, 'capabilities', default='')
334
+
335
+ # Prompt configuration
336
+ if bot.system_prompt_template:
337
+ self.system_prompt_template = bot.system_prompt_template
338
+ if bot.human_prompt_template:
339
+ self.human_prompt_template = bot.human_prompt_template
340
+
341
+ # LLM Configuration
342
+ self._llm = self._from_db(bot, 'llm', default='google')
343
+ self._llm_model = self._from_db(bot, 'model', default='gemini-2.5-flash')
344
+ self._llm_temp = self._from_db(bot, 'temperature', default=0.1)
345
+ self._max_tokens = self._from_db(bot, 'max_tokens', default=1024)
346
+ self._top_k = self._from_db(bot, 'top_k', default=41)
347
+ self._top_p = self._from_db(bot, 'top_p', default=0.9)
348
+ self._llm_config = self._from_db(bot, 'model_config', default={})
349
+
350
+ # Tool and agent configuration
351
+ self.enable_tools = self._from_db(bot, 'tools_enabled', default=True)
352
+ self.auto_tool_detection = self._from_db(bot, 'auto_tool_detection', default=True)
353
+ self.tool_threshold = self._from_db(bot, 'tool_threshold', default=0.7)
354
+ self.operation_mode = self._from_db(bot, 'operation_mode', default='adaptive')
355
+
356
+ # Load tools from database
357
+ tool_names = self._from_db(bot, 'tools', default=[])
358
+ if tool_names and self.enable_tools:
359
+ self.tool_manager.register_tools(tool_names)
360
+
361
+ # Embedding Model Configuration
362
+ self.embedding_model: dict = self._from_db(
363
+ bot, 'embedding_model', default={
364
+ 'model_name': EMBEDDING_DEFAULT_MODEL,
365
+ 'model_type': 'huggingface'
366
+ }
367
+ )
368
+
369
+ # Vector store configuration
370
+ self._use_vector = self._from_db(bot, 'use_vector', default=False)
371
+ self._vector_store = self._from_db(bot, 'vector_store_config', default={})
372
+ self._metric_type = self._vector_store.get('metric_type', self._metric_type)
373
+
374
+ # Memory and conversation configuration
375
+ self.memory_type = self._from_db(bot, 'memory_type', default='memory')
376
+ self.memory_config = self._from_db(bot, 'memory_config', default={})
377
+ self.max_context_turns = self._from_db(bot, 'max_context_turns', default=5)
378
+ self.use_conversation_history = self._from_db(bot, 'use_conversation_history', default=True)
379
+
380
+ # Context and retrieval settings
381
+ self.context_search_limit = self._from_db(bot, 'context_search_limit', default=10)
382
+ self.context_score_threshold = self._from_db(bot, 'context_score_threshold', default=0.7)
383
+
384
+ # Security and permissions
385
+ _default = self.default_permissions()
386
+ _permissions = self._from_db(bot, 'permissions', default={})
387
+ self._permissions = {**_default, **_permissions}
388
+
389
+ # Knowledge Base:
390
+ self.use_kb = self._from_db(bot, 'use_kb', default=False)
391
+ self._kb = self._from_db(bot, 'kb', default=[])
392
+ if self.use_kb:
393
+ from ..stores.kb.store import KnowledgeBaseStore
394
+ self.kb_store = KnowledgeBaseStore(
395
+ embedding_model=KB_DEFAULT_MODEL,
396
+ dimension=384
397
+ )
398
+
399
+ # Custom Knowledge Bases
400
+ self.custom_kbs = self._from_db(bot, 'custom_kbs', default=[])
401
+ if self.custom_kbs:
402
+ for kb_path in self.custom_kbs:
403
+ kb_class = self.import_kb_class(kb_path)
404
+ if kb_class:
405
+ self.register_kb(kb_class)
406
+
407
+ # Other settings
408
+ self.language = self._from_db(bot, 'language', default='en')
409
+ self.disclaimer = self._from_db(bot, 'disclaimer', default=None)
410
+
411
+ self.logger.info(
412
+ f"Loaded bot configuration: "
413
+ f"tools_enabled={self.enable_tools}, "
414
+ f"operation_mode={self.operation_mode}, "
415
+ f"use_vector={self._use_vector}, "
416
+ f"tools_count={self.tool_manager.tool_count()}"
417
+ )
418
+
419
+ def _define_prompt(self, config: dict = None, **kwargs):
420
+ """
421
+ Enhanced prompt definition that includes tools information.
422
+ """
423
+ # Setup the prompt variables
424
+ if config:
425
+ for key, val in config.items():
426
+ setattr(self, key, val)
427
+
428
+ # Build pre-context
429
+ pre_context = ''
430
+ if self.pre_instructions:
431
+ pre_context = "IMPORTANT PRE-INSTRUCTIONS: \n"
432
+ pre_context += "\n".join(f"- {a}." for a in self.pre_instructions)
433
+
434
+ # Build tools context if tools are available
435
+ tools_context = ''
436
+ # Apply template substitution
437
+ tmpl = Template(self.system_prompt_template)
438
+ final_prompt = tmpl.safe_substitute(
439
+ name=self.name,
440
+ role=self.role,
441
+ goal=self.goal,
442
+ capabilities=self.capabilities,
443
+ backstory=self.backstory,
444
+ rationale=self.rationale,
445
+ pre_context=pre_context,
446
+ tools_context=tools_context,
447
+ **kwargs
448
+ )
449
+ # Set the system prompt
450
+ self.system_prompt_template = final_prompt
451
+ if self._debug:
452
+ print(' SYSTEM PROMPT ')
453
+ print(final_prompt)
454
+
455
+ async def update_database_config(self, **updates) -> bool:
456
+ """
457
+ Update bot configuration in database.
458
+
459
+ Args:
460
+ **updates: Configuration updates to apply
461
+
462
+ Returns:
463
+ bool: True if update was successful, False otherwise
464
+ """
465
+ try:
466
+ async with self._botmodel_connection() as conn: # pylint: disable=E1101 # noqa
467
+ BotModel.Meta.connection = conn
468
+ bot = await BotModel.get(chatbot_id=self.chatbot_id)
469
+
470
+ # Apply updates
471
+ for key, value in updates.items():
472
+ if hasattr(bot, key):
473
+ setattr(bot, key, value)
474
+
475
+ # Save changes
476
+ await bot.update()
477
+ self.logger.info(f"Updated bot configuration in database: {list(updates.keys())}")
478
+ return True
479
+
480
+ except Exception as e:
481
+ self.logger.error(f"Error updating bot configuration: {e}")
482
+ return False
483
+
484
+ async def save_to_database(self) -> bool:
485
+ """
486
+ Save current bot configuration to database.
487
+
488
+ Returns:
489
+ bool: True if save was successful, False otherwise
490
+ """
491
+ try:
492
+ async with self._botmodel_connection() as conn: # pylint: disable=E1101 # noqa
493
+ BotModel.Meta.connection = conn
494
+
495
+ # Create or update bot model
496
+ bot_data = {
497
+ 'chatbot_id': self.chatbot_id,
498
+ 'name': self.name,
499
+ 'description': self.description,
500
+ 'role': self.role,
501
+ 'goal': self.goal,
502
+ 'backstory': self.backstory,
503
+ 'rationale': self.rationale,
504
+ 'capabilities': getattr(self, 'capabilities', ''),
505
+ 'system_prompt_template': self.system_prompt_template,
506
+ 'human_prompt_template': getattr(self, 'human_prompt_template', None),
507
+ 'pre_instructions': self.pre_instructions,
508
+ 'llm': self._llm,
509
+ 'model_name': self._llm_model,
510
+ 'temperature': self._llm_temp,
511
+ 'max_tokens': self._max_tokens,
512
+ 'top_k': self._top_k,
513
+ 'top_p': self._top_p,
514
+ 'model_config': self._llm_config,
515
+ 'tools_enabled': getattr(self, 'enable_tools', True),
516
+ 'auto_tool_detection': getattr(self, 'auto_tool_detection', True),
517
+ 'tool_threshold': getattr(self, 'tool_threshold', 0.7),
518
+ 'tools': [tool.name for tool in self.tool_manager.list_tools()] if self.tool_manager else [],
519
+ 'operation_mode': getattr(self, 'operation_mode', 'adaptive'),
520
+ 'use_vector': self._use_vector,
521
+ 'vector_store_config': self._vector_store,
522
+ 'embedding_model': self.embedding_model,
523
+ 'context_search_limit': getattr(self, 'context_search_limit', 10),
524
+ 'context_score_threshold': getattr(self, 'context_score_threshold', 0.7),
525
+ 'memory_type': getattr(self, 'memory_type', 'memory'),
526
+ 'memory_config': getattr(self, 'memory_config', {}),
527
+ 'max_context_turns': getattr(self, 'max_context_turns', 5),
528
+ 'use_conversation_history': getattr(self, 'use_conversation_history', True),
529
+ 'permissions': self._permissions,
530
+ 'language': getattr(self, 'language', 'en'),
531
+ 'disclaimer': getattr(self, 'disclaimer', None),
532
+ }
533
+
534
+ try:
535
+ # Try to get existing bot
536
+ bot = await BotModel.get(chatbot_id=self.chatbot_id)
537
+ # Update existing
538
+ for key, value in bot_data.items():
539
+ setattr(bot, key, value)
540
+ await bot.update()
541
+ self.logger.info(f"Updated existing bot {self.name} in database")
542
+
543
+ except NoDataFound:
544
+ # Create new bot
545
+ bot = BotModel(**bot_data)
546
+ await bot.save()
547
+ self.logger.info(f"Created new bot {self.name} in database")
548
+
549
+ return True
550
+
551
+ except Exception as e:
552
+ self.logger.error(f"Error saving bot to database: {e}")
553
+ return False
554
+
555
+ def get_configuration_summary(self) -> Dict[str, Any]:
556
+ """
557
+ Get a summary of the current bot configuration.
558
+
559
+ Returns:
560
+ Dict containing configuration summary
561
+ """
562
+ return {
563
+ 'name': self.name,
564
+ 'chatbot_id': self.chatbot_id,
565
+ 'operation_mode': getattr(self, 'operation_mode', 'adaptive'),
566
+ 'current_mode': self.get_operation_mode(),
567
+ 'tools_enabled': getattr(self, 'enable_tools', False),
568
+ 'tools_count': self.tool_manager.tool_count() if self.tool_manager else 0,
569
+ 'available_tools': self.tool_manager.list_tools() if self.tool_manager else [],
570
+ 'use_vector_store': self._use_vector,
571
+ 'vector_store_type': self._vector_store.get('name', 'none') if self._vector_store else 'none',
572
+ 'llm': self._llm,
573
+ 'model_name': self._llm_model,
574
+ 'memory_type': getattr(self, 'memory_type', 'memory'),
575
+ 'max_context_turns': getattr(self, 'max_context_turns', 5),
576
+ 'auto_tool_detection': getattr(self, 'auto_tool_detection', True),
577
+ 'tool_threshold': getattr(self, 'tool_threshold', 0.7),
578
+ 'language': getattr(self, 'language', 'en'),
579
+ }
580
+
581
+ async def test_configuration(self) -> Dict[str, Any]:
582
+ """
583
+ Test the current bot configuration and return status.
584
+
585
+ Returns:
586
+ Dict containing test results
587
+ """
588
+ results = {
589
+ 'status': 'success',
590
+ 'errors': [],
591
+ 'warnings': [],
592
+ 'info': []
593
+ }
594
+
595
+ try:
596
+ # Test database connection
597
+ if not await self.bot_exists(name=self.name):
598
+ results['warnings'].append(f"Bot {self.name} not found in database")
599
+ else:
600
+ results['info'].append("Database connection: OK")
601
+
602
+ # Test LLM configuration
603
+ if not self._llm:
604
+ results['errors'].append("No LLM configured")
605
+ else:
606
+ results['info'].append(f"LLM configured: {self._llm}")
607
+
608
+ # Test tools configuration
609
+ if getattr(self, 'enable_tools', False):
610
+ if not self.tool_manager:
611
+ results['warnings'].append("Tools enabled but no tools loaded")
612
+ else:
613
+ results['info'].append(f"Tools loaded: {len(self.tool_manager.list_tools())}")
614
+
615
+ # Test each tool
616
+ for tool in self.tool_manager.list_tools():
617
+ try:
618
+ # Basic tool validation
619
+ if not hasattr(tool, 'name'):
620
+ results['errors'].append(f"Tool {tool.__class__.__name__} missing name attribute")
621
+ else:
622
+ results['info'].append(f"Tool {tool.name}: OK")
623
+ except Exception as e:
624
+ results['errors'].append(f"Tool {tool.__class__.__name__} error: {e}")
625
+
626
+ # Test vector store configuration
627
+ if self._use_vector:
628
+ if not self._vector_store:
629
+ results['errors'].append("Vector store enabled but not configured")
630
+ else:
631
+ results['info'].append("Vector store configured")
632
+
633
+ # Set overall status
634
+ if results['errors']:
635
+ results['status'] = 'error'
636
+ elif results['warnings']:
637
+ results['status'] = 'warning'
638
+
639
+ except Exception as e:
640
+ results['status'] = 'error'
641
+ results['errors'].append(f"Configuration test failed: {e}")
642
+
643
+ return results
644
+
645
+ async def reload_from_database(self) -> bool:
646
+ """
647
+ Reload bot configuration from database.
648
+
649
+ Returns:
650
+ bool: True if reload was successful, False otherwise
651
+ """
652
+ try:
653
+ if bot := await self.bot_exists(name=self.name, uuid=self.chatbot_id):
654
+ await self.from_database(bot)
655
+ self.logger.info(f"Reloaded bot {self.name} configuration from database")
656
+ return True
657
+ else:
658
+ self.logger.error(f"Bot {self.name} not found in database for reload")
659
+ return False
660
+ except Exception as e:
661
+ self.logger.error(f"Error reloading bot configuration: {e}")
662
+ return False
663
+
664
+ def __str__(self) -> str:
665
+ """String representation of the bot."""
666
+ mode = self.get_operation_mode()
667
+ tools_info = f", {self.tool_manager.tool_count()} tools" if self.enable_tools else ", no tools"
668
+ vector_info = ", vector store" if self._use_vector else ""
669
+ return f"{self.name} ({mode} mode{tools_info}{vector_info})"