Feat/outlook toolkit
Description
#3201 Hi @Wendong-Fan
I am still working on this issue but since the size of this pr is already big I am creating a draft pr. I have so far added these actions
- send_email
- create_draft_email
- send_draft_email
- delete_email
- move_message_to_folder
- get_attachments
- get_message
- list_messages
and reply and update message actions are still pending
Also I wanted to ask some questions
- I think we can make seperate files for each set of actions like mail, calender and so on. So just wanted a confirmation if it is all right. If yes I will rename the current file and classname
- The reply api of microsoft doesnt allow attachments so I was thinking we can add draft reply and add attachment to it, is this ok,
Also feel free to let me know if there are any suggestions to improve the code. I havent written tests so far as most of the code was related to api calls I was kind of manually testing everything, will be adding those soon.
In the next few commits I will add some test and add remaining actions. Also I previously hardcode message content type to text so will be fixing that to allow html content when creating and sending mail
Reference: msgraph msgraph (some docs like send mail are in users section for some reason) authorizationcodecredential for auth
Checklist
Go over all the following points, and put an x in all the boxes that apply.
- [ ] I have read the CONTRIBUTION guide (required)
- [ ] I have linked this PR to an issue using the Development section on the right sidebar or by adding
Fixes #issue-numberin the PR description (required) - [ ] I have checked if any dependencies need to be added or updated in
pyproject.tomlanduv lock - [ ] I have updated the tests accordingly (required for a bug fix or a new feature)
- [ ] I have updated the documentation if needed:
- [ ] I have added examples if this is a new feature
If you are unsure about any of these, don't hesitate to ask. We are here to help!
[!IMPORTANT]
Review skipped
Auto reviews are disabled on this repository.
Please check the settings in the CodeRabbit UI or the
.coderabbit.yamlfile in this repository. To trigger a single review, invoke the@coderabbitai reviewcommand.You can disable this status message by setting the
reviews.review_statustofalsein the CodeRabbit configuration file.
âš Finishing touches
đ§Ș Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
- [ ] Commit unit tests in branch
feat/outlook-toolkit
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
Hi @Wendong-Fan Sorry to bother you but i was getting some error during setup env in the above tests Is this related to me pushing uv.lock or in general ( I didnt see anyone else getting this error)
Run source .venv/bin/activate
Ă No solution found when resolving dependencies:
â°ââ¶ Because fish-audio-sdk==2024.12.5 was yanked (reason: Break Change) and
only the following versions of fish-audio-sdk are available:
fish-audio-sdk<=2024.12.5
fish-audio-sdk>2025
we can conclude that fish-audio-sdk>=2024.12.5,<2025 cannot be used.
And because camel-ai[all]==0.2.79 depends on
fish-audio-sdk>=2024.12.5,<2025, we can conclude that
camel-ai[all]==0.2.79 cannot be used.
And because only camel-ai[all]==0.2.79 is available and you require
camel-ai[all], we can conclude that your requirements are unsatisfiable.
Hi @Wendong-Fan Sorry to bother you but i was getting some error during setup env in the above tests Is this related to me pushing uv.lock or in general ( I didnt see anyone else getting this error)
Run source .venv/bin/activate Ă No solution found when resolving dependencies: â°ââ¶ Because fish-audio-sdk==2024.12.5 was yanked (reason: Break Change) and only the following versions of fish-audio-sdk are available: fish-audio-sdk<=2024.12.5 fish-audio-sdk>2025 we can conclude that fish-audio-sdk>=2024.12.5,<2025 cannot be used. And because camel-ai[all]==0.2.79 depends on fish-audio-sdk>=2024.12.5,<2025, we can conclude that camel-ai[all]==0.2.79 cannot be used. And because only camel-ai[all]==0.2.79 is available and you require camel-ai[all], we can conclude that your requirements are unsatisfiable.
Regarding this issue, I think this is unrelated to my pr and the reason I am getting this is because i pushed uv lock file due to which we tied creating new environment instead of one in cache
I have added the remaining tests and function For now I have kept the reply_to_email and update_draft_message simple without attachment handling since their api dont support it directly. I will be adding attachment post method in a seperate pr later and will update this code then
Also I choose update_draft_message instead of update_message as updating sent message only changes data on our side like changing cc recipients wont send them mail again, so it wouldnt be very helpful for a llm toolkit in my opinion or even in general other than faking a sent mail.
I have completed the mail part of actions for now but feel free to let me know if there are any suggestions or change either regarding this pr or in general that might help me.
Thanks Will be working on calender part of toolkit in few days
Also to make reviewers life easier Here is how you setup things at azure
1 Go to https://portal.azure.com/ 2 Search for microsoft Entra ID and open it 3 Click on add button in horizontal menu and click app registeration 4 add name, supported account type and redirect uri (should be set to http://localhost:1000) and platform as web - this page should have client id 5 On the next page there should be a link for 'Add a certificate or secret' click on it then add a new secret , then copy the Value (Client secret) dont use Secret ID
Thats it Now you just have to add the user that you want to sign in as Go back to default directory overview page and add the user of your choice. For personal account select add external account
Now just add these creds to env (for personal account dont add tenant id or if you want add "common" ) and the code should work
Later we should also add all this to example file ( I didnt create it since i dont have open ai credits)
Hi @Wendong-Fan Sorry to bother you but i was getting some error during setup env in the above tests Is this related to me pushing uv.lock or in general ( I didnt see anyone else getting this error)
Run source .venv/bin/activate Ă No solution found when resolving dependencies: â°ââ¶ Because fish-audio-sdk==2024.12.5 was yanked (reason: Break Change) and only the following versions of fish-audio-sdk are available: fish-audio-sdk<=2024.12.5 fish-audio-sdk>2025 we can conclude that fish-audio-sdk>=2024.12.5,<2025 cannot be used. And because camel-ai[all]==0.2.79 depends on fish-audio-sdk>=2024.12.5,<2025, we can conclude that camel-ai[all]==0.2.79 cannot be used. And because only camel-ai[all]==0.2.79 is available and you require camel-ai[all], we can conclude that your requirements are unsatisfiable.Regarding this issue, I think this is unrelated to my pr and the reason I am getting this is because i pushed uv lock file due to which we tied creating new environment instead of one in cache
Hey @Tanuj-Taneja1, I will have a look at this issue and see why this may be happening, also moving forward feel free to message me with any concerns or issues you may face!
Hi @Wendong-Fan Sorry to bother you but i was getting some error during setup env in the above tests Is this related to me pushing uv.lock or in general ( I didnt see anyone else getting this error)
Run source .venv/bin/activate Ă No solution found when resolving dependencies: â°ââ¶ Because fish-audio-sdk==2024.12.5 was yanked (reason: Break Change) and only the following versions of fish-audio-sdk are available: fish-audio-sdk<=2024.12.5 fish-audio-sdk>2025 we can conclude that fish-audio-sdk>=2024.12.5,<2025 cannot be used. And because camel-ai[all]==0.2.79 depends on fish-audio-sdk>=2024.12.5,<2025, we can conclude that camel-ai[all]==0.2.79 cannot be used. And because only camel-ai[all]==0.2.79 is available and you require camel-ai[all], we can conclude that your requirements are unsatisfiable.Regarding this issue, I think this is unrelated to my pr and the reason I am getting this is because i pushed uv lock file due to which we tied creating new environment instead of one in cache
Hey @Tanuj-Taneja1, I will have a look at this issue and see why this may be happening, also moving forward feel free to message me with any concerns or issues you may face!
Hi @waleedalzarooni, I think the issue has been fixed in pr #3427 I think that is the reason my branch has conflict in uv lock file, I will fix it in some time
Hi @waleedalzarooni, I think the issue has been fixed in pr #3427 I think that is the reason my branch has conflict in uv lock file, I will fix it in some time
I have resolved the merge conflict and now all the tests seems to be running fine But I think there are some mypy issues in my recent commits, I will fix those
Also I face following issue with mypy, if there is a solution to these do let me know I always get pre-commit mypy errors (unrelated to my changes) while commiting so I just have to skip them. The mypy -pre commit test take way too long in my system, my laptop is kind of slow but i think it takes around 20-30 minutes for pre-commit tests if i dont skip mypy
Hi @waleedalzarooni , I will start working on calender actions soon and was thinking about keeping it in seperate file, will that be alright. Also if you need any help to review this pr do let me know
Hey @Tanuj-Taneja1,
No problem go ahead with the separate calendar functionality, thanks again for your effort on the PR. I will be passing it to reviewers promptly so we can put your hard work to use!
Hey @Tanuj-Taneja1,
I am currently working on reviewing your implementation, one thing to note for toolkits is that we typically have example files for each toolkit to demonstrate usage, would you mind creating one for the Microsoft toolkit (use the gmail_toolkit.py for reference)
Hey @Tanuj-Taneja1,
I am currently working on reviewing your implementation, one thing to note for toolkits is that we typically have example files for each toolkit to demonstrate usage, would you mind creating one for the Microsoft toolkit (use the
gmail_toolkit.pyfor reference)
Hi @waleedalzarooni I think I mentioned in a earlier conversation, but I dont currently have any openai credits, so wont be able to create a example file with default model.
I think I can give you a notebook file which runs all the functions and setup instructions , would that be helpful?
If yes heres the link: https://colab.research.google.com/drive/1jgJVfljz2HfdmgcmDZclhfdybCYNdi3u?usp=sharing It is mostly ai generated but everything works, I had to hide the cell ouputs though since they contain important message id and stuff. If it doesnt work for you feel free to let me know
Hey @Tanuj-Taneja1, I am currently working on reviewing your implementation, one thing to note for toolkits is that we typically have example files for each toolkit to demonstrate usage, would you mind creating one for the Microsoft toolkit (use the
gmail_toolkit.pyfor reference)Hi @waleedalzarooni I think I mentioned in a earlier conversation, but I dont currently have any openai credits, so wont be able to create a example file with default model.
I think I can give you a notebook file which runs all the functions and setup instructions , would that be helpful?
If yes heres the link: https://colab.research.google.com/drive/1jgJVfljz2HfdmgcmDZclhfdybCYNdi3u?usp=sharing It is mostly ai generated but everything works, I had to hide the cell ouputs though since they contain important message id and stuff. If it doesnt work for you feel free to let me know
No problem, I'll work on that thanks for the heads up and I'll make sure to let you know if I have any questions about the colab file!
Hey @Tanuj-Taneja1,
Thank you so much for your patience, I have added an enhance PR (https://github.com/camel-ai/camel/pull/3492) that fixes some of the async functionality as well as the way the port is assigned, since you must set a fixed port for use in the OAUTH process I allow the user to set the port in the env variable, would be great if you could review this when possible so we can merge this feature!
Hey @Tanuj-Taneja1,
Thank you so much for your patience, I have added an enhance PR (#3492) that fixes some of the async functionality as well as the way the port is assigned, since you must set a fixed port for use in the OAUTH process I allow the user to set the port in the env variable, would be great if you could review this when possible so we can merge this feature!
Hi @waleedalzarooni I think we dont need to specify the port if we set redirect uri to "http://localhost/" in azure.
Hey @Tanuj-Taneja1, Thank you so much for your patience, I have added an enhance PR (#3492) that fixes some of the async functionality as well as the way the port is assigned, since you must set a fixed port for use in the OAUTH process I allow the user to set the port in the env variable, would be great if you could review this when possible so we can merge this feature!
Hi @waleedalzarooni I think we dont need to specify the port if we set redirect uri to "http://localhost/" in azure.
Yep, you're totally right I will reset to the original conventions in the enhanced PR
everything looks goodïŒ some minor issues in this PR are around auth lifecycle and runtime robustness:
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
- Scopes were provided in short form (e.g., Mail.Send), which can be unstable across SDK/adapters and lead to token/scope mismatch and intermittent 401s.
- The custom credential performed token refresh via synchronous HTTP, which can block the asyncio event loop in async Graph usage and cause latency spikes/timeouts.
- Tests were environment-sensitive (localhost port bind) and could fail in restricted CI/sandbox setups.
created an enhance pr, https://github.com/camel-ai/camel/pull/3578 feel free to check it! @Tanuj-Taneja1 Changes i applied: implemented auth-code token exchange and persisted refresh_token to the configured file with a regression test; normalized scopes to Graph fully-qualified form while keeping backward compatibility; migrated the custom credential to an async implementation to avoid blocking; and adjusted tests to avoid relying on local port binding.
hi @MuggleJinx if you have timeïŒplease take a look at this pr againïŒ
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Hi figured out the reason of this and mentioned the reason in #3578 For the solution part we can set a default file path for refresh token and that should solve the issue, we can also remove the authorizationcredentialflow logic as it uses the exact logic you added of using getting refresh token from authentication code and use it to get tokens, it just saved the tokens in persistence cache instead of a common file which can be reused after first init
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Yes, thatâs expected. Itâs just that the previous persistence logic didnât take effect. Now it can be saved properly, but to skip verification under the current implementation, a refresh token path needs to be provided. We could also change it to be passed automatically.
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Yes, thatâs expected. Itâs just that the previous persistence logic didnât take effect. Now it can be saved properly, but to skip verification under the current implementation, a refresh token path needs to be provided. We could also change it to be passed automatically.
Actually previously even in browser auth persistance was there just not in refresh_token_file_path but using TokenCachePersistenceOptions. Browser auth is when either user didnt provide refresh_token_file_path or when authentication using it fails.
For Browser auth TokenCachePersistenceOptions stored refresh token and access token internally.
Your current implentation is exactly what AuthorizationCodeCredential and TokenCachePersistenceOptions did internally.
Feel free to refer this : https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/TokenCache.md
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Yes, thatâs expected. Itâs just that the previous persistence logic didnât take effect. Now it can be saved properly, but to skip verification under the current implementation, a refresh token path needs to be provided. We could also change it to be passed automatically.
Actually previously even in browser auth persistance was there just not in refresh_token_file_path but using TokenCachePersistenceOptions. Browser auth is when either user didnt provide refresh_token_file_path or when authentication using it fails.
For Browser auth TokenCachePersistenceOptions stored refresh token and access token internally.
Your current implentation is exactly what AuthorizationCodeCredential and TokenCachePersistenceOptions did internally.
Feel free to refer this : https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/TokenCache.md
Thanks for the clear explanation. I also reviewed the Azure Identity docs you linked. Based on that, to achieve âreuse credentials without repeated browser prompts,â it seems the official way is to enable persistent caching via TokenCachePersistenceOptions. Are you suggesting we switch to using the official TokenCachePersistenceOptions for this?
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Yes, thatâs expected. Itâs just that the previous persistence logic didnât take effect. Now it can be saved properly, but to skip verification under the current implementation, a refresh token path needs to be provided. We could also change it to be passed automatically.
Actually previously even in browser auth persistance was there just not in refresh_token_file_path but using TokenCachePersistenceOptions. Browser auth is when either user didnt provide refresh_token_file_path or when authentication using it fails. For Browser auth TokenCachePersistenceOptions stored refresh token and access token internally. Your current implentation is exactly what AuthorizationCodeCredential and TokenCachePersistenceOptions did internally. Feel free to refer this : https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/TokenCache.md
Thanks for the clear explanation. I also reviewed the Azure Identity docs you linked. Based on that, to achieve âreuse credentials without repeated browser prompts,â it seems the official way is to enable persistent caching via TokenCachePersistenceOptions. Are you suggesting we switch to using the official TokenCachePersistenceOptions for this?
Yes we can just revert to our original logic, it used TokenCachePersistenceOptions. Either way the current implementation is also correct though involves more loc. We can either fix it here or later since I was planning on removing auth logic from this code based on our discussion in #3553
Hi @fengju0213
- In the browser OAuth fallback, the obtained refresh_token is not persisted to refresh_token_file_path, so the documented âreuse credentials without repeated browser promptsâ doesnât work and users get forced through browser login on every init.
I think that is still the case, I am still getting browser login with each init. Can you confirm that from your side?
Yes, thatâs expected. Itâs just that the previous persistence logic didnât take effect. Now it can be saved properly, but to skip verification under the current implementation, a refresh token path needs to be provided. We could also change it to be passed automatically.
Actually previously even in browser auth persistance was there just not in refresh_token_file_path but using TokenCachePersistenceOptions. Browser auth is when either user didnt provide refresh_token_file_path or when authentication using it fails. For Browser auth TokenCachePersistenceOptions stored refresh token and access token internally. Your current implentation is exactly what AuthorizationCodeCredential and TokenCachePersistenceOptions did internally. Feel free to refer this : https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/TokenCache.md
Thanks for the clear explanation. I also reviewed the Azure Identity docs you linked. Based on that, to achieve âreuse credentials without repeated browser prompts,â it seems the official way is to enable persistent caching via TokenCachePersistenceOptions. Are you suggesting we switch to using the official TokenCachePersistenceOptions for this?
Yes we can just revert to our original logic, it used TokenCachePersistenceOptions. Either way the current implementation is also correct though involves more loc. We can either fix it here or later since I was planning on removing auth logic from this code based on our discussion in #3553
okayïŒwe can merge it firstïŒthen we can improve the implement