-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat: gmail_toolkit integration fixes issue #3189 #3205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ✨ Finishing touches🧪 Generate unit tests (beta)
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 |
|
I still need to include the gmail keys to env variables file |
|
@Wendong-Fan, should be ready for review only a couple of things to note
|
|
@Wendong-Fan I have integrated a clean OAUTH authentication mechanism and made some fixes according to your IMAP review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @waleedalzarooni ! left some comments below
examples/toolkits/gmail_toolkit.py
Outdated
| # Add camel to path - find the camel package directory | ||
| current_file = Path(__file__).resolve() | ||
| camel_root = current_file.parent.parent.parent | ||
| sys.path.insert(0, str(camel_root)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why we need this
examples/toolkits/gmail_toolkit.py
Outdated
| from camel.agents import ChatAgent # noqa: E402 | ||
| from camel.models import ModelFactory # noqa: E402 | ||
| from camel.toolkits import GmailToolkit # noqa: E402 | ||
| from camel.types import ModelPlatformType # noqa: E402 | ||
| from camel.types.enums import ModelType # noqa: E402 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why need # noqa: E402
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested the functionality it works, but seems now we require both GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and OAuth, do all those necessary?
| return header['value'] | ||
| return "" | ||
|
|
||
| def _extract_message_body(self, message: Dict[str, Any]) -> str: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems this function cannot handle nested multipart message structures, only single-level multipart messages?
| "googlemaps>=4.10.0,<5", | ||
| "requests_oauthlib>=1.3.1,<2", | ||
| "google-api-python-client==2.166.0", | ||
| "google-auth>=2.0.0,<3.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we also need to add this dependency to [all]
camel/toolkits/gmail_toolkit.py
Outdated
| if TYPE_CHECKING: | ||
| from googleapiclient.discovery import Resource | ||
| else: | ||
| Resource = Any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where did Resource used?
camel/toolkits/gmail_toolkit.py
Outdated
| bcc (Optional[Union[str, List[str]]]): BCC recipient email | ||
| address(es). | ||
| attachments (Optional[List[str]]): List of file paths to attach. | ||
| is_html (bool): Whether the body is HTML format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we add more description for this argument? how and when would this be used, same for other functions
camel/toolkits/gmail_toolkit.py
Outdated
| query (str): Gmail search query string. | ||
| max_results (int): Maximum number of emails to fetch. | ||
| include_spam_trash (bool): Whether to include spam and trash. | ||
| label_ids (Optional[List[str]]): List of label IDs to filter by. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what kind of label would be used here? I think we need more description to make it clear
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
|
@Wendong-Fan, new commit addressing review comments. As discussed I will open a new PR for the Eigent Authentication integration Sorry about the messy commit history, I've tried multiple approaches to prevent this but neither are working. When I'm ready to push and I get a warning that my feature branch is diverging from master I have tried git merge and rebase but both cause this issue. I will try and find a solution as I'm not quite sure what I'm doing wrong |
f82aa26 to
a6444dc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current OAuth2 requires
- GOOGLE_CLIENT_ID
- GOOGLE_CLIENT_SECRET
We shoud mention them in the docs
| os.unlink(temp_file_path) | ||
| except Exception as e: | ||
| logger.warning( | ||
| f"Failed to delete temp file {temp_file}: {e}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"temp_file" is possibly unbound. should be temp_file_path I guess.
| if text: | ||
| text_parts.append(text) | ||
|
|
||
| # Lines 1458-1462 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we removing .env.example ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing: The current functions — fetch_emails, list_threads, list_drafts, and get_contacts — only return next_page_token. It is recommended to also accept a page_token parameter as input so that the upper layers can request subsequent pages.
Location: At the points where next_page_token is returned, such as in camel/toolkits/gmail_toolkit.py:521, 756, 796, 1043.
| logger = get_logger(__name__) | ||
|
|
||
| SCOPES = [ | ||
| 'https://mail.google.com/', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove the first one since it's too broad. might not be necessary.
| logger.error("Failed to send email: %s", e) | ||
| return {"error": f"Failed to send email: {e!s}"} | ||
|
|
||
| def reply_to_email( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reply_to_email function does not set the threadId and does not include the In-Reply-To or References headers. This may cause Gmail to create a new thread instead of appending the message to the existing conversation.
Recommendation: When sending a reply, include the original email’s threadId in the request body (e.g., {'raw': ..., 'threadId': ...}), and update _create_message to optionally set the In-Reply-To and References headers before returning.
| logger.error("Failed to reply to email: %s", e) | ||
| return {"error": f"Failed to reply to email: {e!s}"} | ||
|
|
||
| def forward_email( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The forward_email function’s documentation states that “inline images are not included”, but the implementation does not filter by is_inline. As a result, inline images (such as logos or embedded images within the email body) are also treated as attachments when forwarding.
Recommendation: Filter the return value of _extract_attachments to include only attachments where not att['is_inline'].
| creds = None | ||
|
|
||
| # COMPONENT 2: Refresh if expired | ||
| if creds and creds.expired and creds.refresh_token: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OAuth Token Refresh Not Persisted
After refreshing, the function directly returns creds without writing the updated token back to ~/.camel/gmail_token.json.
Recommendation: After a successful refresh, persist the latest token to disk, consistent with the behavior used during the initial authorization.
| env_file = Path(__file__).parent.parent.parent / '.env' | ||
| load_dotenv(env_file) | ||
|
|
||
| client_id = os.environ.get('GOOGLE_CLIENT_ID') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if None, we should generate error
| 'pageSize': max_results, | ||
| } | ||
|
|
||
| if query: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The people().connections().list method does not support query-based filtering — any provided query parameter is ignored. However, the function’s docstring and signature currently imply that search functionality is supported.
see https://developers.google.com/people/api/rest/v1/people.connections/list
| r"""Delete a Gmail label. | ||
| Args: | ||
| label_id (str): List of label IDs to filter emails by. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not List of label IDs..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @waleedalzarooni for the contribution! I left some comments!
Sorry about the mess. I think I mis-click a few times of submitting review, so now the overall comments look a bit messy 😅
Description
Integrated Gmail_toolkit with with requested tools
Checklist
Go over all the following points, and put an
xin all the boxes that apply.Fixes #issue-numberin the PR description (required)pyproject.tomlanduv lockIf you are unsure about any of these, don't hesitate to ask. We are here to help!