├── .env ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Clippy2.ipynb ├── ClippywithUI.py ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── azureAI.ipynb ├── finalRAG.ipynb ├── firstAgent.ipynb └── requirements.txt /.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=dasfadsfsa-dafdafdsfas-sfadsfasdfsd 2 | TAVILY_API_KEY= 3 | LANGCHAIN_API_KEY= 4 | CLIENT_ID= 5 | CLIENT_SECRET= 6 | TENANT_ID= 7 | USERNAME= 8 | AZURE_OPENAI_API_KEY= 9 | AZURE_OPENAI_ENDPOINT= 10 | GRAPH_ACCESS_TOKEN= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | # but not Directory.Build.rsp, as it configures directory-level build defaults 86 | !Directory.Build.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.tmp_proj 93 | *_wpftmp.csproj 94 | *.log 95 | *.tlog 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 300 | *.vbp 301 | 302 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 303 | *.dsw 304 | *.dsp 305 | 306 | # Visual Studio 6 technical files 307 | *.ncb 308 | *.aps 309 | 310 | # Visual Studio LightSwitch build output 311 | **/*.HTMLClient/GeneratedArtifacts 312 | **/*.DesktopClient/GeneratedArtifacts 313 | **/*.DesktopClient/ModelManifest.xml 314 | **/*.Server/GeneratedArtifacts 315 | **/*.Server/ModelManifest.xml 316 | _Pvt_Extensions 317 | 318 | # Paket dependency manager 319 | .paket/paket.exe 320 | paket-files/ 321 | 322 | # FAKE - F# Make 323 | .fake/ 324 | 325 | # CodeRush personal settings 326 | .cr/personal 327 | 328 | # Python Tools for Visual Studio (PTVS) 329 | __pycache__/ 330 | *.pyc 331 | 332 | # Cake - Uncomment if you are using it 333 | # tools/** 334 | # !tools/packages.config 335 | 336 | # Tabs Studio 337 | *.tss 338 | 339 | # Telerik's JustMock configuration file 340 | *.jmconfig 341 | 342 | # BizTalk build output 343 | *.btp.cs 344 | *.btm.cs 345 | *.odx.cs 346 | *.xsd.cs 347 | 348 | # OpenCover UI analysis results 349 | OpenCover/ 350 | 351 | # Azure Stream Analytics local run output 352 | ASALocalRun/ 353 | 354 | # MSBuild Binary and Structured Log 355 | *.binlog 356 | 357 | # NVidia Nsight GPU debugger configuration file 358 | *.nvuser 359 | 360 | # MFractors (Xamarin productivity tool) working folder 361 | .mfractor/ 362 | 363 | # Local History for Visual Studio 364 | .localhistory/ 365 | 366 | # Visual Studio History (VSHistory) files 367 | .vshistory/ 368 | 369 | # BeatPulse healthcheck temp database 370 | healthchecksdb 371 | 372 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 373 | MigrationBackup/ 374 | 375 | # Ionide (cross platform F# VS Code tools) working folder 376 | .ionide/ 377 | 378 | # Fody - auto-generated XML schema 379 | FodyWeavers.xsd 380 | 381 | # VS Code files for those working on multiple tools 382 | .vscode/* 383 | !.vscode/settings.json 384 | !.vscode/tasks.json 385 | !.vscode/launch.json 386 | !.vscode/extensions.json 387 | *.code-workspace 388 | 389 | # Local History for Visual Studio Code 390 | .history/ 391 | 392 | # Windows Installer files from build outputs 393 | *.cab 394 | *.msi 395 | *.msix 396 | *.msm 397 | *.msp 398 | 399 | # JetBrains Rider 400 | *.sln.iml 401 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /Clippy2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "id": "51139436-d2af-44ca-8d0d-4d3c9848cd96", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "Hello! I am your personal companion, Clippy!. Ask me about your meetings. Or the weather. I can answer most things about the world! \n", 14 | "\n", 15 | "---------------------------------------------------------------------------------------------------------\n", 16 | "User prompt: Hey Clippy! I am Sai. I need to go to Paris, France for a work trip. Can you help me plan that?\n", 17 | "\n", 18 | "\n", 19 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 20 | "\u001b[32;1m\u001b[1;3mOf course, Sai! I'd be happy to help you plan your work trip to Paris, France. Here are a few things we can start with:\n", 21 | "\n", 22 | "1. **Check the Weather**: Knowing the current weather in Paris can help you pack appropriately.\n", 23 | "2. **Travel Itinerary**: Do you have specific dates for your travel? I can help you with your flight and accommodation options.\n", 24 | "3. **Events & Meetings**: I can check your calendar for any scheduled events and help you manage your work commitments while you're away.\n", 25 | "4. **Contacts in Paris**: If you need to meet anyone in Paris, I can search for contacts in that location.\n", 26 | "5. **Travel Policies**: I can provide information on your company's travel policies and any necessary approvals.\n", 27 | "6. **Local Information**: If you're interested in any specific places or activities in Paris, I can look them up for you.\n", 28 | "\n", 29 | "Let me know which of these you'd like to start with, or if there's anything else you need!\u001b[0m\n", 30 | "\n", 31 | "\u001b[1m> Finished chain.\u001b[0m\n", 32 | "---------------------------------------------------------------------------------------------------------\n", 33 | "User prompt: Cool! I want to see if I have any important meetings on 11th and 12th of February?\n", 34 | "\n", 35 | "\n", 36 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 37 | "\u001b[32;1m\u001b[1;3m\n", 38 | "Invoking: `getevents` with `{}`\n", 39 | "\n", 40 | "\n", 41 | "\u001b[0m\u001b[33;1m\u001b[1;3m{'@odata.context': \"https://graph.microsoft.com/v1.0/$metadata#users('2be45935-77e0-45e6-a816-42e5966c0b1c')/events\", 'value': [{'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABIv3GKg==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjFAAA=', 'createdDateTime': '2025-01-14T20:14:18.2622852Z', 'lastModifiedDateTime': '2025-01-14T20:14:30.1639677Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABIv3GKg==', 'categories': [], 'transactionId': 'b64881fa-d1a8-1362-12c0-35fcdc2afbe7', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E00800000000846B02E4C066DB01000000000000000010000000B73CA37223FE144494F78B27C63B6AE2', 'uid': '040000008200E00074C5B7101A82E00800000000846B02E4C066DB01000000000000000010000000B73CA37223FE144494F78B27C63B6AE2', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Dentist Appointment', 'bodyPreview': '', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjFAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': False, 'onlineMeetingProvider': 'unknown', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': ''}, 'start': {'dateTime': '2025-01-14T18:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-14T21:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': '', 'locationType': 'default', 'uniqueIdType': 'unknown', 'address': {}, 'coordinates': {}}, 'locations': [], 'recurrence': None, 'attendees': [], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': None, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABIv3EOw==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjEAAA=', 'createdDateTime': '2025-01-14T20:13:40.8446921Z', 'lastModifiedDateTime': '2025-01-14T20:13:54.1997294Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABIv3EOw==', 'categories': [], 'transactionId': '9e853702-a0e4-9d5f-1cbb-a544ace5d8bf', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E008000000005138B4CDC066DB01000000000000000010000000DAF763CAFC85D044907D88B292BCF954', 'uid': '040000008200E00074C5B7101A82E008000000005138B4CDC066DB01000000000000000010000000DAF763CAFC85D044907D88B292BCF954', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Focus Hours', 'bodyPreview': '', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjEAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': False, 'onlineMeetingProvider': 'unknown', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': ''}, 'start': {'dateTime': '2025-01-17T17:00:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-18T00:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': '', 'locationType': 'default', 'uniqueIdType': 'unknown', 'address': {}, 'coordinates': {}}, 'locations': [], 'recurrence': None, 'attendees': [], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': None, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABIv2/WA==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjDAAA=', 'createdDateTime': '2025-01-14T17:49:18.040024Z', 'lastModifiedDateTime': '2025-01-14T17:49:50.3802554Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABIv2/WA==', 'categories': [], 'transactionId': '178630b1-38e4-3efa-d112-7cf1d9829ff3', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E00800000000D66744A2AC66DB01000000000000000010000000A5E94F3C1FD4B443BC73C26FE4F9672C', 'uid': '040000008200E00074C5B7101A82E00800000000D66744A2AC66DB01000000000000000010000000A5E94F3C1FD4B443BC73C26FE4F9672C', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Focus Hours', 'bodyPreview': '', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjDAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': False, 'onlineMeetingProvider': 'unknown', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': ''}, 'start': {'dateTime': '2025-01-15T18:00:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-15T20:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': '', 'locationType': 'default', 'uniqueIdType': 'unknown', 'address': {}, 'coordinates': {}}, 'locations': [], 'recurrence': None, 'attendees': [], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': None, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABIv2/mA==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjCAAA=', 'createdDateTime': '2025-01-14T17:49:05.7752435Z', 'lastModifiedDateTime': '2025-01-14T17:51:08.4088329Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABIv2/mA==', 'categories': [], 'transactionId': '051acb34-2a31-12df-c3de-7443384b5c46', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E00800000000EDC5F49AAC66DB01000000000000000010000000BE50350F42D77147945D10B9C0A1B6D1', 'uid': '040000008200E00074C5B7101A82E00800000000EDC5F49AAC66DB01000000000000000010000000BE50350F42D77147945D10B9C0A1B6D1', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'LT Review', 'bodyPreview': '________________________________________________________________________________\\r\\nMicrosoft Teams Need help?\\r\\nJoin the meeting now\\r\\nMeeting ID: 214 526 079 36\\r\\nPasscode: KZ95Ty7e\\r\\n________________________________\\r\\nFor organizers: Meeting options\\r\\n______', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjCAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': True, 'onlineMeetingProvider': 'teamsForBusiness', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': '\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
Microsoft Teams\\r\\n\\r\\nNeed help?
\\r\\n
Join\\r\\n the meeting now
\\r\\n
Meeting ID:\\r\\n214 526 079 36\\r\\n
\\r\\n
Passcode:\\r\\nKZ95Ty7e\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
For organizers:\\r\\nMeeting\\r\\n options
\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
\\r\\n\\r\\n\\r\\n'}, 'start': {'dateTime': '2025-01-15T21:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-15T22:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}, 'locations': [{'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}], 'recurrence': None, 'attendees': [{'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Nestor Wilke', 'address': 'NestorW@tfdgr.onmicrosoft.com'}}], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': {'joinUrl': 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_OTM0MDVmMTEtNTZlNy00YTJiLWJlZDktNzY5ZDIwYWRkNDEz%40thread.v2/0?context=%7b%22Tid%22%3a%2295e4fdc7-aaab-48b7-a4a2-4b219b877a6d%22%2c%22Oid%22%3a%222be45935-77e0-45e6-a816-42e5966c0b1c%22%7d'}, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABIv2/mw==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjBAAA=', 'createdDateTime': '2025-01-14T17:48:39.1592667Z', 'lastModifiedDateTime': '2025-01-14T17:51:49.6303078Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABIv2/mw==', 'categories': [], 'transactionId': '65416d37-9742-0822-e72a-5ddc5016c8b8', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E008000000006066188BAC66DB0100000000000000001000000041C866EE949158408C89869D321A51B4', 'uid': '040000008200E00074C5B7101A82E008000000006066188BAC66DB0100000000000000001000000041C866EE949158408C89869D321A51B4', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Pitch Deck Review', 'bodyPreview': '________________________________________________________________________________\\r\\nMicrosoft Teams Need help?\\r\\nJoin the meeting now\\r\\nMeeting ID: 216 567 765 744\\r\\nPasscode: k7Z82L5w\\r\\n________________________________\\r\\nFor organizers: Meeting options\\r\\n_____', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEjLBjBAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': True, 'onlineMeetingProvider': 'teamsForBusiness', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': '\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
Microsoft Teams\\r\\n\\r\\nNeed help?
\\r\\n
Join\\r\\n the meeting now
\\r\\n
Meeting ID:\\r\\n216 567 765 744\\r\\n
\\r\\n
Passcode:\\r\\nk7Z82L5w\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
For organizers:\\r\\nMeeting\\r\\n options
\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
\\r\\n\\r\\n\\r\\n'}, 'start': {'dateTime': '2025-01-15T16:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-15T18:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}, 'locations': [{'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}], 'recurrence': None, 'attendees': [{'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Adam Grotesque', 'address': 'adamg@montoso.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Terry Gordo', 'address': 'terryg@montoso.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Lynne Robbins', 'address': 'LynneR@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Lee Gu', 'address': 'LeeG@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Patti Fernandez', 'address': 'PattiF@tfdgr.onmicrosoft.com'}}], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': {'joinUrl': 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_YTA4ZjFhZGMtODg3Ny00YmUwLWJlNWQtMjFjMTI4NDM4MTI5%40thread.v2/0?context=%7b%22Tid%22%3a%2295e4fdc7-aaab-48b7-a4a2-4b219b877a6d%22%2c%22Oid%22%3a%222be45935-77e0-45e6-a816-42e5966c0b1c%22%7d'}, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABHi8AoA==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9V0AAA=', 'createdDateTime': '2025-01-10T17:57:16.6247634Z', 'lastModifiedDateTime': '2025-01-10T17:59:56.6214156Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABHi8AoA==', 'categories': [], 'transactionId': '6ced3088-0dcf-fb21-2da6-43a6398378bf', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E008000000004B8DDF158963DB010000000000000000100000008D19D744D4AFD84BA42C28458C1CB5A7', 'uid': '040000008200E00074C5B7101A82E008000000004B8DDF158963DB010000000000000000100000008D19D744D4AFD84BA42C28458C1CB5A7', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Pitch Deck Review', 'bodyPreview': '________________________________________________________________________________\\r\\nMicrosoft Teams Need help?\\r\\nJoin the meeting now\\r\\nMeeting ID: 263 681 324 69\\r\\nPasscode: Xo9XY798\\r\\n________________________________\\r\\nFor organizers: Meeting options\\r\\n______', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9V0AAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': True, 'onlineMeetingProvider': 'teamsForBusiness', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': '\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
Microsoft Teams\\r\\n\\r\\nNeed help?
\\r\\n
Join\\r\\n the meeting now
\\r\\n
Meeting ID:\\r\\n263 681 324 69\\r\\n
\\r\\n
Passcode:\\r\\nXo9XY798\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
For organizers:\\r\\nMeeting\\r\\n options
\\r\\n
\\r\\n
\\r\\n
________________________________________________________________________________
\\r\\n
\\r\\n\\r\\n\\r\\n'}, 'start': {'dateTime': '2025-01-10T19:00:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-10T20:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}, 'locations': [{'displayName': 'Microsoft Teams Meeting', 'locationType': 'default', 'uniqueId': 'Microsoft Teams Meeting', 'uniqueIdType': 'private'}], 'recurrence': None, 'attendees': [{'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Grady Archie', 'address': 'GradyA@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Adam Grotesque', 'address': 'adamg@montoso.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Adele Vance', 'address': 'AdeleV@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Lidia Holloway', 'address': 'LidiaH@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Johanna Lorenz', 'address': 'JohannaL@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Miriam Graham', 'address': 'MiriamG@tfdgr.onmicrosoft.com'}}, {'type': 'required', 'status': {'response': 'none', 'time': '0001-01-01T00:00:00Z'}, 'emailAddress': {'name': 'Isaiah Langer', 'address': 'IsaiahL@tfdgr.onmicrosoft.com'}}], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': {'joinUrl': 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_MDgxNDBhZDgtMThhMy00ZGIxLTk1MjktYjU1YTJiYjZhYmZj%40thread.v2/0?context=%7b%22Tid%22%3a%2295e4fdc7-aaab-48b7-a4a2-4b219b877a6d%22%2c%22Oid%22%3a%222be45935-77e0-45e6-a816-42e5966c0b1c%22%7d'}, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABHi8ANA==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9VzAAA=', 'createdDateTime': '2025-01-10T17:56:54.3563722Z', 'lastModifiedDateTime': '2025-01-10T17:56:55.3454895Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABHi8ANA==', 'categories': [], 'transactionId': '09e632e5-ef7b-ebf4-5cf3-368ff8a53bc9', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E0080000000000029A088963DB01000000000000000010000000448D2C88D82F9048A4416E5D5AD6796D', 'uid': '040000008200E00074C5B7101A82E0080000000000029A088963DB01000000000000000010000000448D2C88D82F9048A4416E5D5AD6796D', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Focus Time', 'bodyPreview': '', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9VzAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': False, 'onlineMeetingProvider': 'unknown', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': ''}, 'start': {'dateTime': '2025-01-07T17:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-07T18:00:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': '', 'locationType': 'default', 'uniqueIdType': 'unknown', 'address': {}, 'coordinates': {}}, 'locations': [], 'recurrence': None, 'attendees': [], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': None, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}, {'@odata.etag': 'W/\"84g3LUa6KEK5yANLVuHCtQABHi8ALQ==\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9VyAAA=', 'createdDateTime': '2025-01-10T17:56:41.3443286Z', 'lastModifiedDateTime': '2025-01-10T17:56:42.7242356Z', 'changeKey': '84g3LUa6KEK5yANLVuHCtQABHi8ALQ==', 'categories': [], 'transactionId': 'd9e89c8c-c04d-5ed6-6812-7872b0d3778a', 'originalStartTimeZone': 'Pacific Standard Time', 'originalEndTimeZone': 'Pacific Standard Time', 'iCalUId': '040000008200E00074C5B7101A82E0080000000019EFD7008963DB010000000000000000100000007384F48105644F43BBAF1DA7D314C553', 'uid': '040000008200E00074C5B7101A82E0080000000019EFD7008963DB010000000000000000100000007384F48105644F43BBAF1DA7D314C553', 'reminderMinutesBeforeStart': 15, 'isReminderOn': True, 'hasAttachments': False, 'subject': 'Pitch Deck Review', 'bodyPreview': '', 'importance': 'normal', 'sensitivity': 'normal', 'isAllDay': False, 'isCancelled': False, 'isOrganizer': True, 'responseRequested': True, 'seriesMasterId': None, 'showAs': 'busy', 'type': 'singleInstance', 'webLink': 'https://outlook.office365.com/owa/?itemid=AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAENAADziDctRrooQrnIA0tW4cK1AAEeW9VyAAA%3D&exvsurl=1&path=/calendar/item', 'onlineMeetingUrl': None, 'isOnlineMeeting': False, 'onlineMeetingProvider': 'unknown', 'allowNewTimeProposals': True, 'occurrenceId': None, 'isDraft': False, 'hideAttendees': False, 'responseStatus': {'response': 'organizer', 'time': '0001-01-01T00:00:00Z'}, 'body': {'contentType': 'html', 'content': ''}, 'start': {'dateTime': '2025-01-08T19:30:00.0000000', 'timeZone': 'UTC'}, 'end': {'dateTime': '2025-01-08T20:30:00.0000000', 'timeZone': 'UTC'}, 'location': {'displayName': '', 'locationType': 'default', 'uniqueIdType': 'unknown', 'address': {}, 'coordinates': {}}, 'locations': [], 'recurrence': None, 'attendees': [], 'organizer': {'emailAddress': {'name': 'Sai Deepthi Kovvuru', 'address': 'iamadmin8390@tfdgr.onmicrosoft.com'}}, 'onlineMeeting': None, 'calendar@odata.associationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')/$ref\", 'calendar@odata.navigationLink': \"https://graph.microsoft.com/v1.0/users('2be45935-77e0-45e6-a816-42e5966c0b1c')/calendars('AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEGAADziDctRrooQrnIA0tW4cK1AAADAVO9AAA=')\"}]}\u001b[0m\u001b[32;1m\u001b[1;3mIt looks like you don't have any meetings scheduled on the 11th and 12th of February, 2025. You're free on those dates! If you need any further assistance, feel free to let me know.\u001b[0m\n", 42 | "\n", 43 | "\u001b[1m> Finished chain.\u001b[0m\n", 44 | "---------------------------------------------------------------------------------------------- \n", 45 | "\n", 46 | "User prompt: Okay. Is there anyone in my contacts in the France office location of Montoso, that I can meet?\n", 47 | "\n", 48 | "\n", 49 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 50 | "\u001b[32;1m\u001b[1;3m\n", 51 | "Invoking: `getcontacts` with `{}`\n", 52 | "\n", 53 | "\n", 54 | "\u001b[0m\u001b[36;1m\u001b[1;3m{'@odata.context': \"https://graph.microsoft.com/v1.0/$metadata#users('2be45935-77e0-45e6-a816-42e5966c0b1c')/contacts\", 'value': [{'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEvcFZW\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEvopeCAAA=', 'createdDateTime': '2025-02-07T21:08:46Z', 'lastModifiedDateTime': '2025-02-07T21:08:47Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEvcFZW', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Chin Bansky', 'givenName': 'Chin', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bansky', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Sales', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'France', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 555 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Chin Bansky', 'address': 'chinb@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq21\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sUAAA=', 'createdDateTime': '2025-01-09T05:10:32Z', 'lastModifiedDateTime': '2025-01-09T05:10:34Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq21', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Lipta Swell', 'givenName': 'Lipta', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Swell', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'USA', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Lipta Swell', 'address': 'liptas@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2s\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sTAAA=', 'createdDateTime': '2025-01-09T05:10:00Z', 'lastModifiedDateTime': '2025-01-09T05:10:01Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2s', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Banos Angler', 'givenName': 'Banos', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Angler', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'USA', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Banos Angler', 'address': 'banosa@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2g\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sSAAA=', 'createdDateTime': '2025-01-09T05:02:17Z', 'lastModifiedDateTime': '2025-01-09T05:02:19Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2g', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Keira Noko', 'givenName': 'Keira', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Noko', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Keira Noko', 'address': 'keiran@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2X\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sRAAA=', 'createdDateTime': '2025-01-09T05:01:46Z', 'lastModifiedDateTime': '2025-01-09T05:01:47Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2X', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Terry Gordo', 'givenName': 'Terry', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Gordo', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'VP of Sales', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Terry Gordo', 'address': 'terryg@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2O\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sQAAA=', 'createdDateTime': '2025-01-09T05:01:13Z', 'lastModifiedDateTime': '2025-01-09T05:01:14Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2O', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Molly Moon', 'givenName': 'Molly', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Moon', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'HR', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Molly Moon', 'address': 'mollym@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2F\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sPAAA=', 'createdDateTime': '2025-01-09T05:00:28Z', 'lastModifiedDateTime': '2025-01-09T05:00:30Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2F', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Bina Bella', 'givenName': 'Bina', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bella', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Product Head', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Bina Bella', 'address': 'binab@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmu\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sOAAA=', 'createdDateTime': '2025-01-09T04:59:44Z', 'lastModifiedDateTime': '2025-01-09T04:59:46Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmu', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Adam Grotesque', 'givenName': 'Adam', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Grotesque', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Sales Head', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Adam Grotesque', 'address': 'adamg@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmc\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sNAAA=', 'createdDateTime': '2025-01-09T04:52:26Z', 'lastModifiedDateTime': '2025-01-09T04:52:28Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmc', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Pavel Bansky', 'givenName': 'Pavel', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bansky', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': '', 'generation': None, 'imAddresses': [], 'jobTitle': '', 'companyName': None, 'department': '', 'officeLocation': '', 'profession': None, 'businessHomePage': '', 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 555 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Pavel Bansky', 'address': 'pavelb@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}]}\u001b[0m\u001b[32;1m\u001b[1;3mYou have one contact in the France office location of Montoso:\n", 55 | "\n", 56 | "- **Name:** Chin Bansky\n", 57 | "- **Job Title:** Sales\n", 58 | "- **Company:** Montoso\n", 59 | "- **Office Location:** France\n", 60 | "- **Email:** chinb@montoso.com\n", 61 | "- **Phone:** +1 732 555 0102\n", 62 | "\n", 63 | "You can reach out to Chin Bansky for a meeting.\u001b[0m\n", 64 | "\n", 65 | "\u001b[1m> Finished chain.\u001b[0m\n", 66 | "---------------------------------------------------------------------------------------------- \n", 67 | "\n", 68 | "User prompt: Okay. Can you send Chin a mail with the subject: Can we meet for Lunch? and with body: I am in Paris on 11th and 12th of Feb and can meet you for lunch. Let me know.\n", 69 | "\n", 70 | "\n", 71 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 72 | "\u001b[32;1m\u001b[1;3m\n", 73 | "Invoking: `getcontacts` with `{}`\n", 74 | "\n", 75 | "\n", 76 | "\u001b[0m\u001b[36;1m\u001b[1;3m{'@odata.context': \"https://graph.microsoft.com/v1.0/$metadata#users('2be45935-77e0-45e6-a816-42e5966c0b1c')/contacts\", 'value': [{'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEvcFZW\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEvopeCAAA=', 'createdDateTime': '2025-02-07T21:08:46Z', 'lastModifiedDateTime': '2025-02-07T21:08:47Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEvcFZW', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Chin Bansky', 'givenName': 'Chin', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bansky', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Sales', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'France', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 555 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Chin Bansky', 'address': 'chinb@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq21\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sUAAA=', 'createdDateTime': '2025-01-09T05:10:32Z', 'lastModifiedDateTime': '2025-01-09T05:10:34Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq21', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Lipta Swell', 'givenName': 'Lipta', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Swell', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'USA', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Lipta Swell', 'address': 'liptas@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2s\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sTAAA=', 'createdDateTime': '2025-01-09T05:10:00Z', 'lastModifiedDateTime': '2025-01-09T05:10:01Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2s', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Banos Angler', 'givenName': 'Banos', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Angler', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'USA', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Banos Angler', 'address': 'banosa@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2g\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sSAAA=', 'createdDateTime': '2025-01-09T05:02:17Z', 'lastModifiedDateTime': '2025-01-09T05:02:19Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2g', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Keira Noko', 'givenName': 'Keira', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Noko', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Accounts', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Keira Noko', 'address': 'keiran@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2X\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sRAAA=', 'createdDateTime': '2025-01-09T05:01:46Z', 'lastModifiedDateTime': '2025-01-09T05:01:47Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2X', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Terry Gordo', 'givenName': 'Terry', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Gordo', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'VP of Sales', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Terry Gordo', 'address': 'terryg@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2O\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sQAAA=', 'createdDateTime': '2025-01-09T05:01:13Z', 'lastModifiedDateTime': '2025-01-09T05:01:14Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2O', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Molly Moon', 'givenName': 'Molly', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Moon', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'HR', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Molly Moon', 'address': 'mollym@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2F\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sPAAA=', 'createdDateTime': '2025-01-09T05:00:28Z', 'lastModifiedDateTime': '2025-01-09T05:00:30Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLq2F', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Bina Bella', 'givenName': 'Bina', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bella', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Product Head', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 731 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Bina Bella', 'address': 'binab@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmu\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sOAAA=', 'createdDateTime': '2025-01-09T04:59:44Z', 'lastModifiedDateTime': '2025-01-09T04:59:46Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmu', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Adam Grotesque', 'givenName': 'Adam', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Grotesque', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': None, 'generation': None, 'imAddresses': [], 'jobTitle': 'Sales Head', 'companyName': 'Montoso', 'department': None, 'officeLocation': 'Canada', 'profession': None, 'businessHomePage': None, 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 575 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Adam Grotesque', 'address': 'adamg@montoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}, {'@odata.etag': 'W/\"EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmc\"', 'id': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQBGAAAAAADKTYktQPcOQahMFVLnvXJEBwDziDctRrooQrnIA0tW4cK1AAAAAAEOAADziDctRrooQrnIA0tW4cK1AAEeW3sNAAA=', 'createdDateTime': '2025-01-09T04:52:26Z', 'lastModifiedDateTime': '2025-01-09T04:52:28Z', 'changeKey': 'EQAAABYAAADziDctRrooQrnIA0tW4cK1AAEeLqmc', 'categories': [], 'parentFolderId': 'AAMkADVlMDNkMDMzLTQ0NWMtNGFjMi1hODVkLWE0YjM0OGE1ZTc0OQAuAAAAAADKTYktQPcOQahMFVLnvXJEAQDziDctRrooQrnIA0tW4cK1AAAAAAEOAAA=', 'birthday': None, 'fileAs': '', 'displayName': 'Pavel Bansky', 'givenName': 'Pavel', 'initials': None, 'middleName': None, 'nickName': None, 'surname': 'Bansky', 'title': None, 'yomiGivenName': None, 'yomiSurname': None, 'yomiCompanyName': '', 'generation': None, 'imAddresses': [], 'jobTitle': '', 'companyName': None, 'department': '', 'officeLocation': '', 'profession': None, 'businessHomePage': '', 'assistantName': '', 'manager': '', 'homePhones': [], 'mobilePhone': '', 'businessPhones': ['+1 732 555 0102'], 'spouseName': '', 'personalNotes': '', 'children': [], 'emailAddresses': [{'name': 'Pavel Bansky', 'address': 'pavelb@contoso.com'}], 'homeAddress': {}, 'businessAddress': {}, 'otherAddress': {}}]}\u001b[0m\u001b[32;1m\u001b[1;3m\n", 77 | "Invoking: `sendmail` with `{'subject': 'Can we meet for Lunch?', 'body': 'I am in Paris on 11th and 12th of Feb and can meet you for lunch. Let me know.', 'email': 'chinb@montoso.com'}`\n", 78 | "\n", 79 | "\n", 80 | "\u001b[0mStatus Code 202\n", 81 | "\u001b[31;1m\u001b[1;3m\u001b[0m\u001b[32;1m\u001b[1;3mI've successfully sent the email to Chin with the subject \"Can we meet for Lunch?\" and the message body you provided. Let me know if there's anything else you need!\u001b[0m\n", 82 | "\n", 83 | "\u001b[1m> Finished chain.\u001b[0m\n" 84 | ] 85 | }, 86 | { 87 | "data": { 88 | "text/plain": [ 89 | "{'input': 'Okay. Can you send Chin a mail with the subject: Can we meet for Lunch? and with body: I am in Paris on 11th and 12th of Feb and can meet you for lunch. Let me know.',\n", 90 | " 'chat_history': [HumanMessage(content='Hey Clippy! I am Sai. I need to go to Paris, France for a work trip. Can you help me plan that?', additional_kwargs={}, response_metadata={}),\n", 91 | " AIMessage(content=\"Of course, Sai! I'd be happy to help you plan your work trip to Paris, France. Here are a few things we can start with:\\n\\n1. **Check the Weather**: Knowing the current weather in Paris can help you pack appropriately.\\n2. **Travel Itinerary**: Do you have specific dates for your travel? I can help you with your flight and accommodation options.\\n3. **Events & Meetings**: I can check your calendar for any scheduled events and help you manage your work commitments while you're away.\\n4. **Contacts in Paris**: If you need to meet anyone in Paris, I can search for contacts in that location.\\n5. **Travel Policies**: I can provide information on your company's travel policies and any necessary approvals.\\n6. **Local Information**: If you're interested in any specific places or activities in Paris, I can look them up for you.\\n\\nLet me know which of these you'd like to start with, or if there's anything else you need!\", additional_kwargs={}, response_metadata={}),\n", 92 | " HumanMessage(content='Cool! I want to see if I have any important meetings on 11th and 12th of February?', additional_kwargs={}, response_metadata={}),\n", 93 | " AIMessage(content=\"It looks like you don't have any meetings scheduled on the 11th and 12th of February, 2025. You're free on those dates! If you need any further assistance, feel free to let me know.\", additional_kwargs={}, response_metadata={}),\n", 94 | " HumanMessage(content='Okay. Is there anyone in my contacts in the France office location of Montoso, that I can meet?', additional_kwargs={}, response_metadata={}),\n", 95 | " AIMessage(content='You have one contact in the France office location of Montoso:\\n\\n- **Name:** Chin Bansky\\n- **Job Title:** Sales\\n- **Company:** Montoso\\n- **Office Location:** France\\n- **Email:** chinb@montoso.com\\n- **Phone:** +1 732 555 0102\\n\\nYou can reach out to Chin Bansky for a meeting.', additional_kwargs={}, response_metadata={})],\n", 96 | " 'output': 'I\\'ve successfully sent the email to Chin with the subject \"Can we meet for Lunch?\" and the message body you provided. Let me know if there\\'s anything else you need!'}" 97 | ] 98 | }, 99 | "execution_count": 4, 100 | "metadata": {}, 101 | "output_type": "execute_result" 102 | } 103 | ], 104 | "source": [ 105 | "# Import relevant functionality\n", 106 | "import os\n", 107 | "import asyncio\n", 108 | "import requests\n", 109 | "import urllib.parse\n", 110 | "import json\n", 111 | "import configparser\n", 112 | "from datetime import date\n", 113 | "from dotenv import load_dotenv\n", 114 | "from langchain_community.tools.tavily_search import TavilySearchResults\n", 115 | "from msgraph.generated.models.o_data_errors.o_data_error import ODataError\n", 116 | "from configparser import SectionProxy\n", 117 | "from langchain_core.messages import HumanMessage\n", 118 | "from langgraph.checkpoint.memory import MemorySaver\n", 119 | "from langgraph.prebuilt import create_react_agent\n", 120 | "from langchain_openai import ChatOpenAI\n", 121 | "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", 122 | "from langgraph.graph import START, MessagesState, StateGraph\n", 123 | "from langchain.agents import AgentType, initialize_agent, load_tools\n", 124 | "from langchain.tools import BaseTool, StructuredTool, tool\n", 125 | "from langchain_openai import OpenAI\n", 126 | "from langchain_core.runnables import ConfigurableField\n", 127 | "from langchain.agents import create_tool_calling_agent, AgentExecutor\n", 128 | "from langchain_core.runnables.history import RunnableWithMessageHistory\n", 129 | "from langchain.agents import AgentExecutor, create_react_agent\n", 130 | "from langchain.memory import ChatMessageHistory\n", 131 | "from dotenv import load_dotenv, find_dotenv\n", 132 | "from configparser import SectionProxy\n", 133 | "from azure.identity import DeviceCodeCredential\n", 134 | "from msgraph import GraphServiceClient\n", 135 | "from langgraph.types import interrupt\n", 136 | "from msgraph.generated.users.users_request_builder import UsersRequestBuilder\n", 137 | "from kiota_abstractions.base_request_configuration import RequestConfiguration\n", 138 | "#MSAL Auth\n", 139 | "import msal\n", 140 | "import jwt\n", 141 | "import json\n", 142 | "import sys\n", 143 | "import requests\n", 144 | "from datetime import datetime as dt\n", 145 | "from msal_extensions import *\n", 146 | "\n", 147 | "# Graph permissions scopes\n", 148 | "# For multiple scopes, separate with a space\n", 149 | "scopes = 'user.read Calendars.Read Calendars.ReadBasic Calendars.Read Calendars.ReadWrite Contacts.Read Mail.Send'\n", 150 | "\n", 151 | "#load the environment\n", 152 | "load_dotenv(override=True)\n", 153 | "\n", 154 | "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\")\n", 155 | "os.environ[\"TAVILY_API_KEY\"] = os.getenv(\"TAVILY_API_KEY\")\n", 156 | "OPENWEATHERMAP_API_KEY = os.getenv(\"OPENWEATHERMAP_API_KEY\")\n", 157 | "TENANT_GRAPH_ACCESS_TOKEN = os.getenv(\"TENANT_GRAPH_ACCESS_TOKEN\")\n", 158 | "GRAPH_ACCESS_TOKEN = os.getenv(\"GRAPH_ACCESS_TOKEN\")\n", 159 | "TENANT_GRAPH_ACCESS_TOKEN = GRAPH_ACCESS_TOKEN\n", 160 | "CLIENT_ID = os.getenv(\"CLIENT_ID\")\n", 161 | "TENANT_ID = os.getenv(\"TENANT_ID\")\n", 162 | "USERNAME = os.getenv(\"USERNAME\")\n", 163 | "\n", 164 | "#MSAL Auth\n", 165 | "graphURI = 'https://graph.microsoft.com'\n", 166 | "tenantID = TENANT_ID\n", 167 | "authority = 'https://login.microsoftonline.com/' + tenantID\n", 168 | "clientID = CLIENT_ID\n", 169 | "scope = [\"User.Read\",\"Calendars.Read\",\"Calendars.ReadBasic\", \"Calendars.Read\", \"Calendars.ReadWrite\"]\n", 170 | "username = USERNAME\n", 171 | "result = None\n", 172 | "tokenExpiry = None\n", 173 | "\n", 174 | "\n", 175 | "def msal_persistence(location, fallback_to_plaintext=False):\n", 176 | " \"\"\"Build a suitable persistence instance based your current OS\"\"\"\n", 177 | " if sys.platform.startswith('win'):\n", 178 | " return FilePersistenceWithDataProtection(location)\n", 179 | " if sys.platform.startswith('darwin'):\n", 180 | " return KeychainPersistence(location, \"my_service_name\", \"my_account_name\")\n", 181 | " return FilePersistence(location)\n", 182 | "\n", 183 | "def msal_cache_accounts(clientID, authority):\n", 184 | " # Accounts\n", 185 | " persistence = msal_persistence(\"token_cache.bin\")\n", 186 | " #print(\"Is this MSAL persistence cache encrypted?\", persistence.is_encrypted)\n", 187 | " cache = PersistedTokenCache(persistence)\n", 188 | " \n", 189 | " app = msal.PublicClientApplication(\n", 190 | " client_id=clientID, authority=authority, token_cache=cache)\n", 191 | " accounts = app.get_accounts()\n", 192 | " #print(accounts)\n", 193 | " return accounts\n", 194 | "\n", 195 | "def msal_delegated_refresh(clientID, scope, authority, account):\n", 196 | " persistence = msal_persistence(\"token_cache.bin\")\n", 197 | " cache = PersistedTokenCache(persistence)\n", 198 | " \n", 199 | " app = msal.PublicClientApplication(\n", 200 | " client_id=clientID, authority=authority, token_cache=cache)\n", 201 | " result = app.acquire_token_silent_with_error(\n", 202 | " scopes=scope, account=account)\n", 203 | " return result\n", 204 | "\n", 205 | "def msal_delegated_refresh_force(clientID, scope, authority, account):\n", 206 | " persistence = msal_persistence(\"token_cache.bin\")\n", 207 | " cache = PersistedTokenCache(persistence)\n", 208 | " \n", 209 | " app = msal.PublicClientApplication(\n", 210 | " client_id=clientID, authority=authority, token_cache=cache)\n", 211 | " result = app.acquire_token_silent_with_error(\n", 212 | " scopes=scope, account=account, force_refresh=True)\n", 213 | " return result\n", 214 | "\n", 215 | "def msal_delegated_device_flow(clientID, scope, authority):\n", 216 | " #print(\"Initiate Device Code Flow to get an AAD Access Token.\")\n", 217 | " #print(\"Open a browser window and paste in the URL below and then enter the Code. CTRL+C to cancel.\")\n", 218 | " persistence = msal_persistence(\"token_cache.bin\")\n", 219 | " cache = PersistedTokenCache(persistence)\n", 220 | " app = msal.PublicClientApplication(client_id=clientID, authority=authority, token_cache=cache)\n", 221 | " flow = app.initiate_device_flow(scopes=scope)\n", 222 | " if \"user_code\" not in flow:\n", 223 | " raise ValueError(\"Fail to create device flow. Err: %s\" % json.dumps(flow, indent=4))\n", 224 | " print(flow[\"message\"])\n", 225 | " sys.stdout.flush()\n", 226 | " result = app.acquire_token_by_device_flow(flow)\n", 227 | " return result\n", 228 | "\n", 229 | "def msal_jwt_expiry(accessToken):\n", 230 | " decodedAccessToken = jwt.decode(accessToken, verify=False)\n", 231 | " accessTokenFormatted = json.dumps(decodedAccessToken, indent=2)\n", 232 | " # Token Expiry\n", 233 | " tokenExpiry = dt.fromtimestamp(int(decodedAccessToken['exp']))\n", 234 | " #print(\"Token Expires at: \" + str(tokenExpiry))\n", 235 | " return tokenExpiry\n", 236 | "\n", 237 | "def msgraph_request(resource, requestHeaders):\n", 238 | " # Request\n", 239 | " results = requests.get(resource, headers=requestHeaders).json()\n", 240 | " return results\n", 241 | "\n", 242 | "accounts = msal_cache_accounts(clientID, authority)\n", 243 | "if accounts:\n", 244 | " for account in accounts:\n", 245 | " if account['username'] == username:\n", 246 | " myAccount = account\n", 247 | " #print(\"Found account in MSAL Cache: \" + account['username'])\n", 248 | " #print(\"Obtaining a new Access Token using the Refresh Token\")\n", 249 | " result = msal_delegated_refresh(clientID, scope, authority, myAccount)\n", 250 | "\n", 251 | " if result is None:\n", 252 | " # Get a new Access Token using the Device Code Flow\n", 253 | " result = msal_delegated_device_flow(clientID, scope, authority)\n", 254 | " else:\n", 255 | " if result[\"access_token\"]:\n", 256 | " msal_jwt_expiry(result[\"access_token\"]) \n", 257 | "else:\n", 258 | " # Get a new Access Token using the Device Code Flow\n", 259 | " result = msal_delegated_device_flow(clientID, scope, authority)\n", 260 | "\n", 261 | " if result[\"access_token\"]:\n", 262 | " msal_jwt_expiry(result[\"access_token\"])\n", 263 | "\n", 264 | "# End of authentication code\n", 265 | "\n", 266 | "@tool\n", 267 | "async def getevents():\n", 268 | " \"\"\"Get a list of my events from my calendar and display them with the meeting name, subject of the meeting, start dateTime, end dateTime, organizers, participants, date and time.\"\"\"\n", 269 | " # To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python\n", 270 | " requestHeaders = {'Authorization': 'Bearer ' + result[\"access_token\"],'Content-Type': 'application/json'}\n", 271 | " queryResults = msgraph_request(graphURI + \"/v1.0/me/events\",requestHeaders)\n", 272 | " #print(json.dumps(queryResults, indent=2))\n", 273 | " return queryResults\n", 274 | " \n", 275 | "\n", 276 | "@tool\n", 277 | "async def getcontacts():\n", 278 | " \"\"\"Get a list of user's contacts and display with their full name, office location, jobTitle, email id, company name\"\"\"\n", 279 | " requestHeaders = {'Authorization': 'Bearer ' + result[\"access_token\"],'Content-Type': 'application/json'}\n", 280 | " queryResults = msgraph_request(graphURI + \"/v1.0/me/contacts\",requestHeaders)\n", 281 | " #print(json.dumps(queryResults, indent=2))\n", 282 | " return queryResults\n", 283 | "\n", 284 | "\n", 285 | "GRAPH_ACCESS_TOKEN = result[\"access_token\"]\n", 286 | "\n", 287 | "@tool\n", 288 | "def sendmail(subject: str, body: str, email: str) -> str:\n", 289 | " \"\"\"Send a mail to the email address provided with the Subject provided in the subject and Body provided in the body as the user.\"\"\"\n", 290 | " url = \"https://graph.microsoft.com/v1.0/me/sendMail\"\n", 291 | " headers = {\n", 292 | " \"Authorization\": f\"Bearer {GRAPH_ACCESS_TOKEN}\"}\n", 293 | " data = {\n", 294 | " \"message\": {\n", 295 | " \"subject\": f\"{subject}\",\n", 296 | " \"body\": {\n", 297 | " \"contentType\": \"Text\",\n", 298 | " \"content\": f\"{body}\"\n", 299 | " },\n", 300 | " \"toRecipients\": [\n", 301 | " {\n", 302 | " \"emailAddress\": {\n", 303 | " \"address\": f\"{email}\"\n", 304 | " }\n", 305 | " }\n", 306 | " ]\n", 307 | " }\n", 308 | " }\n", 309 | " response = requests.post(url, headers=headers, json=data)\n", 310 | " #response = requests.post(url, json=data)\n", 311 | " print(\"Status Code\", response.status_code)\n", 312 | " #print(\"JSON Response \", response.json())\n", 313 | " return response\n", 314 | "\n", 315 | "\n", 316 | "prompt = ChatPromptTemplate.from_messages([\n", 317 | " (\"system\", \"you're a helpful admin assistant who can talk professionally. Your name is Clippy. Please answer all questions knowing that today's date is \"+ date.today().strftime('%m/%d/%Y') +\". You can send emails. Search the web. Whenever someone wants to see their events, use the tool getevents and identify the right start dateTime from the results you get from getEvents tool and answer the user prompt about their availability correctly. Please format the tool responses you get into much more readable format. You can fetch their contacts. You can search the web for anything else you don't understand. You can get their calendar events. You can also give information to users about the holidays in their regions. Their DTO policies. Their timeoff policies. Anything they want to know about their employee benefits. The access_tokens are available in the tools so don't ask the users again.\"), \n", 318 | " (\"human\", \"{input}\"), \n", 319 | " (\"placeholder\", \"{agent_scratchpad}\"),\n", 320 | "])\n", 321 | "\n", 322 | "search = TavilySearchResults(max_results=2)\n", 323 | "\n", 324 | "# all the tools I have access to\n", 325 | "tools = [getcontacts, getevents, search, sendmail]\n", 326 | "\n", 327 | "llm = ChatOpenAI(model=\"gpt-4o\")\n", 328 | "\n", 329 | "# Define a new graph\n", 330 | "workflow = StateGraph(state_schema=MessagesState)\n", 331 | "\n", 332 | "\n", 333 | "# Define the function that calls the model\n", 334 | "async def call_model(state: MessagesState):\n", 335 | " prompt = prompt.invoke(state)\n", 336 | " response = model.ainvoke(prompt)\n", 337 | " return {\"messages\": response}\n", 338 | "\n", 339 | "# Define the (single) node in the graph\n", 340 | "workflow.add_edge(START, \"model\")\n", 341 | "workflow.add_node(\"model\", call_model)\n", 342 | "\n", 343 | "# Add memory\n", 344 | "memory = ChatMessageHistory(session_id=\"test-session\")\n", 345 | "app = workflow.compile(checkpointer=memory)\n", 346 | "\n", 347 | "config = {\"configurable\": {\"thread_id\": \"def234\"}}\n", 348 | "#config = RunnableConfig(recursion_limit=10)\n", 349 | "agent = create_tool_calling_agent(llm, tools, prompt)\n", 350 | "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, trim_intermediate_steps=True)\n", 351 | "agent_with_chat_history = RunnableWithMessageHistory(\n", 352 | " agent_executor,\n", 353 | " lambda session_id: memory,\n", 354 | " input_messages_key=\"input\",\n", 355 | " history_messages_key=\"chat_history\",\n", 356 | ")\n", 357 | "\n", 358 | "print(\"Hello! I am your personal companion, Clippy!. Ask me about your meetings. Or the weather. I can answer most things about the world!\",\"\\n\")\n", 359 | "\n", 360 | "\n", 361 | "query=\"Hey Clippy! I am Sai. I need to go to Paris, France for a work trip. Can you help me plan that?\"\n", 362 | "print(\"---------------------------------------------------------------------------------------------------------\")\n", 363 | "print(\"User prompt: \",query)\n", 364 | "\n", 365 | "\n", 366 | "\n", 367 | "await agent_with_chat_history.ainvoke(\n", 368 | " {\"input\": query},\n", 369 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 370 | ")\n", 371 | "\n", 372 | "\n", 373 | "query=\"Cool! I want to see if I have any important meetings on 11th and 12th of February?\"\n", 374 | "print(\"---------------------------------------------------------------------------------------------------------\")\n", 375 | "print(\"User prompt: \",query)\n", 376 | "\n", 377 | "\n", 378 | "\n", 379 | "await agent_with_chat_history.ainvoke(\n", 380 | " {\"input\": query},\n", 381 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 382 | ")\n", 383 | "\n", 384 | "\n", 385 | "query=\"Okay. Is there anyone in my contacts in the France office location of Montoso, that I can meet?\"\n", 386 | "print(\"----------------------------------------------------------------------------------------------\",\"\\n\")\n", 387 | "print(\"User prompt: \",query)\n", 388 | " \n", 389 | "await agent_with_chat_history.ainvoke(\n", 390 | " {\"input\": query},\n", 391 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 392 | ")\n", 393 | "\n", 394 | "query=\"Okay. Can you send Chin a mail with the subject: Can we meet for Lunch? and with body: I am in Paris on 11th and 12th of Feb and can meet you for lunch. Let me know.\"\n", 395 | "print(\"----------------------------------------------------------------------------------------------\",\"\\n\")\n", 396 | "print(\"User prompt: \",query)\n", 397 | " \n", 398 | "await agent_with_chat_history.ainvoke(\n", 399 | " {\"input\": query},\n", 400 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 401 | ")\n" 402 | ] 403 | }, 404 | { 405 | "cell_type": "code", 406 | "execution_count": null, 407 | "id": "b5a0bb48-9d27-49e8-9136-2868a2c6878f", 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "id": "676e73d0-5b17-4eb6-9dcf-03c05419fbf4", 416 | "metadata": {}, 417 | "outputs": [], 418 | "source": [] 419 | } 420 | ], 421 | "metadata": { 422 | "kernelspec": { 423 | "display_name": "Python 3 (ipykernel)", 424 | "language": "python", 425 | "name": "python3" 426 | }, 427 | "language_info": { 428 | "codemirror_mode": { 429 | "name": "ipython", 430 | "version": 3 431 | }, 432 | "file_extension": ".py", 433 | "mimetype": "text/x-python", 434 | "name": "python", 435 | "nbconvert_exporter": "python", 436 | "pygments_lexer": "ipython3", 437 | "version": "3.12.9" 438 | } 439 | }, 440 | "nbformat": 4, 441 | "nbformat_minor": 5 442 | } 443 | -------------------------------------------------------------------------------- /ClippywithUI.py: -------------------------------------------------------------------------------- 1 | from langchain.prompts import ChatPromptTemplate 2 | from langchain.schema import StrOutputParser 3 | from langchain.schema.runnable import Runnable 4 | from langchain.schema.runnable.config import RunnableConfig 5 | import getpass 6 | import os 7 | from langchain_openai import ChatOpenAI 8 | from langchain_core.messages import HumanMessage, SystemMessage 9 | from dotenv import load_dotenv 10 | import chainlit as cl 11 | import asyncio 12 | import requests 13 | import urllib.parse 14 | import json 15 | import configparser 16 | from datetime import date 17 | from langchain_community.tools.tavily_search import TavilySearchResults 18 | from msgraph.generated.models.o_data_errors.o_data_error import ODataError 19 | from configparser import SectionProxy 20 | from langchain_core.messages import HumanMessage 21 | from langgraph.checkpoint.memory import MemorySaver 22 | from langgraph.prebuilt import create_react_agent 23 | from langchain_openai import ChatOpenAI 24 | from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder 25 | from langgraph.graph import START, MessagesState, StateGraph 26 | from langchain.agents import AgentType, initialize_agent, load_tools 27 | from langchain.tools import BaseTool, StructuredTool, tool 28 | from langchain_openai import OpenAI 29 | from langchain_core.runnables import ConfigurableField 30 | from langchain.agents import create_tool_calling_agent, AgentExecutor 31 | from langchain_core.runnables.history import RunnableWithMessageHistory 32 | from langchain.agents import AgentExecutor, create_react_agent 33 | from langchain.memory import ChatMessageHistory 34 | from dotenv import load_dotenv, find_dotenv 35 | from configparser import SectionProxy 36 | from azure.identity import DeviceCodeCredential 37 | from msgraph import GraphServiceClient 38 | from langgraph.types import interrupt 39 | from msgraph.generated.users.users_request_builder import UsersRequestBuilder 40 | from kiota_abstractions.base_request_configuration import RequestConfiguration 41 | from typing import Literal 42 | from langgraph.prebuilt import ToolNode 43 | from langchain.schema.runnable.config import RunnableConfig 44 | from langgraph.errors import GraphRecursionError 45 | from langgraph.checkpoint.memory import MemorySaver 46 | #MSAL Auth 47 | import msal 48 | import jwt 49 | import json 50 | import sys 51 | import requests 52 | from datetime import datetime as dt 53 | from datetime import date 54 | from msal_extensions import * 55 | 56 | 57 | #load the environment 58 | load_dotenv(override=True) 59 | 60 | 61 | os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") 62 | os.environ["TAVILY_API_KEY"] = os.getenv("TAVILY_API_KEY") 63 | OPENWEATHERMAP_API_KEY = os.getenv("OPENWEATHERMAP_API_KEY") 64 | TENANT_GRAPH_ACCESS_TOKEN = os.getenv("TENANT_GRAPH_ACCESS_TOKEN") 65 | CLIENT_ID = os.getenv("CLIENT_ID") 66 | TENANT_ID = os.getenv("TENANT_ID") 67 | USERNAME = os.getenv("USERNAME") 68 | os.environ["LANGCHAIN_TRACING_V2"] = "true" 69 | os.environ["LANGCHAIN_API_KEY"] = os.getenv("LANGCHAIN_API_KEY") 70 | 71 | 72 | 73 | #MSAL Auth 74 | graphURI = 'https://graph.microsoft.com' 75 | tenantID = TENANT_ID 76 | authority = 'https://login.microsoftonline.com/' + tenantID 77 | clientID = CLIENT_ID 78 | scope = ["User.Read","Calendars.Read","Calendars.ReadBasic", "Calendars.Read", "Calendars.ReadWrite"] 79 | username = USERNAME 80 | result = None 81 | tokenExpiry = None 82 | 83 | def msal_persistence(location, fallback_to_plaintext=False): 84 | """Build a suitable persistence instance based your current OS""" 85 | if sys.platform.startswith('win'): 86 | return FilePersistenceWithDataProtection(location) 87 | if sys.platform.startswith('darwin'): 88 | return KeychainPersistence(location, "my_service_name", "my_account_name") 89 | return FilePersistence(location) 90 | 91 | def msal_cache_accounts(clientID, authority): 92 | # Accounts 93 | persistence = msal_persistence("token_cache.bin") 94 | #print("Is this MSAL persistence cache encrypted?", persistence.is_encrypted) 95 | cache = PersistedTokenCache(persistence) 96 | 97 | app = msal.PublicClientApplication( 98 | client_id=clientID, authority=authority, token_cache=cache) 99 | accounts = app.get_accounts() 100 | #print(accounts) 101 | return accounts 102 | 103 | def msal_delegated_refresh(clientID, scope, authority, account): 104 | persistence = msal_persistence("token_cache.bin") 105 | cache = PersistedTokenCache(persistence) 106 | 107 | app = msal.PublicClientApplication( 108 | client_id=clientID, authority=authority, token_cache=cache) 109 | result = app.acquire_token_silent_with_error( 110 | scopes=scope, account=account) 111 | return result 112 | 113 | def msal_delegated_refresh_force(clientID, scope, authority, account): 114 | persistence = msal_persistence("token_cache.bin") 115 | cache = PersistedTokenCache(persistence) 116 | 117 | app = msal.PublicClientApplication( 118 | client_id=clientID, authority=authority, token_cache=cache) 119 | result = app.acquire_token_silent_with_error( 120 | scopes=scope, account=account, force_refresh=True) 121 | return result 122 | 123 | def msal_delegated_device_flow(clientID, scope, authority): 124 | #print("Initiate Device Code Flow to get an AAD Access Token.") 125 | #print("Open a browser window and paste in the URL below and then enter the Code. CTRL+C to cancel.") 126 | persistence = msal_persistence("token_cache.bin") 127 | cache = PersistedTokenCache(persistence) 128 | app = msal.PublicClientApplication(client_id=clientID, authority=authority, token_cache=cache) 129 | flow = app.initiate_device_flow(scopes=scope) 130 | if "user_code" not in flow: 131 | raise ValueError("Fail to create device flow. Err: %s" % json.dumps(flow, indent=4)) 132 | print(flow["message"]) 133 | sys.stdout.flush() 134 | result = app.acquire_token_by_device_flow(flow) 135 | return result 136 | 137 | def msal_jwt_expiry(accessToken): 138 | decodedAccessToken = jwt.decode(accessToken, verify=False) 139 | accessTokenFormatted = json.dumps(decodedAccessToken, indent=2) 140 | # Token Expiry 141 | tokenExpiry = dt.fromtimestamp(int(decodedAccessToken['exp'])) 142 | #print("Token Expires at: " + str(tokenExpiry)) 143 | return tokenExpiry 144 | 145 | 146 | def msgraph_request(resource, requestHeaders): 147 | # Request 148 | results = requests.get(resource, headers=requestHeaders).json() 149 | return results 150 | 151 | accounts = msal_cache_accounts(clientID, authority) 152 | if accounts: 153 | for account in accounts: 154 | if account['username'] == username: 155 | myAccount = account 156 | #print("Found account in MSAL Cache: " + account['username']) 157 | #print("Obtaining a new Access Token using the Refresh Token") 158 | result = msal_delegated_refresh(clientID, scope, authority, myAccount) 159 | 160 | if result is None: 161 | # Get a new Access Token using the Device Code Flow 162 | result = msal_delegated_device_flow(clientID, scope, authority) 163 | else: 164 | if result["access_token"]: 165 | msal_jwt_expiry(result["access_token"]) 166 | else: 167 | # Get a new Access Token using the Device Code Flow 168 | result = msal_delegated_device_flow(clientID, scope, authority) 169 | 170 | if result["access_token"]: 171 | msal_jwt_expiry(result["access_token"]) 172 | 173 | GRAPH_ACCESS_TOKEN =result["access_token"] 174 | # End of authentication code 175 | 176 | @tool 177 | async def getevents(): 178 | """Get a list of my events from my calendar and display them with the meeting name, subject of the meeting, start dateTime, end dateTime, organizers, participants, date and time.""" 179 | # To initialize your graph_client, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=python 180 | print("using getevents tool") 181 | requestHeaders = {'Authorization': 'Bearer ' + result["access_token"],'Content-Type': 'application/json'} 182 | queryResults = msgraph_request(graphURI + "/v1.0/me/events",requestHeaders) 183 | #print(json.dumps(queryResults, indent=2)) 184 | return queryResults 185 | 186 | 187 | @tool 188 | async def getcontacts(): 189 | """Get a list of my contacts and display with their full name, office location, email id, company name""" 190 | print("using getevents tool") 191 | requestHeaders = {'Authorization': 'Bearer ' + result["access_token"],'Content-Type': 'application/json'} 192 | queryResults = msgraph_request(graphURI + "/v1.0/me/contacts",requestHeaders) 193 | #print(json.dumps(queryResults, indent=2)) 194 | return queryResults 195 | 196 | 197 | @tool 198 | def sendmail(subject: str, body: str, email: str) -> str: 199 | """Send a mail to the email address provided with the Subject provided in the subject and Body provided in the body as the user.Send an empty body if there is no body in the user query. Do not sign the mail.""" 200 | url = "https://graph.microsoft.com/v1.0/me/sendMail" 201 | headers = { 202 | "Authorization": f"Bearer {GRAPH_ACCESS_TOKEN}"} 203 | data = { 204 | "message": { 205 | "subject": f"{subject}", 206 | "body": { 207 | "contentType": "Text", 208 | "content": f"{body}" 209 | }, 210 | "toRecipients": [ 211 | { 212 | "emailAddress": { 213 | "address": f"{email}" 214 | } 215 | } 216 | ] 217 | } 218 | } 219 | response = requests.post(url, headers=headers, json=data) 220 | #response = requests.post(url, json=data) 221 | print("Status Code", response.status_code) 222 | #print("JSON Response ", response.json()) 223 | return response 224 | 225 | llm = ChatOpenAI(model="gpt-4o") 226 | 227 | prompt = ChatPromptTemplate.from_messages([ 228 | ("system", "you're a helpful admin assistant who can send emails on behalf of the user. Your name is Clippy. Please answer all questions knowing that today's date is"+ date.today().strftime('%m/%d/%Y') +"Whenever someone wants to see their events, use the tool getevents and identify the right start dateTime from the results you get from getEvents tool and answer the user prompt about their availability correctly. Please format the tool responses you get into much more readable format. You can fetch their contacts. You can search the web for anything else you don't understand. You can get their calendar events. You can also give information to users about the holidays in their regions. Their DTO policies. Their timeoff policies. Anything they want to know about their employee benefits. The access_tokens are available in the tools so don't ask the users again."), 229 | ("human", "{input}"), 230 | ("placeholder", "{agent_scratchpad}"), 231 | ]) 232 | 233 | search = TavilySearchResults(max_results=2) 234 | 235 | # all the tools I have access to 236 | tools = [getcontacts, getevents, sendmail, search] 237 | 238 | model = ChatOpenAI(model="gpt-4o-mini", temperature=0, max_retries=2) 239 | 240 | 241 | llm = ChatOpenAI(model="gpt-4o") 242 | 243 | # Define a new graph 244 | workflow = StateGraph(state_schema=MessagesState) 245 | 246 | 247 | # Define the function that calls the model 248 | async def call_model(state: MessagesState): 249 | prompt = prompt.invoke(state) 250 | response = model.ainvoke(prompt) 251 | return {"messages": response} 252 | 253 | # Define the (single) node in the graph 254 | workflow.add_edge(START, "model") 255 | workflow.add_node("model", call_model) 256 | 257 | # Add memory 258 | memory = ChatMessageHistory(session_id="test-session") 259 | app = workflow.compile(checkpointer=memory) 260 | 261 | agent = create_tool_calling_agent(model, tools, prompt) 262 | langgraph_agent_executor = agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, trim_intermediate_steps=True) 263 | agent_with_chat_history = RunnableWithMessageHistory( 264 | langgraph_agent_executor, 265 | lambda session_id: memory, 266 | input_messages_key="input", 267 | history_messages_key="chat_history", 268 | ) 269 | 270 | config = {"configurable": {"thread_id": "def234"}} 271 | 272 | @cl.on_chat_start 273 | async def on_chat_start(): 274 | await cl.Message(content="Hello! I am your personal companion, Clippy! Ask me about your meetings. Or the weather. I can answer most things about the world!").send() 275 | cl.user_session.set("langgraph_agent_executor", langgraph_agent_executor) 276 | 277 | @cl.on_message 278 | async def handle_message(message: cl.Message): 279 | langgraph_agent_executor = cl.user_session.get("langgraph_agent_executor") 280 | prompt = ChatPromptTemplate.from_messages([ 281 | ("system", "you're a helpful admin assistant who can send mails on behalf of users. You can answer simple questions like country capitals without using any tools. You can search the web. Your name is Clippy. Please answer all questions knowing that today's date is "+ date.today().strftime('%m/%d/%Y') +". Whenever someone wants to see their events, use the tool getevents and identify the right start dateTime from the results you get from getEvents tool and answer the user prompt about their availability correctly. Please format the tool responses you get into much more readable format. You can fetch their contacts. You can search the web for anything else you don't understand. You can get their calendar events. You can also give information to users about the holidays in their regions. Their DTO policies. Their timeoff policies. Anything they want to know about their employee benefits. The access_tokens are available in the tools so don't ask the users again."), 282 | ("human", message.content), 283 | ("placeholder", "{agent_scratchpad}"), 284 | ]) 285 | agent = create_tool_calling_agent(model, tools, prompt) 286 | langgraph_agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, trim_intermediate_steps=True) 287 | agent_with_chat_history = RunnableWithMessageHistory( 288 | langgraph_agent_executor, 289 | lambda session_id: memory, 290 | input_messages_key="input", 291 | history_messages_key="chat_history", 292 | ) 293 | 294 | 295 | # Invoke the LangGraph agent executor 296 | config = {"configurable": {"session_id": "def234"}} 297 | 298 | async for chunk in agent_with_chat_history.astream( 299 | {"messages": [HumanMessage(content=message.content)]}, config 300 | ): 301 | print(chunk) 302 | if 'output' in chunk: 303 | # Do something if the object has the 'my_field' attribute 304 | print("Object has the attribute") 305 | await cl.Message(chunk['output']).send() 306 | else: 307 | cl.Message("Processing step:","\n") 308 | await cl.Message(chunk).send() 309 | print("----") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains sample agentic applications in python that can talk to Azure AI and OpenAI models and perform complex tasks based on user queries. 2 | 3 | ## Prerequisites 4 | 5 | 1. You need an OpenAI API Key, Tavily Search API Key, Open Weather Map API Key and M365 Developer Tenant 6 | 2. You will need to buy a license to use the OpenAI GPT models 7 | 3. Alternatively, you can use AzureAI models by deploying your models using your Azure subscription. Steps are here --> https://learn.microsoft.com/en-us/azure/ai-foundry/model-inference/concepts/endpoints?tabs=python 8 | 4. You will need to create an app registration in Azure portal. Use the following steps - https://learn.microsoft.com/en-us/graph/tutorials/python?tabs=aad&tutorial-step=1 9 | 5. Save the ClientID and the TenantID from this app you created. 10 | 6. You need to install Python, Jupyter notebook, PIP on your system. I am using Windows 11. 11 | 7. You need to install the following Python Packages - Jupyter, Python, LangChain, MSGraph, AzureIdentity 12 | 13 | ## Steps to get your first Agent running 14 | 15 | 1. Clone this repository 16 | 2. Go to the folder where you downloaded the repository. 17 | 3. Open the .env file and add your keys that you obtained from OpenAI, Tavily, Open Weather Map, etc. 18 | 4. Add ClientID and the TenantID 19 | 5. Save and Close the file. 20 | 6. Run the following command to ensure all the right libraries are installed --> pip install --requirement=.\requirements.txt 21 | 7. Open Command Prompt and go to the folder where the repository is. 22 | 8. Type the following command - jupyter notebook 23 | 9. This will open a web page that contains all your scripts. 24 | 10. Click on first Agent script and it will open in a separate page. 25 | 11. Click on the run icon. 26 | 12. You should see the output on the line below. 27 | 28 | 29 | ## Getting the Clippy2 Agent running 30 | 1. This is a more advanced Agent and to run it, you will need to access Microsoft Graph SDKs. 31 | 2. Follow this tutorial --> https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/graph-api-tutorial 32 | 33 | ## Feedback 34 | If you have any feedback, please send a mail to sakov@microsoft.com and I will get back. 35 | 36 | ## Contributing 37 | 38 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 39 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 40 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 41 | 42 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 43 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 44 | provided by the bot. You will only need to do this once across all repos using our CLA. 45 | 46 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 47 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 48 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 49 | 50 | ## Trademarks 51 | 52 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 53 | trademarks or logos is subject to and must follow 54 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 55 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 56 | Any use of third-party trademarks or logos are subject to those third-party's policies. 57 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /azureAI.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "id": "afdec5df-fad2-48fe-a3f5-0bc92b70db98", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "Sure! Here's one for you:\n", 14 | "\n", 15 | "Why don’t skeletons fight each other?\n", 16 | "\n", 17 | "Because they don’t have the guts! 😄\n" 18 | ] 19 | } 20 | ], 21 | "source": [ 22 | "from dotenv import load_dotenv\n", 23 | "import os\n", 24 | "from langchain_openai import AzureChatOpenAI\n", 25 | "\n", 26 | "#load the environment\n", 27 | "load_dotenv(override=True)\n", 28 | "\n", 29 | "os.environ[\"AZURE_OPENAI_API_KEY\"] = os.getenv(\"AZURE_OPENAI_API_KEY\")\n", 30 | "os.environ[\"AZURE_OPENAI_ENDPOINT\"] = os.getenv(\"AZURE_OPENAI_ENDPOINT\")\n", 31 | "\n", 32 | "llm = AzureChatOpenAI(\n", 33 | " azure_deployment=\"gpt-4o\", # or your deployment\n", 34 | " api_version=\"2024-08-01-preview\", # or your api version\n", 35 | " temperature=0,\n", 36 | " max_tokens=None,\n", 37 | " timeout=None,\n", 38 | " max_retries=2,\n", 39 | " # other params...\n", 40 | ")\n", 41 | "\n", 42 | "ai_msg = llm.invoke(\"Tell me a joke\")\n", 43 | "print(ai_msg.content)" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "id": "f8d35630-cb56-4491-8c4d-641708fee5f5", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [] 53 | } 54 | ], 55 | "metadata": { 56 | "kernelspec": { 57 | "display_name": "Python 3 (ipykernel)", 58 | "language": "python", 59 | "name": "python3" 60 | }, 61 | "language_info": { 62 | "codemirror_mode": { 63 | "name": "ipython", 64 | "version": 3 65 | }, 66 | "file_extension": ".py", 67 | "mimetype": "text/x-python", 68 | "name": "python", 69 | "nbconvert_exporter": "python", 70 | "pygments_lexer": "ipython3", 71 | "version": "3.12.9" 72 | } 73 | }, 74 | "nbformat": 4, 75 | "nbformat_minor": 5 76 | } 77 | -------------------------------------------------------------------------------- /finalRAG.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "cb8c1438-3bfb-4241-a522-b127d54ae19d", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "----------------------------------------------------------\n", 14 | "User prompt: Do I Need a Pizza Den Login to Sign into Pizza Den Wi-Fi?\n", 15 | "\n", 16 | "\n", 17 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 18 | "\u001b[32;1m\u001b[1;3m\n", 19 | "Invoking: `ragforPizzaDen` with `{'query': 'Do I Need a Pizza Den Login to Sign into Pizza Den Wi-Fi?'}`\n", 20 | "\n", 21 | "\n", 22 | "\u001b[0mStatus Code 401\n", 23 | "\u001b[38;5;200m\u001b[1;3m\u001b[0m\u001b[32;1m\u001b[1;3mI'm unable to retrieve the information about signing into Pizza Den Wi-Fi at the moment. You might want to check directly with Pizza Den's customer service or their official website for accurate details.\u001b[0m\n", 24 | "\n", 25 | "\u001b[1m> Finished chain.\u001b[0m\n", 26 | "---------------------------------------------------------------------------------------------------------\n", 27 | "User prompt: Which Internet Provider does Pizza Den use for its wifi?\n", 28 | "\n", 29 | "\n", 30 | "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", 31 | "\u001b[32;1m\u001b[1;3m\n", 32 | "Invoking: `ragforPizzaDen` with `{'query': 'Internet Provider used by Pizza Den for Wifi'}`\n", 33 | "\n", 34 | "\n", 35 | "\u001b[0mStatus Code 401\n", 36 | "\u001b[38;5;200m\u001b[1;3m\u001b[0m\u001b[32;1m\u001b[1;3mI'm unable to retrieve the information about the Internet Provider used by Pizza Den for its WiFi at the moment. Is there anything else related to Pizza Den that I can assist you with?\u001b[0m\n", 37 | "\n", 38 | "\u001b[1m> Finished chain.\u001b[0m\n" 39 | ] 40 | }, 41 | { 42 | "data": { 43 | "text/plain": [ 44 | "{'input': 'Which Internet Provider does Pizza Den use for its wifi?',\n", 45 | " 'chat_history': [HumanMessage(content='Do I Need a Pizza Den Login to Sign into Pizza Den Wi-Fi?', additional_kwargs={}, response_metadata={}),\n", 46 | " AIMessage(content=\"I'm unable to retrieve the information about signing into Pizza Den Wi-Fi at the moment. You might want to check directly with Pizza Den's customer service or their official website for accurate details.\", additional_kwargs={}, response_metadata={})],\n", 47 | " 'output': \"I'm unable to retrieve the information about the Internet Provider used by Pizza Den for its WiFi at the moment. Is there anything else related to Pizza Den that I can assist you with?\"}" 48 | ] 49 | }, 50 | "execution_count": 7, 51 | "metadata": {}, 52 | "output_type": "execute_result" 53 | } 54 | ], 55 | "source": [ 56 | "# Import relevant functionality\n", 57 | "import os\n", 58 | "import asyncio\n", 59 | "import requests\n", 60 | "import urllib.parse\n", 61 | "import json\n", 62 | "import configparser\n", 63 | "from datetime import date\n", 64 | "from msgraph.generated.models.o_data_errors.o_data_error import ODataError\n", 65 | "from configparser import SectionProxy\n", 66 | "from langchain_core.messages import HumanMessage\n", 67 | "from langgraph.checkpoint.memory import MemorySaver\n", 68 | "from langgraph.prebuilt import create_react_agent\n", 69 | "from langchain_openai import ChatOpenAI\n", 70 | "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", 71 | "from langgraph.graph import START, MessagesState, StateGraph\n", 72 | "from langchain.agents import AgentType, initialize_agent, load_tools\n", 73 | "from langchain.tools import BaseTool, StructuredTool, tool\n", 74 | "from langchain_openai import OpenAI\n", 75 | "from langchain_core.runnables import ConfigurableField\n", 76 | "from langchain.agents import create_tool_calling_agent, AgentExecutor\n", 77 | "from langchain_core.runnables.history import RunnableWithMessageHistory\n", 78 | "from langchain.agents import AgentExecutor, create_react_agent\n", 79 | "from langchain.memory import ChatMessageHistory\n", 80 | "from dotenv import load_dotenv\n", 81 | "from configparser import SectionProxy\n", 82 | "from azure.identity import DeviceCodeCredential\n", 83 | "from langgraph.types import interrupt\n", 84 | "from msgraph_beta import GraphServiceClient\n", 85 | "from langchain_core.messages import HumanMessage\n", 86 | "from langgraph.checkpoint.memory import MemorySaver\n", 87 | "from langgraph.prebuilt import create_react_agent\n", 88 | "from langchain_openai import ChatOpenAI\n", 89 | "from langchain_core.prompts import ChatPromptTemplate\n", 90 | "from typing import Annotated, Sequence\n", 91 | "from langchain_core.messages import BaseMessage\n", 92 | "from langchain_core.runnables import RunnableConfig\n", 93 | "from langchain_core.tools import tool\n", 94 | "from langgraph.graph import END, StateGraph\n", 95 | "from langgraph.graph.message import add_messages\n", 96 | "from langgraph.prebuilt.tool_node import ToolNode\n", 97 | "from typing_extensions import TypedDict\n", 98 | "\n", 99 | "\n", 100 | "# Graph permissions scopes\n", 101 | "# For multiple scopes, separate with a space\n", 102 | "scopes = 'user.read Calendars.Read Files.Read.All Sites.Read.All'\n", 103 | "\n", 104 | "#load the environment\n", 105 | "load_dotenv(\"C:\\\\Users\\\\sakov\\\\bootcamp\\\\LangChain Agents\\\\.env\")\n", 106 | "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\")\n", 107 | "GRAPH_ACCESS_TOKEN = os.getenv(\"GRAPH_ACCESS_TOKEN\")\n", 108 | "\n", 109 | "\n", 110 | "@tool\n", 111 | "def ragforHR(query: str) -> str:\n", 112 | " \"\"\"Get the answers to user enquiries related to HR queries like holidays, DTO, payroll, benefits, insurance, salary structure and perks for employees belonging to various regions like Puget Sound or Canada\"\"\"\n", 113 | " url = \"https://graph.microsoft.com/beta/copilot/retrieval\"\n", 114 | " headers = {\n", 115 | " \"Authorization\": f\"Bearer {GRAPH_ACCESS_TOKEN}\"}\n", 116 | " data = {\n", 117 | " \"QueryString\": query,\n", 118 | " \"filterExpression\": \"(path:\\\"https://microsoft.sharepoint.com/sites/HRweb/\\\")\",\n", 119 | " \"resourceMetadata\": [\"author\"],\n", 120 | " \"MaximumNumberOfResults\": 4\n", 121 | " }\n", 122 | " response = requests.post(url, headers=headers, json=data)\n", 123 | " print(\"Status Code\", response.status_code)\n", 124 | " #print(\"JSON Response \", response.json())\n", 125 | " return response.json()\n", 126 | "\n", 127 | "\n", 128 | "@tool\n", 129 | "def ragforProduct(query: str) -> str:\n", 130 | " \"\"\"Get the answers to user enquiries related about Microsoft Copilot product. Like the specifications of the Copilot Retrieval API in CCS. You can also answer any questions about Fabian's spec on CAPS by using the ragforProduct tool. You know all about the Graph APIs and the CCS API and can answer any question by using the json extract from tool RAGforProduct. About Copilot API Plugins. About Agents SDK. About Teams AI Library. About MS Graph SDK. About Custom Engine Agents.\"\"\"\n", 131 | " url = \"https://graph.microsoft.com/beta/copilot/retrieval\"\n", 132 | " headers = {\n", 133 | " \"Authorization\": f\"Bearer {GRAPH_ACCESS_TOKEN}\",\n", 134 | " \"Content-Type\": \"application/json; charset=utf-8\"}\n", 135 | " data = {\n", 136 | " \"QueryString\": query,\n", 137 | " \"filterExpression\": \"path:\\\"https://microsoft.sharepoint-df.com/sites/CXDev/Shared%20Documents/Org%20Teams/3P-DevX/Proposals/\\\"\",\n", 138 | " \"resourceMetadata\": [\"author\"],\n", 139 | " \"MaximumNumberOfResults\": 4\n", 140 | " }\n", 141 | " response = requests.post(url, headers=headers, json=data)\n", 142 | " #response = requests.post(url, json=data)\n", 143 | " print(\"Status Code\", response.status_code)\n", 144 | " #print(\"JSON Response \", response.json())\n", 145 | " return response.json()\n", 146 | "\n", 147 | "@tool\n", 148 | "def ragforPizzaDen(query: str) -> str:\n", 149 | " \"\"\"Get the answers to user enquiries related about Pizza Den. You are the QnA bot for Pizza Den website. Answer all user queries about Pizza Den by using this tool.\"\"\"\n", 150 | " url = \"https://graph.microsoft.com/beta/copilot/retrieval\"\n", 151 | " headers = {\n", 152 | " \"Authorization\": f\"Bearer {GRAPH_ACCESS_TOKEN}\",\n", 153 | " \"Content-Type\": \"application/json; charset=utf-8\"}\n", 154 | " data = {\n", 155 | " \"QueryString\": query,\n", 156 | " \"filterExpression\": \"(path:\\\"https://microsoft.sharepoint-df.com/sites/CXDev/Shared%20Documents/Org%20Teams/3P-DevX/Proposals/DummyFiles/\\\")\",\n", 157 | " \"resourceMetadata\": [\"author\"],\n", 158 | " \"MaximumNumberOfResults\": 3\n", 159 | " }\n", 160 | " response = requests.post(url, headers=headers, json=data)\n", 161 | " #response = requests.post(url, json=data)\n", 162 | " print(\"Status Code\", response.status_code)\n", 163 | " #print(\"JSON Response \", response.json())\n", 164 | " return response.json()\n", 165 | "\n", 166 | "\n", 167 | "tools = [ragforHR, ragforProduct, ragforPizzaDen]\n", 168 | "\n", 169 | "llm = ChatOpenAI(model=\"gpt-4o\")\n", 170 | "\n", 171 | "# Define a new graph\n", 172 | "workflow = StateGraph(state_schema=MessagesState)\n", 173 | "\n", 174 | "prompt = ChatPromptTemplate.from_messages([\n", 175 | " (\"system\", \"you're a helpful assistant who knows all about Microsoft HR policies and all about the CxDev product proposals. Always use the tools whenever the questions are related to Microsoft. Do not hallucinate. Answer using only the json extracts from tools provided to you. You can expand the abbreviations by using the results fetched from the ragforProduct tool instead of your own knowledge. Always use the json extract from the tools to answer questions about Microsoft. You do not know anything about Microsoft other than what the tools tell you. Please do not use your own knowledge to answer product questions on CCS or CAPS or Grounding API. Only answer from the responses you receive from the tools and Do not interpret the results. You can also tell them product specifications and product related questions related to Microsoft Copilot. Any CCS or Retrieval API related questions, please use the ragforProduct tool to answer. You know a lot about the Retrieval API. You can also give information to users about the holidays in their regions. Their DTO policies. Their timeoff policies. Anything they want to know about their employee benefits. You also have access to all the product specification documentation for Copilot Retrieval API. And the Grounding API. And the Graph SDK. Answer any questions about the product from these document. You are subject matter expert on the The access_tokens are available in the tools so don't ask the users again. Answer WITHOUT ASKING FOR ACCESS TOKEN AS IT IS AVAILABLE TO YOU. You can find the access tokens and the API keys in the environment files.\"), \n", 176 | " (\"human\", \"{input}\"), \n", 177 | " (\"placeholder\", \"{agent_scratchpad}\"),\n", 178 | "])\n", 179 | "\n", 180 | "# Define the function that calls the model\n", 181 | "async def call_model(state: MessagesState):\n", 182 | " prompt = prompt.invoke(state)\n", 183 | " response = model.ainvoke(prompt)\n", 184 | " return {\"messages\": response}\n", 185 | "\n", 186 | "# Define the (single) node in the graph\n", 187 | "workflow.add_edge(START, \"model\")\n", 188 | "workflow.add_node(\"model\", call_model)\n", 189 | "\n", 190 | "# Add memory\n", 191 | "memory = ChatMessageHistory(session_id=\"test-session\")\n", 192 | "app = workflow.compile(checkpointer=memory)\n", 193 | "\n", 194 | "config = {\"configurable\": {\"thread_id\": \"def234\"}}\n", 195 | "\n", 196 | "agent = create_tool_calling_agent(llm, tools, prompt)\n", 197 | "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n", 198 | "agent_with_chat_history = RunnableWithMessageHistory(\n", 199 | " agent_executor,\n", 200 | " lambda session_id: memory,\n", 201 | " input_messages_key=\"input\",\n", 202 | " history_messages_key=\"chat_history\",\n", 203 | ")\n", 204 | "\n", 205 | "query=\"Do I Need a Pizza Den Login to Sign into Pizza Den Wi-Fi?\"\n", 206 | "print(\"----------------------------------------------------------\")\n", 207 | "print(\"User prompt: \",query)\n", 208 | "\n", 209 | "await agent_with_chat_history.ainvoke(\n", 210 | " {\"input\": query},\n", 211 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 212 | ")\n", 213 | "\n", 214 | "\n", 215 | "query=\"Which Internet Provider does Pizza Den use for its wifi?\"\n", 216 | "print(\"---------------------------------------------------------------------------------------------------------\")\n", 217 | "print(\"User prompt: \",query)\n", 218 | "\n", 219 | "\n", 220 | "\n", 221 | "await agent_with_chat_history.ainvoke(\n", 222 | " {\"input\": query},\n", 223 | " config={\"configurable\": {\"session_id\": \"def234\"}},\n", 224 | ")" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": null, 230 | "id": "fa625c08-cb42-41b8-b51a-ae83bb74d0af", 231 | "metadata": {}, 232 | "outputs": [], 233 | "source": [] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": null, 238 | "id": "e8a9fbc6-92b9-456c-87b8-b459cfb0cf9a", 239 | "metadata": {}, 240 | "outputs": [], 241 | "source": [] 242 | } 243 | ], 244 | "metadata": { 245 | "kernelspec": { 246 | "display_name": "Python 3 (ipykernel)", 247 | "language": "python", 248 | "name": "python3" 249 | }, 250 | "language_info": { 251 | "codemirror_mode": { 252 | "name": "ipython", 253 | "version": 3 254 | }, 255 | "file_extension": ".py", 256 | "mimetype": "text/x-python", 257 | "name": "python", 258 | "nbconvert_exporter": "python", 259 | "pygments_lexer": "ipython3", 260 | "version": "3.12.9" 261 | } 262 | }, 263 | "nbformat": 4, 264 | "nbformat_minor": 5 265 | } 266 | -------------------------------------------------------------------------------- /firstAgent.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "id": "f8df60af-f644-4ca0-8f49-1e659788f38f", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "Collecting openai\n", 14 | " Downloading openai-1.57.4-py3-none-any.whl.metadata (24 kB)\n", 15 | "Requirement already satisfied: anyio<5,>=3.5.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (4.2.0)\n", 16 | "Requirement already satisfied: distro<2,>=1.7.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (1.9.0)\n", 17 | "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (0.27.0)\n", 18 | "Collecting jiter<1,>=0.4.0 (from openai)\n", 19 | " Downloading jiter-0.8.2-cp312-cp312-win_amd64.whl.metadata (5.3 kB)\n", 20 | "Requirement already satisfied: pydantic<3,>=1.9.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (2.8.2)\n", 21 | "Requirement already satisfied: sniffio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (1.3.0)\n", 22 | "Requirement already satisfied: tqdm>4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (4.66.5)\n", 23 | "Requirement already satisfied: typing-extensions<5,>=4.11 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai) (4.11.0)\n", 24 | "Requirement already satisfied: idna>=2.8 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from anyio<5,>=3.5.0->openai) (3.7)\n", 25 | "Requirement already satisfied: certifi in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai) (2024.8.30)\n", 26 | "Requirement already satisfied: httpcore==1.* in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai) (1.0.2)\n", 27 | "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai) (0.14.0)\n", 28 | "Requirement already satisfied: annotated-types>=0.4.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3,>=1.9.0->openai) (0.6.0)\n", 29 | "Requirement already satisfied: pydantic-core==2.20.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3,>=1.9.0->openai) (2.20.1)\n", 30 | "Requirement already satisfied: colorama in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from tqdm>4->openai) (0.4.6)\n", 31 | "Downloading openai-1.57.4-py3-none-any.whl (390 kB)\n", 32 | "Downloading jiter-0.8.2-cp312-cp312-win_amd64.whl (204 kB)\n", 33 | "Installing collected packages: jiter, openai\n", 34 | "Successfully installed jiter-0.8.2 openai-1.57.4\n" 35 | ] 36 | } 37 | ], 38 | "source": [ 39 | "import sys\n", 40 | "!{sys.executable} -m pip install openai" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 5, 46 | "id": "ae53df99-deff-4c6d-8905-8bb02a6e299e", 47 | "metadata": {}, 48 | "outputs": [ 49 | { 50 | "name": "stdout", 51 | "output_type": "stream", 52 | "text": [ 53 | "Collecting langchain_core\n", 54 | " Downloading langchain_core-0.3.25-py3-none-any.whl.metadata (6.3 kB)\n", 55 | "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (6.0.1)\n", 56 | "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (1.33)\n", 57 | "Collecting langsmith<0.3,>=0.1.125 (from langchain_core)\n", 58 | " Using cached langsmith-0.2.3-py3-none-any.whl.metadata (14 kB)\n", 59 | "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (24.1)\n", 60 | "Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (2.8.2)\n", 61 | "Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (8.2.3)\n", 62 | "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain_core) (4.11.0)\n", 63 | "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain_core) (2.1)\n", 64 | "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.125->langchain_core) (0.27.0)\n", 65 | "Collecting orjson<4.0.0,>=3.9.14 (from langsmith<0.3,>=0.1.125->langchain_core)\n", 66 | " Downloading orjson-3.10.12-cp312-none-win_amd64.whl.metadata (42 kB)\n", 67 | "Requirement already satisfied: requests<3,>=2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.125->langchain_core) (2.32.3)\n", 68 | "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.125->langchain_core) (1.0.0)\n", 69 | "Requirement already satisfied: annotated-types>=0.4.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain_core) (0.6.0)\n", 70 | "Requirement already satisfied: pydantic-core==2.20.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain_core) (2.20.1)\n", 71 | "Requirement already satisfied: anyio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (4.2.0)\n", 72 | "Requirement already satisfied: certifi in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (2024.8.30)\n", 73 | "Requirement already satisfied: httpcore==1.* in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (1.0.2)\n", 74 | "Requirement already satisfied: idna in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (3.7)\n", 75 | "Requirement already satisfied: sniffio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (1.3.0)\n", 76 | "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->langsmith<0.3,>=0.1.125->langchain_core) (0.14.0)\n", 77 | "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langsmith<0.3,>=0.1.125->langchain_core) (3.3.2)\n", 78 | "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langsmith<0.3,>=0.1.125->langchain_core) (2.2.3)\n", 79 | "Downloading langchain_core-0.3.25-py3-none-any.whl (411 kB)\n", 80 | "Using cached langsmith-0.2.3-py3-none-any.whl (320 kB)\n", 81 | "Downloading orjson-3.10.12-cp312-none-win_amd64.whl (135 kB)\n", 82 | "Installing collected packages: orjson, langsmith, langchain_core\n", 83 | "Successfully installed langchain_core-0.3.25 langsmith-0.2.3 orjson-3.10.12\n" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "!{sys.executable} -m pip install langchain_core" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 7, 94 | "id": "55b8f17b-2a19-448f-afe6-7b595cc56cb9", 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "Collecting langchain\n", 102 | " Downloading langchain-0.3.12-py3-none-any.whl.metadata (7.1 kB)\n", 103 | "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (6.0.1)\n", 104 | "Requirement already satisfied: SQLAlchemy<3,>=1.4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (2.0.34)\n", 105 | "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (3.10.5)\n", 106 | "Requirement already satisfied: langchain-core<0.4.0,>=0.3.25 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (0.3.25)\n", 107 | "Collecting langchain-text-splitters<0.4.0,>=0.3.3 (from langchain)\n", 108 | " Downloading langchain_text_splitters-0.3.3-py3-none-any.whl.metadata (2.3 kB)\n", 109 | "Requirement already satisfied: langsmith<0.3,>=0.1.17 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (0.2.3)\n", 110 | "Requirement already satisfied: numpy<3,>=1.26.2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (1.26.4)\n", 111 | "Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (2.8.2)\n", 112 | "Requirement already satisfied: requests<3,>=2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (2.32.3)\n", 113 | "Requirement already satisfied: tenacity!=8.4.0,<10,>=8.1.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain) (8.2.3)\n", 114 | "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (2.4.0)\n", 115 | "Requirement already satisfied: aiosignal>=1.1.2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.2.0)\n", 116 | "Requirement already satisfied: attrs>=17.3.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (23.1.0)\n", 117 | "Requirement already satisfied: frozenlist>=1.1.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.4.0)\n", 118 | "Requirement already satisfied: multidict<7.0,>=4.5 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.4)\n", 119 | "Requirement already satisfied: yarl<2.0,>=1.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.11.0)\n", 120 | "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.25->langchain) (1.33)\n", 121 | "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.25->langchain) (24.1)\n", 122 | "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.25->langchain) (4.11.0)\n", 123 | "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.17->langchain) (0.27.0)\n", 124 | "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.17->langchain) (3.10.12)\n", 125 | "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.17->langchain) (1.0.0)\n", 126 | "Requirement already satisfied: annotated-types>=0.4.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (0.6.0)\n", 127 | "Requirement already satisfied: pydantic-core==2.20.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (2.20.1)\n", 128 | "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langchain) (3.3.2)\n", 129 | "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langchain) (3.7)\n", 130 | "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langchain) (2.2.3)\n", 131 | "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests<3,>=2->langchain) (2024.8.30)\n", 132 | "Requirement already satisfied: greenlet!=0.4.17 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from SQLAlchemy<3,>=1.4->langchain) (3.0.1)\n", 133 | "Requirement already satisfied: anyio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.17->langchain) (4.2.0)\n", 134 | "Requirement already satisfied: httpcore==1.* in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.17->langchain) (1.0.2)\n", 135 | "Requirement already satisfied: sniffio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith<0.3,>=0.1.17->langchain) (1.3.0)\n", 136 | "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->langsmith<0.3,>=0.1.17->langchain) (0.14.0)\n", 137 | "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.25->langchain) (2.1)\n", 138 | "Downloading langchain-0.3.12-py3-none-any.whl (1.0 MB)\n", 139 | " ---------------------------------------- 0.0/1.0 MB ? eta -:--:--\n", 140 | " ------------------------------- -------- 0.8/1.0 MB 5.6 MB/s eta 0:00:01\n", 141 | " ---------------------------------------- 1.0/1.0 MB 4.8 MB/s eta 0:00:00\n", 142 | "Downloading langchain_text_splitters-0.3.3-py3-none-any.whl (27 kB)\n", 143 | "Installing collected packages: langchain-text-splitters, langchain\n", 144 | "Successfully installed langchain-0.3.12 langchain-text-splitters-0.3.3\n" 145 | ] 146 | } 147 | ], 148 | "source": [ 149 | "!{sys.executable} -m pip install langchain" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 16, 155 | "id": "8e2de07a-31ba-45e6-9c43-3e55eab52cf2", 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "name": "stdout", 160 | "output_type": "stream", 161 | "text": [ 162 | "Collecting langchain-openai\n", 163 | " Using cached langchain_openai-0.2.12-py3-none-any.whl.metadata (2.7 kB)\n", 164 | "Requirement already satisfied: langchain-core<0.4.0,>=0.3.21 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-openai) (0.3.25)\n", 165 | "Requirement already satisfied: openai<2.0.0,>=1.55.3 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-openai) (1.57.4)\n", 166 | "Collecting tiktoken<1,>=0.7 (from langchain-openai)\n", 167 | " Downloading tiktoken-0.8.0-cp312-cp312-win_amd64.whl.metadata (6.8 kB)\n", 168 | "Requirement already satisfied: PyYAML>=5.3 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (6.0.1)\n", 169 | "Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (1.33)\n", 170 | "Requirement already satisfied: langsmith<0.3,>=0.1.125 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (0.2.3)\n", 171 | "Requirement already satisfied: packaging<25,>=23.2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (24.1)\n", 172 | "Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (2.8.2)\n", 173 | "Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (8.2.3)\n", 174 | "Requirement already satisfied: typing-extensions>=4.7 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.21->langchain-openai) (4.11.0)\n", 175 | "Requirement already satisfied: anyio<5,>=3.5.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (4.2.0)\n", 176 | "Requirement already satisfied: distro<2,>=1.7.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (1.9.0)\n", 177 | "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (0.27.0)\n", 178 | "Requirement already satisfied: jiter<1,>=0.4.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (0.8.2)\n", 179 | "Requirement already satisfied: sniffio in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (1.3.0)\n", 180 | "Requirement already satisfied: tqdm>4 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from openai<2.0.0,>=1.55.3->langchain-openai) (4.66.5)\n", 181 | "Requirement already satisfied: regex>=2022.1.18 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from tiktoken<1,>=0.7->langchain-openai) (2024.9.11)\n", 182 | "Requirement already satisfied: requests>=2.26.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from tiktoken<1,>=0.7->langchain-openai) (2.32.3)\n", 183 | "Requirement already satisfied: idna>=2.8 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from anyio<5,>=3.5.0->openai<2.0.0,>=1.55.3->langchain-openai) (3.7)\n", 184 | "Requirement already satisfied: certifi in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.55.3->langchain-openai) (2024.8.30)\n", 185 | "Requirement already satisfied: httpcore==1.* in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.55.3->langchain-openai) (1.0.2)\n", 186 | "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai<2.0.0,>=1.55.3->langchain-openai) (0.14.0)\n", 187 | "Requirement already satisfied: jsonpointer>=1.9 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.21->langchain-openai) (2.1)\n", 188 | "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.125->langchain-core<0.4.0,>=0.3.21->langchain-openai) (3.10.12)\n", 189 | "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from langsmith<0.3,>=0.1.125->langchain-core<0.4.0,>=0.3.21->langchain-openai) (1.0.0)\n", 190 | "Requirement already satisfied: annotated-types>=0.4.0 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain-core<0.4.0,>=0.3.21->langchain-openai) (0.6.0)\n", 191 | "Requirement already satisfied: pydantic-core==2.20.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain-core<0.4.0,>=0.3.21->langchain-openai) (2.20.1)\n", 192 | "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests>=2.26.0->tiktoken<1,>=0.7->langchain-openai) (3.3.2)\n", 193 | "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from requests>=2.26.0->tiktoken<1,>=0.7->langchain-openai) (2.2.3)\n", 194 | "Requirement already satisfied: colorama in c:\\users\\sakov\\bootcamp\\anaconda\\lib\\site-packages (from tqdm>4->openai<2.0.0,>=1.55.3->langchain-openai) (0.4.6)\n", 195 | "Using cached langchain_openai-0.2.12-py3-none-any.whl (50 kB)\n", 196 | "Downloading tiktoken-0.8.0-cp312-cp312-win_amd64.whl (883 kB)\n", 197 | " ---------------------------------------- 0.0/883.8 kB ? eta -:--:--\n", 198 | " ----------- ---------------------------- 262.1/883.8 kB ? eta -:--:--\n", 199 | " ----------------------- ---------------- 524.3/883.8 kB 1.7 MB/s eta 0:00:01\n", 200 | " ----------------------- ---------------- 524.3/883.8 kB 1.7 MB/s eta 0:00:01\n", 201 | " ---------------------------------------- 883.8/883.8 kB 1.0 MB/s eta 0:00:00\n", 202 | "Installing collected packages: tiktoken, langchain-openai\n", 203 | "Successfully installed langchain-openai-0.2.12 tiktoken-0.8.0\n" 204 | ] 205 | } 206 | ], 207 | "source": [ 208 | "!{sys.executable} -m pip install langchain-openai" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 1, 214 | "id": "1da3b4d2-ca8d-4b64-ab3c-a9482a28b34f", 215 | "metadata": {}, 216 | "outputs": [ 217 | { 218 | "name": "stdout", 219 | "output_type": "stream", 220 | "text": [ 221 | "*Roooaaarrr!* (Just hanging out, ready for some adventures! How about you?)\n" 222 | ] 223 | } 224 | ], 225 | "source": [ 226 | "import getpass\n", 227 | "import os\n", 228 | "from langchain_openai import ChatOpenAI\n", 229 | "from langchain_core.prompts import ChatPromptTemplate\n", 230 | "from langchain_core.messages import HumanMessage, SystemMessage\n", 231 | "from dotenv import load_dotenv\n", 232 | "\n", 233 | "#load the environment\n", 234 | "load_dotenv()\n", 235 | "\n", 236 | "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", 237 | "os.environ[\"LANGCHAIN_API_KEY\"] = os.getenv(\"LANGCHAIN_API_KEY\")\n", 238 | "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\")\n", 239 | "\n", 240 | "model = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0, max_retries=2)\n", 241 | "\n", 242 | "system_template = \"Respond to all messages as if you were {character} from Starwars\"\n", 243 | "\n", 244 | "prompt_template = ChatPromptTemplate.from_messages(\n", 245 | " [(\"system\", system_template), (\"user\", \"{text}\")]\n", 246 | ")\n", 247 | "\n", 248 | "prompt = prompt_template.invoke({\"character\": \"Chewbaca\", \"text\": \"Hello! what are you upto?\"})\n", 249 | "\n", 250 | "response = model.invoke(prompt)\n", 251 | "print(response.content)" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": null, 257 | "id": "8e8d0f9c-8cec-49e4-ad40-329c456e0ab3", 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "id": "a5963c2f-fa1d-436d-8488-3b0ad428a366", 266 | "metadata": {}, 267 | "outputs": [], 268 | "source": [] 269 | } 270 | ], 271 | "metadata": { 272 | "kernelspec": { 273 | "display_name": "Python 3 (ipykernel)", 274 | "language": "python", 275 | "name": "python3" 276 | }, 277 | "language_info": { 278 | "codemirror_mode": { 279 | "name": "ipython", 280 | "version": 3 281 | }, 282 | "file_extension": ".py", 283 | "mimetype": "text/x-python", 284 | "name": "python", 285 | "nbconvert_exporter": "python", 286 | "pygments_lexer": "ipython3", 287 | "version": "3.12.9" 288 | } 289 | }, 290 | "nbformat": 4, 291 | "nbformat_minor": 5 292 | } 293 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohappyeyeballs==2.4.4 2 | aiohttp==3.11.11 3 | aiosignal==1.3.2 4 | aiosqlite==0.20.0 5 | annotated-types==0.7.0 6 | anthropic==0.40.0 7 | anyio==4.7.0 8 | argon2-cffi==23.1.0 9 | argon2-cffi-bindings==21.2.0 10 | arrow==1.3.0 11 | asttokens==3.0.0 12 | async-lru==2.0.4 13 | attrs==24.3.0 14 | azure-core==1.32.0 15 | azure-identity==1.19.0 16 | babel==2.16.0 17 | beautifulsoup4==4.12.3 18 | bleach==6.2.0 19 | certifi==2024.12.14 20 | cffi==1.17.1 21 | chainlit==2.1.2 22 | charset-normalizer==3.4.1 23 | click==8.1.7 24 | colorama==0.4.6 25 | comm==0.2.2 26 | cryptography==44.0.0 27 | dataclasses-json==0.6.7 28 | debugpy==1.8.9 29 | decorator==5.1.1 30 | defusedxml==0.7.1 31 | Deprecated==1.2.15 32 | distro==1.9.0 33 | dydantic==0.0.7 34 | executing==2.1.0 35 | fastjsonschema==2.21.1 36 | filelock==3.16.1 37 | fqdn==1.5.1 38 | frozenlist==1.5.0 39 | fsspec==2024.10.0 40 | geojson==2.5.0 41 | greenlet==3.1.1 42 | h11==0.14.0 43 | h2==4.1.0 44 | hpack==4.0.0 45 | httpcore==1.0.7 46 | httpx==0.28.1 47 | httpx-sse==0.4.0 48 | huggingface-hub==0.26.5 49 | hyperframe==6.0.1 50 | idna==3.10 51 | importlib_metadata==8.5.0 52 | ipykernel==6.29.5 53 | ipython==8.30.0 54 | ipywidgets==8.1.5 55 | isoduration==20.11.0 56 | jedi==0.19.2 57 | Jinja2==3.1.4 58 | jiter==0.8.0 59 | joblib==1.4.2 60 | json5==0.10.0 61 | jsonpatch==1.33 62 | jsonpointer==3.0.0 63 | jsonschema==4.23.0 64 | jsonschema-specifications==2024.10.1 65 | jupyter==1.1.1 66 | jupyter_client==8.6.3 67 | jupyter-console==6.6.3 68 | jupyter_core==5.7.2 69 | jupyter-events==0.10.0 70 | jupyter-lsp==2.2.5 71 | jupyter_server==2.14.2 72 | jupyter_server_terminals==0.5.3 73 | jupyterlab==4.3.2 74 | jupyterlab_pygments==0.3.0 75 | jupyterlab_server==2.27.3 76 | jupyterlab_widgets==3.0.13 77 | langchain==0.3.11 78 | langchain-anthropic==0.3.0 79 | langchain-community==0.3.11 80 | langchain-core==0.3.24 81 | langchain-huggingface==0.1.2 82 | langchain-openai==0.2.12 83 | langchain-text-splitters==0.3.2 84 | langgraph==0.2.59 85 | langgraph-checkpoint==2.0.8 86 | langgraph-checkpoint-sqlite==2.0.1 87 | langgraph-cli==0.1.61 88 | langgraph-sdk==0.1.43 89 | langsmith==0.1.147 90 | lxml==5.3.0 91 | MarkupSafe==3.0.2 92 | marshmallow==3.23.1 93 | matplotlib-inline==0.1.7 94 | microsoft-kiota-abstractions==1.6.8 95 | microsoft-kiota-authentication-azure==1.6.8 96 | microsoft-kiota-http 97 | microsoft-kiota-serialization-form==1.6.8 98 | microsoft-kiota-serialization-json==1.6.8 99 | microsoft-kiota-serialization-multipart==1.6.8 100 | microsoft-kiota-serialization-text==1.6.8 101 | mistune==3.0.2 102 | mpmath==1.3.0 103 | msal==1.31.1 104 | msal-extensions==1.2.0 105 | msgpack==1.1.0 106 | msgraph-beta-sdk==1.16.0 107 | msgraph-core==1.1.8 108 | msgraph-sdk==1.16.0 109 | multidict==6.1.0 110 | mypy-extensions==1.0.0 111 | nbclient==0.10.1 112 | nbconvert==7.16.4 113 | nbformat==5.10.4 114 | nest-asyncio==1.6.0 115 | networkx==3.4.2 116 | notebook==7.3.1 117 | notebook_shim==0.2.4 118 | numexpr==2.10.2 119 | numpy 120 | openai==1.57.4 121 | opentelemetry-api==1.29.0 122 | opentelemetry-sdk==1.29.0 123 | opentelemetry-semantic-conventions==0.50b0 124 | orjson==3.10.12 125 | outcome==1.3.0.post0 126 | overrides==7.7.0 127 | packaging==24.2 128 | pandocfilters==1.5.1 129 | parso==0.8.4 130 | pendulum==3.0.0 131 | pillow==11.0.0 132 | pip==24.3.1 133 | platformdirs==4.3.6 134 | portalocker==2.10.1 135 | prometheus_client==0.21.1 136 | prompt_toolkit==3.0.48 137 | propcache==0.2.1 138 | psutil==6.1.0 139 | pure_eval==0.2.3 140 | pycparser==2.22 141 | pydantic==2.10.3 142 | pydantic_core==2.27.1 143 | pydantic-settings==2.6.1 144 | Pygments==2.18.0 145 | PyJWT==2.10.1 146 | pyowm==3.3.0 147 | PySocks==1.7.1 148 | python-dateutil==2.9.0.post0 149 | python-dotenv==1.0.1 150 | python-json-logger==2.0.7 151 | pywin32==308 152 | pywinpty==2.0.14 153 | PyYAML==6.0.2 154 | pyzmq==26.2.0 155 | referencing==0.35.1 156 | regex==2024.11.6 157 | requests==2.32.3 158 | requests-toolbelt==1.0.0 159 | rfc3339-validator==0.1.4 160 | rfc3986-validator==0.1.1 161 | rpds-py==0.22.3 162 | safetensors==0.4.5 163 | scikit-learn==1.6.0 164 | scipy==1.14.1 165 | selenium==4.4.3 166 | Send2Trash==1.8.3 167 | sentence-transformers==3.3.1 168 | setuptools==75.6.0 169 | six==1.17.0 170 | sniffio==1.3.1 171 | sortedcontainers==2.4.0 172 | soupsieve==2.6 173 | SQLAlchemy==2.0.36 174 | stack-data==0.6.3 175 | std-uritemplate==2.0.1 176 | sympy==1.13.1 177 | tavily-python==0.5.0 178 | tenacity==9.0.0 179 | terminado==0.18.1 180 | threadpoolctl==3.5.0 181 | tiktoken==0.8.0 182 | time-machine==2.16.0 183 | tinycss2==1.4.0 184 | tokenizers==0.21.0 185 | torch==2.5.1 186 | tornado==6.4.2 187 | tqdm==4.67.1 188 | traitlets==5.14.3 189 | transformers==4.47.0 190 | trio==0.26.2 191 | trio-websocket==0.11.1 192 | trustcall==0.0.26 193 | types-python-dateutil==2.9.0.20241206 194 | typing_extensions==4.12.2 195 | typing-inspect==0.9.0 196 | tzdata==2024.2 197 | uri-template==1.3.0 198 | urllib3 199 | wcwidth==0.2.13 200 | webcolors==24.11.1 201 | webencodings==0.5.1 202 | websocket-client==1.8.0 203 | widgetsnbextension==4.0.13 204 | wikipedia==1.4.0 205 | wrapt==1.17.0 206 | wsproto==1.2.0 207 | yarl==1.18.3 208 | zipp==3.21.0 209 | aiofiles 23.2.1 210 | aiohappyeyeballs 2.4.4 211 | aiohttp 3.11.11 212 | aiosignal 1.3.2 213 | annotated-types 0.7.0 214 | anyio 4.8.0 215 | asyncer 0.0.7 216 | attrs 25.1.0 217 | azure-core 1.32.0 218 | azure-identity 1.19.0 219 | bidict 0.23.1 220 | certifi 2025.1.31 221 | cffi 1.17.1 222 | chainlit 2.1.2 223 | charset-normalizer 3.4.1 224 | chevron 0.14.0 225 | click 8.1.8 226 | colorama 0.4.6 227 | cryptography 44.0.0 228 | dataclasses-json 0.6.7 229 | Deprecated 1.2.18 230 | distro 1.9.0 231 | fastapi 0.115.8 232 | filetype 1.2.0 233 | frozenlist 1.5.0 234 | googleapis-common-protos 1.66.0 235 | greenlet 3.1.1 236 | grpcio 1.70.0 237 | h11 0.14.0 238 | h2 4.2.0 239 | hpack 4.1.0 240 | httpcore 1.0.7 241 | httpx 0.28.1 242 | httpx-sse 0.4.0 243 | hyperframe 6.1.0 244 | idna 3.10 245 | importlib_metadata 8.5.0 246 | jiter 0.8.2 247 | jsonpatch 1.33 248 | jsonpointer 3.0.0 249 | langchain 0.3.17 250 | langchain-community 0.3.16 251 | langchain-core 0.3.33 252 | langchain-openai 0.3.3 253 | langchain-text-splitters 0.3.5 254 | langgraph 0.2.69 255 | langgraph-checkpoint 2.0.10 256 | langgraph-sdk 0.1.51 257 | langsmith 0.3.6 258 | Lazify 0.4.0 259 | literalai 0.1.103 260 | marshmallow 3.26.1 261 | microsoft-kiota-abstractions 1.9.1 262 | microsoft-kiota-authentication-azure 1.9.1 263 | microsoft-kiota-http 1.9.1 264 | microsoft-kiota-serialization-form 1.9.1 265 | microsoft-kiota-serialization-json 1.9.1 266 | microsoft-kiota-serialization-multipart 1.9.1 267 | microsoft-kiota-serialization-text 1.9.1 268 | msal 1.31.1 269 | msal-extensions 1.2.0 270 | msgpack 1.1.0 271 | msgraph-core 1.3.0 272 | msgraph-sdk 1.18.0 273 | multidict 6.1.0 274 | mypy-extensions 1.0.0 275 | nest-asyncio 1.6.0 276 | numpy 2.2.2 277 | openai 1.61.1 278 | opentelemetry-api 1.29.0 279 | opentelemetry-exporter-otlp 1.29.0 280 | opentelemetry-exporter-otlp-proto-common 1.29.0 281 | opentelemetry-exporter-otlp-proto-grpc 1.29.0 282 | opentelemetry-exporter-otlp-proto-http 1.29.0 283 | opentelemetry-instrumentation 0.50b0 284 | opentelemetry-proto 1.29.0 285 | opentelemetry-sdk 1.29.0 286 | opentelemetry-semantic-conventions 0.50b0 287 | orjson 3.10.15 288 | packaging 24.2 289 | pip 25.0 290 | portalocker 2.10.1 291 | propcache 0.2.1 292 | protobuf 5.29.3 293 | pycparser 2.22 294 | pydantic 2.10.6 295 | pydantic_core 2.27.2 296 | pydantic-settings 2.7.1 297 | PyJWT 1.7.0 298 | python-dotenv 1.0.1 299 | python-engineio 4.11.2 300 | python-multipart 0.0.18 301 | python-socketio 5.12.1 302 | pywin32 308 303 | PyYAML 6.0.2 304 | regex 2024.11.6 305 | requests 2.32.3 306 | requests-toolbelt 1.0.0 307 | simple-websocket 1.1.0 308 | six 1.17.0 309 | sniffio 1.3.1 310 | SQLAlchemy 2.0.37 311 | starlette 0.41.3 312 | std-uritemplate 2.0.1 313 | syncer 2.0.3 314 | tenacity 9.0.0 315 | tiktoken 0.8.0 316 | tomli 2.2.1 317 | tqdm 4.67.1 318 | typing_extensions 4.12.2 319 | typing-inspect 0.9.0 320 | uptrace 1.29.0 321 | urllib3 2.3.0 322 | uvicorn 0.34.0 323 | watchfiles 0.20.0 324 | wrapt 1.17.2 325 | wsproto 1.2.0 326 | yarl 1.18.3 327 | zipp 3.21.0 328 | zstandard 0.23.0 --------------------------------------------------------------------------------