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,554 @@
1
+ """
2
+ Office365 Tools Implementation.
3
+
4
+ Specific tools for interacting with Office365 services:
5
+ - CreateDraftMessage: Create email drafts
6
+ - CreateEvent: Create calendar events
7
+ - SearchEmail: Search through emails
8
+ - SendEmail: Send emails directly
9
+ """
10
+ from typing import Dict, Any, Optional, List, Type
11
+ from pydantic import BaseModel, Field
12
+ from msgraph.generated.models.email_address import EmailAddress
13
+ from msgraph.generated.models.item_body import ItemBody
14
+ from msgraph.generated.models.body_type import BodyType
15
+ from msgraph.generated.models.event import Event
16
+ from msgraph.generated.models.date_time_time_zone import DateTimeTimeZone
17
+ from msgraph.generated.models.location import Location
18
+ from msgraph.generated.models.attendee import Attendee
19
+ from msgraph.generated.models.attendee_type import AttendeeType
20
+ from msgraph.generated.models.importance import Importance
21
+ from kiota_abstractions.base_request_configuration import RequestConfiguration
22
+
23
+ from .base import O365Tool, O365ToolArgsSchema, O365Client
24
+
25
+
26
+ # ============================================================================
27
+ # CREATE EVENT TOOL
28
+ # ============================================================================
29
+
30
+ class CreateEventArgs(O365ToolArgsSchema):
31
+ """Arguments for creating a calendar event."""
32
+ subject: str = Field(
33
+ description="Event subject/title"
34
+ )
35
+ start_datetime: str = Field(
36
+ description="Event start date and time in ISO format (e.g., '2025-01-20T14:00:00')"
37
+ )
38
+ end_datetime: str = Field(
39
+ description="Event end date and time in ISO format (e.g., '2025-01-20T15:00:00')"
40
+ )
41
+ timezone: str = Field(
42
+ default="UTC",
43
+ description="Timezone for the event (e.g., 'America/New_York', 'Europe/London')"
44
+ )
45
+ body: Optional[str] = Field(
46
+ default=None,
47
+ description="Event description/body content"
48
+ )
49
+ location: Optional[str] = Field(
50
+ default=None,
51
+ description="Event location (e.g., 'Conference Room A', 'Zoom Meeting')"
52
+ )
53
+ attendees: Optional[List[str]] = Field(
54
+ default=None,
55
+ description="List of attendee email addresses"
56
+ )
57
+ is_online_meeting: bool = Field(
58
+ default=False,
59
+ description="Whether to create an online meeting (Teams meeting)"
60
+ )
61
+ is_all_day: bool = Field(
62
+ default=False,
63
+ description="Whether this is an all-day event"
64
+ )
65
+
66
+
67
+ class CreateEventTool(O365Tool):
68
+ """
69
+ Tool for creating calendar events in Office365.
70
+
71
+ This tool creates calendar events with support for:
72
+ - Attendees and invitations
73
+ - Online meetings (Teams)
74
+ - All-day events
75
+ - Timezone handling
76
+ - Location and descriptions
77
+
78
+ Examples:
79
+ # Create a simple meeting
80
+ result = await tool.run(
81
+ subject="Team Standup",
82
+ start_datetime="2025-01-20T09:00:00",
83
+ end_datetime="2025-01-20T09:30:00",
84
+ timezone="America/New_York",
85
+ attendees=["team@company.com"]
86
+ )
87
+
88
+ # Create an online meeting
89
+ result = await tool.run(
90
+ subject="Client Presentation",
91
+ start_datetime="2025-01-21T14:00:00",
92
+ end_datetime="2025-01-21T15:00:00",
93
+ body="Presenting Q4 results",
94
+ attendees=["client@external.com"],
95
+ is_online_meeting=True
96
+ )
97
+
98
+ # Create an all-day event
99
+ result = await tool.run(
100
+ subject="Company Holiday",
101
+ start_datetime="2025-12-25T00:00:00",
102
+ end_datetime="2025-12-25T23:59:59",
103
+ is_all_day=True
104
+ )
105
+ """
106
+
107
+ name: str = "create_event"
108
+ description: str = (
109
+ "Create a calendar event in Office365. "
110
+ "Supports attendees, online meetings, locations, and timezone handling."
111
+ )
112
+ args_schema: Type[BaseModel] = CreateEventArgs
113
+
114
+ async def _execute_graph_operation(
115
+ self,
116
+ client: O365Client,
117
+ **kwargs
118
+ ) -> Dict[str, Any]:
119
+ """
120
+ Create a calendar event using Microsoft Graph API.
121
+
122
+ Args:
123
+ client: Authenticated O365Client
124
+ **kwargs: Event parameters
125
+
126
+ Returns:
127
+ Dict with event details
128
+ """
129
+ # Extract parameters
130
+ subject = kwargs.get('subject')
131
+ start_dt = kwargs.get('start_datetime')
132
+ end_dt = kwargs.get('end_datetime')
133
+ timezone = kwargs.get('timezone', 'UTC')
134
+ body_content = kwargs.get('body')
135
+ location_name = kwargs.get('location')
136
+ attendee_emails = kwargs.get('attendees', [])
137
+ is_online_meeting = kwargs.get('is_online_meeting', False)
138
+ is_all_day = kwargs.get('is_all_day', False)
139
+ user_id = kwargs.get('user_id')
140
+
141
+ try:
142
+ # Get user context
143
+ mailbox = client.get_user_context(user_id=user_id)
144
+
145
+ # Build event object
146
+ event = Event()
147
+ event.subject = subject
148
+ event.is_all_day = is_all_day
149
+
150
+ # Set start and end times
151
+ event.start = DateTimeTimeZone()
152
+ event.start.date_time = start_dt
153
+ event.start.time_zone = timezone
154
+
155
+ event.end = DateTimeTimeZone()
156
+ event.end.date_time = end_dt
157
+ event.end.time_zone = timezone
158
+
159
+ # Set body if provided
160
+ if body_content:
161
+ event.body = ItemBody()
162
+ event.body.content = body_content
163
+ event.body.content_type = BodyType.Text
164
+
165
+ # Set location if provided
166
+ if location_name:
167
+ event.location = Location()
168
+ event.location.display_name = location_name
169
+
170
+ # Set attendees if provided
171
+ if attendee_emails:
172
+ event.attendees = []
173
+ for email in attendee_emails:
174
+ attendee = Attendee()
175
+ attendee.type = AttendeeType.Required
176
+ attendee.email_address = EmailAddress()
177
+ attendee.email_address.address = email
178
+ event.attendees.append(attendee)
179
+
180
+ # Enable online meeting if requested
181
+ if is_online_meeting:
182
+ event.is_online_meeting = True
183
+ # Note: online_meeting_provider might need to be set differently
184
+ # depending on your Graph SDK version
185
+ try:
186
+ event.online_meeting_provider = "teamsForBusiness"
187
+ except AttributeError:
188
+ # Some versions use a different property
189
+ self.logger.warning("Could not set online_meeting_provider, using default")
190
+
191
+ # Create the event
192
+ self.logger.info(f"Creating event: {subject}")
193
+ created_event = await mailbox.events.post(event)
194
+
195
+ self.logger.info(f"Created event with ID: {created_event.id}")
196
+
197
+ result = {
198
+ "status": "created",
199
+ "id": created_event.id,
200
+ "subject": created_event.subject,
201
+ "start": start_dt,
202
+ "end": end_dt,
203
+ "timezone": timezone,
204
+ "location": location_name,
205
+ "attendees": attendee_emails,
206
+ "is_online_meeting": is_online_meeting,
207
+ "is_all_day": is_all_day,
208
+ "web_link": created_event.web_link
209
+ }
210
+
211
+ # Add online meeting info if available
212
+ if is_online_meeting and hasattr(created_event, 'online_meeting') and created_event.online_meeting:
213
+ result["join_url"] = getattr(created_event.online_meeting, 'join_url', None)
214
+
215
+ return result
216
+
217
+ except Exception as e:
218
+ self.logger.error(f"Failed to create event: {e}", exc_info=True)
219
+ raise
220
+
221
+ # events.py (Continued)
222
+
223
+ # ============================================================================
224
+ # LIST EVENTS TOOL
225
+ # ============================================================================
226
+
227
+ class ListEventArgs(O365ToolArgsSchema):
228
+ """Arguments for listing calendar events."""
229
+ start_datetime: Optional[str] = Field(
230
+ default=None,
231
+ description="Optional: Start date and time for the range query in ISO format (e.g., '2025-01-01T00:00:00'). Required for /instances endpoint."
232
+ )
233
+ end_datetime: Optional[str] = Field(
234
+ default=None,
235
+ description="Optional: End date and time for the range query in ISO format (e.g., '2025-01-31T23:59:59'). Required for /instances endpoint."
236
+ )
237
+ top: Optional[int] = Field(
238
+ default=10,
239
+ description="Maximum number of events to return. Defaults to 10."
240
+ )
241
+ filter: Optional[str] = Field(
242
+ default=None,
243
+ description="OData $filter string for advanced filtering (e.g., 'subject eq \"Team Standup\"')"
244
+ )
245
+ timezone: str = Field(
246
+ default="UTC",
247
+ description="Timezone for event start/end times in the response (e.g., 'America/New_York')."
248
+ )
249
+
250
+ class ListEventsTool(O365Tool):
251
+ """
252
+ Tool for listing events in the user's calendar.
253
+
254
+ Uses OData query parameters ($top, $filter) for customization and
255
+ `Prefer: outlook.timezone` header to control response timezones.
256
+ """
257
+ name: str = "list_events"
258
+ description: str = (
259
+ "List upcoming or recent calendar events. "
260
+ "Can filter by date range and use OData queries for advanced filtering."
261
+ )
262
+ args_schema: Type[BaseModel] = ListEventArgs
263
+
264
+ async def _execute_graph_operation(
265
+ self,
266
+ client: O365Client,
267
+ **kwargs
268
+ ) -> Dict[str, Any]:
269
+ """
270
+ List calendar events using Microsoft Graph API.
271
+ """
272
+ start_dt = kwargs.get('start_datetime')
273
+ end_dt = kwargs.get('end_datetime')
274
+ top = kwargs.get('top', 10)
275
+ filter_query = kwargs.get('filter')
276
+ timezone = kwargs.get('timezone', 'UTC')
277
+ user_id = kwargs.get('user_id')
278
+
279
+ try:
280
+ mailbox = client.get_user_context(user_id=user_id)
281
+
282
+ # Use RequestConfiguration for headers and query parameters
283
+ request_configuration = RequestConfiguration()
284
+
285
+ # Set the timezone preference header
286
+ request_configuration.headers.add("Prefer", f"outlook.timezone=\"{timezone}\"")
287
+
288
+ # Set top for pagination
289
+ request_configuration.query_parameters['$top'] = top
290
+
291
+ # Set filter
292
+ if filter_query:
293
+ request_configuration.query_parameters['$filter'] = filter_query
294
+
295
+ # Check for date range which uses the /calendarView endpoint (or /events if no range)
296
+ if start_dt and end_dt:
297
+ self.logger.info(f"Listing events between {start_dt} and {end_dt} for timezone {timezone}")
298
+
299
+ # Note: CalendarView requires start and end date
300
+ request_configuration.query_parameters['startDateTime'] = start_dt
301
+ request_configuration.query_parameters['endDateTime'] = end_dt
302
+
303
+ events_response = await mailbox.calendar.calendar_view.get(request_configuration=request_configuration)
304
+ else:
305
+ self.logger.info(f"Listing events with top={top}, timezone={timezone}")
306
+ events_response = await mailbox.events.get(request_configuration=request_configuration)
307
+
308
+ event_list = events_response.value or []
309
+
310
+ # Format the list for output
311
+ results = [
312
+ {
313
+ "id": event.id,
314
+ "subject": event.subject,
315
+ "start": event.start.date_time if event.start else None,
316
+ "end": event.end.date_time if event.end else None,
317
+ "location": event.location.display_name if event.location else None,
318
+ "is_online_meeting": event.is_online_meeting,
319
+ "web_link": event.web_link
320
+ } for event in event_list
321
+ ]
322
+
323
+ return {
324
+ "status": "success",
325
+ "count": len(results),
326
+ "events": results
327
+ }
328
+
329
+ except Exception as e:
330
+ self.logger.error(f"Failed to list events: {e}", exc_info=True)
331
+ raise
332
+
333
+ # ============================================================================
334
+ # GET EVENT TOOL
335
+ # ============================================================================
336
+
337
+ class GetEventArgs(O365ToolArgsSchema):
338
+ """Arguments for retrieving a single calendar event by ID."""
339
+ event_id: str = Field(
340
+ description="The unique ID of the calendar event to retrieve."
341
+ )
342
+ timezone: str = Field(
343
+ default="UTC",
344
+ description="Timezone for event start/end times in the response (e.g., 'America/New_York')."
345
+ )
346
+
347
+ class GetEventTool(O365Tool):
348
+ """
349
+ Tool for retrieving a single calendar event by its ID.
350
+ """
351
+ name: str = "get_event"
352
+ description: str = (
353
+ "Retrieve the full details of a single calendar event using its unique ID."
354
+ )
355
+ args_schema: Type[BaseModel] = GetEventArgs
356
+
357
+ async def _execute_graph_operation(
358
+ self,
359
+ client: O365Client,
360
+ **kwargs
361
+ ) -> Dict[str, Any]:
362
+ """
363
+ Get a calendar event by ID using Microsoft Graph API.
364
+ """
365
+ event_id = kwargs.get('event_id')
366
+ timezone = kwargs.get('timezone', 'UTC')
367
+ user_id = kwargs.get('user_id')
368
+
369
+ try:
370
+ mailbox = client.get_user_context(user_id=user_id)
371
+
372
+ # Use RequestConfiguration for headers
373
+ request_configuration = RequestConfiguration()
374
+ request_configuration.headers.add("Prefer", f"outlook.timezone=\"{timezone}\"")
375
+
376
+ self.logger.info(f"Retrieving event with ID: {event_id}")
377
+
378
+ event = await mailbox.events.by_event_id(event_id).get(
379
+ request_configuration=request_configuration
380
+ )
381
+
382
+ # Format the output
383
+ attendees_list = [
384
+ {
385
+ "email": a.email_address.address,
386
+ "type": a.type.value,
387
+ "response": a.status.response.value
388
+ } for a in event.attendees
389
+ ] if event.attendees else []
390
+
391
+ return {
392
+ "status": "success",
393
+ "id": event.id,
394
+ "subject": event.subject,
395
+ "body_preview": event.body_preview,
396
+ "body": event.body.content if event.body else None,
397
+ "start": event.start.date_time if event.start else None,
398
+ "end": event.end.date_time if event.end else None,
399
+ "timezone": event.start.time_zone if event.start else None,
400
+ "location": event.location.display_name if event.location else None,
401
+ "is_online_meeting": event.is_online_meeting,
402
+ "join_url": event.online_meeting.join_url if event.online_meeting else None,
403
+ "attendees": attendees_list,
404
+ "web_link": event.web_link
405
+ }
406
+
407
+ except Exception as e:
408
+ self.logger.error(f"Failed to get event {event_id}: {e}", exc_info=True)
409
+ raise
410
+
411
+ # ============================================================================
412
+ # UPDATE EVENT TOOL
413
+ # ============================================================================
414
+
415
+ class UpdateEventArgs(O365ToolArgsSchema):
416
+ """Arguments for updating a calendar event."""
417
+ event_id: str = Field(
418
+ description="The unique ID of the calendar event to update."
419
+ )
420
+ subject: Optional[str] = Field(
421
+ default=None,
422
+ description="Optional: New event subject/title"
423
+ )
424
+ start_datetime: Optional[str] = Field(
425
+ default=None,
426
+ description="Optional: New event start date and time in ISO format (e.g., '2025-01-20T14:00:00')"
427
+ )
428
+ end_datetime: Optional[str] = Field(
429
+ default=None,
430
+ description="Optional: New event end date and time in ISO format (e.g., '2025-01-20T15:00:00')"
431
+ )
432
+ timezone: str = Field(
433
+ default="UTC",
434
+ description="Timezone for the event's start/end times (e.g., 'America/New_York')."
435
+ )
436
+ body: Optional[str] = Field(
437
+ default=None,
438
+ description="Optional: New event description/body content"
439
+ )
440
+ location: Optional[str] = Field(
441
+ default=None,
442
+ description="Optional: New event location (e.g., 'Conference Room B', 'New Zoom Link'). Set to empty string to clear."
443
+ )
444
+ # Note: Updating attendees is complex (add/remove) and usually done via a full Event object replacement/PATCH,
445
+ # but for simplicity, we'll keep the core fields for this tool.
446
+ send_updates: Optional[bool] = Field(
447
+ default=True,
448
+ description="Whether to send update notifications to attendees. Defaults to True."
449
+ )
450
+ is_online_meeting: Optional[bool] = Field(
451
+ default=None,
452
+ description="Optional: Whether to make this an online meeting (Teams meeting)."
453
+ )
454
+
455
+ class UpdateEventTool(O365Tool):
456
+ """
457
+ Tool for updating an existing calendar event in Office365.
458
+
459
+ The update uses a PATCH operation, so only fields provided will be updated.
460
+ """
461
+ name: str = "update_event"
462
+ description: str = (
463
+ "Update an existing calendar event using its ID. "
464
+ "Only provide the fields you want to change."
465
+ )
466
+ args_schema: Type[BaseModel] = UpdateEventArgs
467
+
468
+ async def _execute_graph_operation(
469
+ self,
470
+ client: O365Client,
471
+ **kwargs
472
+ ) -> Dict[str, Any]:
473
+ """
474
+ Update a calendar event using Microsoft Graph API (PATCH).
475
+ """
476
+ event_id = kwargs.get('event_id')
477
+ user_id = kwargs.get('user_id')
478
+ timezone = kwargs.get('timezone', 'UTC')
479
+
480
+ # Determine if we should send updates
481
+ send_updates = kwargs.get('send_updates', True)
482
+
483
+ # Build the update object (Event model with only fields to update)
484
+ update_event = Event()
485
+
486
+ if subject := kwargs.get('subject'):
487
+ update_event.subject = subject
488
+
489
+ if body_content := kwargs.get('body'):
490
+ update_event.body = ItemBody(content=body_content, content_type=BodyType.Text)
491
+
492
+ if location_name := kwargs.get('location'):
493
+ # Clear location if an empty string is passed
494
+ if location_name.strip() == "":
495
+ update_event.location = Location(display_name="")
496
+ else:
497
+ update_event.location = Location(display_name=location_name)
498
+
499
+ # Handle start and end time updates (requires both to be consistently set if changing)
500
+ start_dt = kwargs.get('start_datetime')
501
+ end_dt = kwargs.get('end_datetime')
502
+
503
+ if start_dt:
504
+ update_event.start = DateTimeTimeZone(date_time=start_dt, time_zone=timezone)
505
+ if end_dt:
506
+ update_event.end = DateTimeTimeZone(date_time=end_dt, time_zone=timezone)
507
+
508
+ if is_online_meeting := kwargs.get('is_online_meeting'):
509
+ update_event.is_online_meeting = is_online_meeting
510
+ # The online_meeting_provider might need to be set if creating a new one
511
+ if is_online_meeting:
512
+ try:
513
+ update_event.online_meeting_provider = "teamsForBusiness"
514
+ except AttributeError:
515
+ self.logger.warning("Could not set online_meeting_provider in update")
516
+
517
+ # Set up request configuration for sending updates header
518
+ request_configuration = RequestConfiguration()
519
+ if send_updates is False:
520
+ request_configuration.headers.add(
521
+ "Prefer", "outlook.sendUpdateNotificationsForRecipients=\"None\""
522
+ )
523
+ elif send_updates is True:
524
+ # Send updates to all attendees
525
+ request_configuration.headers.add(
526
+ "Prefer", "outlook.sendUpdateNotificationsForRecipients=\"All\""
527
+ )
528
+
529
+
530
+ try:
531
+ mailbox = client.get_user_context(user_id=user_id)
532
+ self.logger.info(f"Updating event with ID: {event_id}. Send updates: {send_updates}")
533
+
534
+ # Send the PATCH request
535
+ updated_event = await mailbox.events.by_event_id(event_id).patch(
536
+ update_event,
537
+ request_configuration=request_configuration
538
+ )
539
+
540
+ # Note: The PATCH request typically returns a 200 OK or 204 No Content
541
+ # and may not return the full updated object in all SDK versions.
542
+ # We return a status and the ID.
543
+ return {
544
+ "status": "updated",
545
+ "id": event_id,
546
+ "subject": subject or updated_event.subject,
547
+ "start": start_dt or updated_event.start.date_time if updated_event.start else None,
548
+ "end": end_dt or updated_event.end.date_time if updated_event.end else None,
549
+ "web_link": updated_event.web_link
550
+ }
551
+
552
+ except Exception as e:
553
+ self.logger.error(f"Failed to update event {event_id}: {e}", exc_info=True)
554
+ raise