camel icon indicating copy to clipboard operation
camel copied to clipboard

Feat/outlook toolkit

Open Tanuj-Taneja1 opened this issue 1 month ago ‱ 1 comments

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

  1. 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
  2. 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-number in the PR description (required)
  • [ ] I have checked if any dependencies need to be added or updated in pyproject.toml and uv 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!

Tanuj-Taneja1 avatar Nov 14 '25 18:11 Tanuj-Taneja1

[!IMPORTANT]

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in 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.

❀ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Nov 14 '25 18:11 coderabbitai[bot]

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.

Tanuj-Taneja1 avatar Nov 17 '25 06:11 Tanuj-Taneja1

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

Tanuj-Taneja1 avatar Nov 17 '25 14:11 Tanuj-Taneja1

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

Tanuj-Taneja1 avatar Nov 17 '25 14:11 Tanuj-Taneja1

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)

Tanuj-Taneja1 avatar Nov 18 '25 06:11 Tanuj-Taneja1

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!

waleedalzarooni avatar Nov 19 '25 13:11 waleedalzarooni

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

Tanuj-Taneja1 avatar Nov 19 '25 13:11 Tanuj-Taneja1

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

Tanuj-Taneja1 avatar Nov 20 '25 05:11 Tanuj-Taneja1

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

Tanuj-Taneja1 avatar Nov 21 '25 09:11 Tanuj-Taneja1

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!

waleedalzarooni avatar Nov 21 '25 09:11 waleedalzarooni

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)

waleedalzarooni avatar Nov 25 '25 13:11 waleedalzarooni

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)

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

Tanuj-Taneja1 avatar Nov 25 '25 15:11 Tanuj-Taneja1

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)

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!

waleedalzarooni avatar Nov 28 '25 12:11 waleedalzarooni

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!

waleedalzarooni avatar Dec 03 '25 15:12 waleedalzarooni

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.

Tanuj-Taneja1 avatar Dec 03 '25 16:12 Tanuj-Taneja1

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

waleedalzarooni avatar Dec 03 '25 17:12 waleedalzarooni

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.

fengju0213 avatar Dec 17 '25 04:12 fengju0213

hi @MuggleJinx if you have timeplease take a look at this pr again

fengju0213 avatar Dec 17 '25 04:12 fengju0213

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?

Tanuj-Taneja1 avatar Dec 17 '25 14:12 Tanuj-Taneja1

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

Tanuj-Taneja1 avatar Dec 17 '25 15:12 Tanuj-Taneja1

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.

fengju0213 avatar Dec 18 '25 03:12 fengju0213

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

Tanuj-Taneja1 avatar Dec 18 '25 11:12 Tanuj-Taneja1

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?

fengju0213 avatar Dec 19 '25 04:12 fengju0213

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

Tanuj-Taneja1 avatar Dec 19 '25 05:12 Tanuj-Taneja1

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

fengju0213 avatar Dec 19 '25 05:12 fengju0213