feat: Add Composio Outlook component (#7987)

* feat: add Composio Outlook component

* feat: add Composio Outlook component

* feat: add outlook test file

* chore: remove file

* fix: format

* fix: add result_field to improve toolcall response

* Update src/frontend/src/icons/outlook/outlook.jsx

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Abhishek Patil 2025-06-03 21:58:24 +05:30 committed by GitHub
commit f835a6b4dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 990 additions and 0 deletions

View file

@ -2,6 +2,7 @@ from .composio_api import ComposioAPIComponent
from .github_composio import ComposioGitHubAPIComponent
from .gmail_composio import ComposioGmailAPIComponent
from .googlecalendar_composio import ComposioGoogleCalendarAPIComponent
from .outlook_composio import ComposioOutlookAPIComponent
from .slack_composio import ComposioSlackAPIComponent
__all__ = [
@ -9,5 +10,6 @@ __all__ = [
"ComposioGitHubAPIComponent",
"ComposioGmailAPIComponent",
"ComposioGoogleCalendarAPIComponent",
"ComposioOutlookAPIComponent",
"ComposioSlackAPIComponent",
]

View file

@ -0,0 +1,765 @@
import json
from typing import Any
from composio import Action
from langflow.base.composio.composio_base import ComposioBaseComponent
from langflow.inputs import BoolInput, FileInput, IntInput, MessageTextInput
from langflow.logging import logger
class ComposioOutlookAPIComponent(ComposioBaseComponent):
display_name: str = "Outlook"
description: str = "Outlook API"
icon = "Outlook"
documentation: str = "https://docs.composio.dev"
app_name = "outlook"
_actions_data: dict = {
"OUTLOOK_OUTLOOK_REPLY_EMAIL": {
"display_name": "Reply To Email",
"action_fields": [
"OUTLOOK_OUTLOOK_REPLY_EMAIL_user_id",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_message_id",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_comment",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_cc_emails",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_bcc_emails",
],
"get_result_field": False,
},
"OUTLOOK_OUTLOOK_GET_PROFILE": {
"display_name": "Get Profile",
"action_fields": ["OUTLOOK_OUTLOOK_GET_PROFILE_user_id"],
"get_result_field": True,
"result_field": "response_data",
},
"OUTLOOK_OUTLOOK_SEND_EMAIL": {
"display_name": "Send Email",
"action_fields": [
"OUTLOOK_OUTLOOK_SEND_EMAIL_user_id",
"OUTLOOK_OUTLOOK_SEND_EMAIL_subject",
"OUTLOOK_OUTLOOK_SEND_EMAIL_body",
"OUTLOOK_OUTLOOK_SEND_EMAIL_to_email",
"OUTLOOK_OUTLOOK_SEND_EMAIL_to_name",
"OUTLOOK_OUTLOOK_SEND_EMAIL_cc_emails",
"OUTLOOK_OUTLOOK_SEND_EMAIL_bcc_emails",
"OUTLOOK_OUTLOOK_SEND_EMAIL_is_html",
"OUTLOOK_OUTLOOK_SEND_EMAIL_save_to_sent_items",
"OUTLOOK_OUTLOOK_SEND_EMAIL_attachment",
],
"get_result_field": False,
},
"OUTLOOK_OUTLOOK_LIST_MESSAGES": {
"display_name": "List Messages",
"action_fields": [
"OUTLOOK_OUTLOOK_LIST_MESSAGES_user_id",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_folder",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_top",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_skip",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_is_read",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_importance",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_gt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_startswith",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_endswith",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_contains",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_ge",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_lt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_le",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_from_address",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_has_attachments",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_body_preview_contains",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_gt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_lt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_categories",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_select",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_orderby",
],
"get_result_field": True,
"result_field": "value",
},
"OUTLOOK_OUTLOOK_LIST_EVENTS": {
"display_name": "List Events",
"action_fields": [
"OUTLOOK_OUTLOOK_LIST_EVENTS_user_id",
"OUTLOOK_OUTLOOK_LIST_EVENTS_top",
"OUTLOOK_OUTLOOK_LIST_EVENTS_skip",
"OUTLOOK_OUTLOOK_LIST_EVENTS_filter",
"OUTLOOK_OUTLOOK_LIST_EVENTS_select",
"OUTLOOK_OUTLOOK_LIST_EVENTS_orderby",
"OUTLOOK_OUTLOOK_LIST_EVENTS_timezone",
],
"get_result_field": True,
"result_field": "value",
},
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT": {
"display_name": "Create Calendar Event",
"action_fields": [
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_user_id",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_subject",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_body",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_html",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_start_datetime",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_end_datetime",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_time_zone",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_online_meeting",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_online_meeting_provider",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_attendees_info",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_location",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_show_as",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_categories",
],
"get_result_field": True,
"result_field": "response_data",
},
"OUTLOOK_OUTLOOK_GET_EVENT": {
"display_name": "Get Calendar Event",
"action_fields": ["OUTLOOK_OUTLOOK_GET_EVENT_user_id", "OUTLOOK_OUTLOOK_GET_EVENT_event_id"],
"get_result_field": True,
"result_field": "response_data",
},
"OUTLOOK_OUTLOOK_CREATE_DRAFT": {
"display_name": "Create Email Draft",
"action_fields": [
"OUTLOOK_OUTLOOK_CREATE_DRAFT_subject",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_body",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_to_recipients",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_cc_recipients",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_bcc_recipients",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_is_html",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_attachment",
],
"get_result_field": True,
"result_field": "response_data",
},
}
_all_fields = {field for action_data in _actions_data.values() for field in action_data["action_fields"]}
_bool_variables = {
"OUTLOOK_OUTLOOK_SEND_EMAIL_is_html",
"OUTLOOK_OUTLOOK_SEND_EMAIL_save_to_sent_items",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_is_html",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_html",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_online_meeting",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_is_read",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_has_attachments",
}
_list_variables = {
"OUTLOOK_OUTLOOK_LIST_EVENTS_select",
"OUTLOOK_OUTLOOK_LIST_EVENTS_orderby",
"OUTLOOK_OUTLOOK_SEND_EMAIL_cc_emails",
"OUTLOOK_OUTLOOK_SEND_EMAIL_bcc_emails",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_to_recipients",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_cc_recipients",
"OUTLOOK_OUTLOOK_CREATE_DRAFT_bcc_recipients",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_cc_emails",
"OUTLOOK_OUTLOOK_REPLY_EMAIL_bcc_emails",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_attendees_info",
"OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_categories",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_categories",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_select",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_orderby",
}
inputs = [
*ComposioBaseComponent._base_inputs,
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_user_id",
display_name="User Id",
info="The target user's email address or 'me' for the authenticated user.",
show=False,
value="me",
advanced=True,
),
IntInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_top",
display_name="Max Results",
info="The maximum number of events to return per request.",
show=False,
value=10,
),
IntInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_skip",
display_name="Skip",
info="The number of events to skip before starting to collect results.",
show=False,
value=0,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_filter",
display_name="Filter",
info="OData query string to filter results. Example: start/dateTime ge '2024-01-01T00:00:00'",
show=False,
value="",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_select",
display_name="Select",
info="List of properties to include in the response comma separated.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_orderby",
display_name="Orderby",
info="Properties to sort results by comma separated.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_EVENTS_timezone",
display_name="Timezone",
info="The timezone for event start and end times in the response.",
show=False,
value="UTC",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_user_id",
display_name="User Id",
info="The user's email address or 'me' for the authenticated user.",
show=False,
value="me",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_subject",
display_name="Subject",
info="Subject of the email",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_body",
display_name="Body",
info="Body content of the email. Can be plain text or HTML based on is_html flag.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_to_email",
display_name="Recipient Email",
info="Recipient email address",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_to_name",
display_name="To Name",
info="Recipient display name",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_cc_emails",
display_name="CC",
info="List of CC recipient email addresses comma separated",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_bcc_emails",
display_name="BCC",
info="List of BCC recipient email addresses comma separated",
show=False,
advanced=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_is_html",
display_name="Is HTML",
info="Set to True if the body content is HTML formatted",
show=False,
value=False,
advanced=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_save_to_sent_items",
display_name="Save To Sent Items",
info="Whether to save the sent email to Sent Items folder.",
show=False,
value=True,
advanced=True,
),
FileInput(
name="OUTLOOK_OUTLOOK_SEND_EMAIL_attachment",
display_name="Attachment",
file_types=[
"csv",
"txt",
"doc",
"docx",
"xls",
"xlsx",
"pdf",
"png",
"jpg",
"jpeg",
"gif",
"zip",
"rar",
"ppt",
"pptx",
],
info="Add an attachment",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_subject",
display_name="Subject",
info="Subject of the email",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_body",
display_name="Body",
info="Body content of the email. Can be plain text or HTML based on is_html flag",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_to_recipients",
display_name="Recipient Email",
info="List of recipient email addresses comma separated",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_cc_recipients",
display_name="Cc Recipients",
info="List of CC recipient email addresses",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_bcc_recipients",
display_name="BCC",
info="List of BCC recipient email addresses comma separated",
show=False,
advanced=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_is_html",
display_name="Is HTML",
info="Set to True if the body content is HTML formatted",
show=False,
value=False,
advanced=True,
),
FileInput(
name="OUTLOOK_OUTLOOK_CREATE_DRAFT_attachment",
display_name="Attachment",
file_types=[
"csv",
"txt",
"doc",
"docx",
"xls",
"xlsx",
"pdf",
"png",
"jpg",
"jpeg",
"gif",
"zip",
"rar",
"ppt",
"pptx",
],
info="Add an attachment",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_GET_PROFILE_user_id",
display_name="User Id",
info="The user's email address or 'me' for the authenticated user.",
show=False,
value="me",
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_REPLY_EMAIL_user_id",
display_name="User Id",
info="The user's email address or 'me' for the authenticated user.",
show=False,
value="me",
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_REPLY_EMAIL_message_id",
display_name="Message Id",
info="The ID of the message to reply to. Can be obtained from OUTLOOK_LIST_MESSAGES action.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_REPLY_EMAIL_comment",
display_name="Comment",
info="Comment to include in the reply. Must be plain text.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_REPLY_EMAIL_cc_emails",
display_name="CC",
info="List of CC recipient email addresses comma separated",
show=False,
value=[],
is_list=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_REPLY_EMAIL_bcc_emails",
display_name="BCC",
info="List of BCC recipient email addresses comma separated",
show=False,
value=[],
is_list=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_user_id",
display_name="User Id",
info="The user's email address or 'me' for the authenticated user.",
show=False,
value="me",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_subject",
display_name="Subject",
info="Subject of the event. Example: 'Team Meeting'.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_body",
display_name="Body",
info="Body content of the event. Can be plain text or HTML.",
show=False,
required=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_html",
display_name="Is Html",
info="Set to True if the body content should be interpreted as HTML.",
show=False,
value=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_start_datetime",
display_name="Start Datetime",
info="Start date/time (ISO 8601). Example: '2025-01-03T10:00:00Z'.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_end_datetime",
display_name="End Datetime",
info="End date/time (ISO 8601). Example: '2025-01-03T11:00:00Z'.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_time_zone",
display_name="Time Zone",
info="Time zone (e.g., 'UTC' or 'America/Los_Angeles').",
show=False,
required=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_is_online_meeting",
display_name="Is Online Meeting",
info="Set to True to make this an online meeting and generate a Teams URL.",
show=False,
value=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_online_meeting_provider",
display_name="Online Meeting Provider",
info="The online meeting service provider. Currently only supports 'teamsForBusiness'.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_attendees_info",
display_name="Attendees",
info="A list of attendee information. Only email is required for each attendee., Example: [{ 'email': 'team@example.com', 'name': 'Team', 'type': 'required' }, { 'email': 'other@example.com', 'type': 'optional' }, { 'email': 'other2@example.com' }]", # noqa: E501
show=False,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_location",
display_name="Location",
info="Location of the event (e.g., 'Conference Room').",
show=False,
value="",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_show_as",
display_name="Show As",
info="Status of the event: 'free', 'tentative', 'busy', or 'oof'.",
show=False,
value="busy",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_CALENDAR_CREATE_EVENT_categories",
display_name="Categories",
info="List of categories associated with the event comma separated.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_GET_EVENT_user_id",
display_name="User Id",
info="The user's email address or 'me' for the authenticated user.",
show=False,
value="me",
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_GET_EVENT_event_id",
display_name="Event Id",
info="The ID of the calendar event to retrieve.",
show=False,
required=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_user_id",
display_name="User Id",
info="The target user's email address or 'me' for the authenticated user. For delegated access scenarios, this should be the email of the shared mailbox or delegated user.", # noqa: E501
show=False,
value="me",
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_folder",
display_name="Folder",
info="",
show=False,
value="inbox",
advanced=True,
),
IntInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_top",
display_name="Max Results",
info="The maximum number of messages to return per request. Must be a positive integer between 1 and 1000.",
show=False,
value=10,
),
IntInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_skip",
display_name="Skip",
info="The number of messages to skip before starting to collect results. Use for paginated responses.",
show=False,
value=0,
advanced=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_is_read",
display_name="Is Read",
info="Filter messages by read status. If set to False, only unread messages will be returned.",
show=False,
value=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_importance",
display_name="Importance",
info="Filter messages by importance. For example, 'high', 'normal', or 'low'.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_subject",
display_name="Subject",
info="Filter messages by subject (exact match).",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_gt",
display_name="Received Date Time Gt",
info="Filter messages with a receivedDateTime greater than the specified value. Example: '2023-01-01T00:00:00Z'.", # noqa: E501
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_startswith",
display_name="Subject Startswith",
info="Filter messages where the subject starts with the specified string.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_endswith",
display_name="Subject Endswith",
info="Filter messages where the subject ends with the specified string.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_contains",
display_name="Subject Contains",
info="Filter messages where the subject contains the specified substring.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_ge",
display_name="Received Date Time Ge",
info="Filter messages with a receivedDateTime greater than or equal to the specified value.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_lt",
display_name="Received Date Time Lt",
info="Filter messages with a receivedDateTime less than the specified value.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_le",
display_name="Received Date Time Le",
info="Filter messages with a receivedDateTime less than or equal to the specified value.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_from_address",
display_name="From Address",
info="Filter messages by the sender's email address. Uses equality check on from/emailAddress/address.",
show=False,
advanced=True,
),
BoolInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_has_attachments",
display_name="Has Attachments",
info="Filter messages by whether they have attachments.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_body_preview_contains",
display_name="Body Preview Contains",
info="Filter messages where the bodyPreview contains the specified substring.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_gt",
display_name="Sent Date Time Gt",
info="Filter messages with a sentDateTime greater than the specified value.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_lt",
display_name="Sent Date Time Lt",
info="Filter messages with a sentDateTime less than the specified value.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_categories",
display_name="Categories",
info="Filter messages by categories. Matches if the message contains any of the specified categories.",
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_select",
display_name="Select",
info="A list of properties to include in the response comma separated. Common properties: 'subject', 'from', 'toRecipients', 'receivedDateTime'.", # noqa: E501
show=False,
advanced=True,
),
MessageTextInput(
name="OUTLOOK_OUTLOOK_LIST_MESSAGES_orderby",
display_name="Orderby",
info="Specify properties to sort results by. For example, 'receivedDateTime desc' for newest messages first.", # noqa: E501
show=False,
advanced=True,
),
]
def execute_action(self):
"""Execute action and return response as Message."""
toolset = self._build_wrapper()
try:
self._build_action_maps()
display_name = self.action[0]["name"] if isinstance(self.action, list) and self.action else self.action
action_key = self._display_to_key_map.get(display_name)
if not action_key:
msg = f"Invalid action: {display_name}"
raise ValueError(msg)
enum_name = getattr(Action, action_key)
params = {}
if action_key in self._actions_data:
for field in self._actions_data[action_key]["action_fields"]:
value = getattr(self, field)
if value is None or value == "":
continue
if field in self._list_variables and value:
value = [item.strip() for item in value.split(",")]
if field in self._bool_variables:
value = bool(value)
param_name = field.replace(action_key + "_", "")
params[param_name] = value
result = toolset.execute_action(
action=enum_name,
params=params,
)
if not result.get("successful"):
error_data = result.get("data", {})
error_message = error_data.get("message", str(result.get("error", "Unknown Error")))
if isinstance(error_message, str):
try:
error_obj = json.loads(error_message).get("error", {})
error_obj["status_code"] = error_data.get("status_code", 400)
return error_obj # noqa: TRY300
except json.JSONDecodeError:
return {"error": error_message, "status_code": error_data.get("status_code", 400)}
return error_message
result_data = result.get("data", {})
actions_data = self._actions_data.get(action_key, {})
if actions_data.get("get_result_field") and actions_data.get("result_field"):
response_data = result_data.get("response_data", {})
if response_data and actions_data.get("result_field") in response_data:
result_data = response_data.get(actions_data.get("result_field"), result.get("data", []))
else:
result_data = result_data.get(actions_data.get("result_field"), result.get("data", []))
if len(result_data) != 1 and not actions_data.get("result_field") and actions_data.get("get_result_field"):
msg = f"Expected a dict with a single key, got {len(result_data)} keys: {result_data.keys()}"
raise ValueError(msg)
return result_data # noqa: TRY300
except Exception as e:
logger.error(f"Error executing action: {e}")
display_name = self.action[0]["name"] if isinstance(self.action, list) and self.action else str(self.action)
msg = f"Failed to execute {display_name}: {e!s}"
raise ValueError(msg) from e
def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:
return super().update_build_config(build_config, field_value, field_name)
def set_default_tools(self):
self._default_tools = {
self.sanitize_action_name("OUTLOOK_OUTLOOK_SEND_EMAIL").replace(" ", "-"),
self.sanitize_action_name("OUTLOOK_OUTLOOK_LIST_MESSAGES").replace(" ", "-"),
}

View file

@ -0,0 +1,184 @@
from unittest.mock import MagicMock, patch
import pytest
from composio import Action
from langflow.components.composio.outlook_composio import ComposioOutlookAPIComponent
from langflow.schema.dataframe import DataFrame
from tests.base import DID_NOT_EXIST, ComponentTestBaseWithoutClient
from .test_base import MockComposioToolSet
class MockAction:
OUTLOOK_OUTLOOK_SEND_EMAIL = "OUTLOOK_OUTLOOK_SEND_EMAIL"
OUTLOOK_OUTLOOK_LIST_MESSAGES = "OUTLOOK_OUTLOOK_LIST_MESSAGES"
class TestOutlookComponent(ComponentTestBaseWithoutClient):
@pytest.fixture(autouse=True)
def mock_composio_toolset(self):
with patch("langflow.base.composio.composio_base.ComposioToolSet", MockComposioToolSet):
yield
@pytest.fixture
def component_class(self):
return ComposioOutlookAPIComponent
@pytest.fixture
def default_kwargs(self):
return {
"api_key": "",
"entity_id": "default",
"action": None,
}
@pytest.fixture
def file_names_mapping(self):
return [
{"version": "1.0.17", "module": "composio", "file_name": DID_NOT_EXIST},
{"version": "1.0.18", "module": "composio", "file_name": DID_NOT_EXIST},
{"version": "1.0.19", "module": "composio", "file_name": DID_NOT_EXIST},
{"version": "1.1.0", "module": "composio", "file_name": DID_NOT_EXIST},
{"version": "1.1.1", "module": "composio", "file_name": DID_NOT_EXIST},
]
def test_init(self, component_class, default_kwargs):
component = component_class(**default_kwargs)
assert component.display_name == "Outlook"
assert component.app_name == "outlook"
assert "OUTLOOK_OUTLOOK_SEND_EMAIL" in component._actions_data
assert "OUTLOOK_OUTLOOK_LIST_MESSAGES" in component._actions_data
def test_execute_action_send_email(self, component_class, default_kwargs, monkeypatch):
monkeypatch.setattr(Action, "OUTLOOK_OUTLOOK_SEND_EMAIL", MockAction.OUTLOOK_OUTLOOK_SEND_EMAIL)
component = component_class(**default_kwargs)
component.api_key = "test_key"
component.action = [{"name": "Send Email"}]
component.OUTLOOK_OUTLOOK_SEND_EMAIL_subject = "Test Subject"
component.OUTLOOK_OUTLOOK_SEND_EMAIL_body = "Test Body"
component.OUTLOOK_OUTLOOK_SEND_EMAIL_to_email = "test@example.com"
component._actions_data = {
"OUTLOOK_OUTLOOK_SEND_EMAIL": {
"display_name": "Send Email",
"action_fields": [
"OUTLOOK_OUTLOOK_SEND_EMAIL_user_id",
"OUTLOOK_OUTLOOK_SEND_EMAIL_subject",
"OUTLOOK_OUTLOOK_SEND_EMAIL_body",
"OUTLOOK_OUTLOOK_SEND_EMAIL_to_email",
"OUTLOOK_OUTLOOK_SEND_EMAIL_to_name",
"OUTLOOK_OUTLOOK_SEND_EMAIL_cc_emails",
"OUTLOOK_OUTLOOK_SEND_EMAIL_bcc_emails",
"OUTLOOK_OUTLOOK_SEND_EMAIL_is_html",
"OUTLOOK_OUTLOOK_SEND_EMAIL_save_to_sent_items",
"OUTLOOK_OUTLOOK_SEND_EMAIL_attachment",
],
},
}
result = component.execute_action()
assert result == {"result": "mocked response"}
def test_execute_action_fetch_emails(self, component_class, default_kwargs, monkeypatch):
monkeypatch.setattr(Action, "OUTLOOK_OUTLOOK_LIST_MESSAGES", MockAction.OUTLOOK_OUTLOOK_LIST_MESSAGES)
component = component_class(**default_kwargs)
component.api_key = "test_key"
component.action = [{"name": "List Messages"}]
component.OUTLOOK_OUTLOOK_LIST_MESSAGES_folder = "Inbox"
component.OUTLOOK_OUTLOOK_LIST_MESSAGES_top = 10
component._actions_data = {
"OUTLOOK_OUTLOOK_LIST_MESSAGES": {
"display_name": "List Messages",
"action_fields": [
"OUTLOOK_OUTLOOK_LIST_MESSAGES_user_id",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_folder",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_top",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_skip",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_is_read",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_importance",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_gt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_startswith",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_endswith",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_subject_contains",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_ge",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_lt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_received_date_time_le",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_from_address",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_has_attachments",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_body_preview_contains",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_gt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_sent_date_time_lt",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_categories",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_select",
"OUTLOOK_OUTLOOK_LIST_MESSAGES_orderby",
],
"get_result_field": True,
"result_field": "value",
},
}
mock_toolset = MagicMock()
mock_toolset.execute_action.return_value = {
"successful": True,
"data": {"response_data": {"value": [{"subject": "Test Email", "from": "test@example.com"}]}},
}
with patch.object(component, "_build_wrapper", return_value=mock_toolset):
result = component.execute_action()
assert result == [{"subject": "Test Email", "from": "test@example.com"}]
def test_execute_action_invalid_action(self, component_class, default_kwargs):
component = component_class(**default_kwargs)
component.api_key = "test_key"
component.action = [{"name": "Invalid Action"}]
with pytest.raises(ValueError, match="Invalid action: Invalid Action"):
component.execute_action()
def test_as_dataframe(self, component_class, default_kwargs, monkeypatch):
monkeypatch.setattr(Action, "OUTLOOK_OUTLOOK_SEND_EMAIL", MockAction.OUTLOOK_OUTLOOK_SEND_EMAIL)
component = component_class(**default_kwargs)
component.api_key = "test_key"
component.action = [{"name": "Send Email"}]
component.OUTLOOK_OUTLOOK_SEND_EMAIL_subject = "Test Subject"
component.OUTLOOK_OUTLOOK_SEND_EMAIL_body = "Test Body"
component.OUTLOOK_OUTLOOK_SEND_EMAIL_to_email = "test@example.com"
mock_emails = [
{
"message": "Email sent successfully.",
}
]
with patch.object(component, "execute_action", return_value=mock_emails):
result = component.as_dataframe()
assert isinstance(result, DataFrame)
assert not result.empty
data_str = str(result)
assert "Email sent successfully." in data_str
def test_update_build_config(self, component_class, default_kwargs):
component = component_class(**default_kwargs)
build_config = {
"auth_link": {"value": "", "auth_tooltip": ""},
"action": {
"options": [],
"helper_text": "",
"helper_text_metadata": {},
},
}
result = component.update_build_config(build_config, "", "api_key")
assert result["auth_link"]["value"] == ""
assert "Please provide a valid Composio API Key" in result["auth_link"]["auth_tooltip"]
assert result["action"]["options"] == []
component.api_key = "test_key"
result = component.update_build_config(build_config, "test_key", "api_key")
assert len(result["action"]["options"]) > 0

View file

@ -109,6 +109,8 @@ export const lazyIconsMapping = {
})),
Gmail: () =>
import("@/icons/gmail").then((mod) => ({ default: mod.GmailIcon })),
Outlook: () =>
import("@/icons/outlook").then((mod) => ({ default: mod.OutlookIcon })),
Googlecalendar: () =>
import("@/icons/googlecalendar").then((mod) => ({
default: mod.GooglecalendarIcon,

View file

@ -0,0 +1,9 @@
import React, { forwardRef } from "react";
import OutlookIconSVG from "./outlook";
export const OutlookIcon = forwardRef<
SVGSVGElement,
React.PropsWithChildren<{}>
>((props, ref) => {
return <OutlookIconSVG ref={ref} {...props} />;
});

View file

@ -0,0 +1,24 @@
const OutlookIconSVG = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
width="23px"
height="23px"
{...props}
>
<path
fill="#03A9F4"
d="M21,31c0,1.104,0.896,2,2,2h17c1.104,0,2-0.896,2-2V16c0-1.104-0.896-2-2-2H23c-1.104,0-2,0.896-2,2V31z"
/>
<path
fill="#B3E5FC"
d="M42,16.975V16c0-0.428-0.137-0.823-0.367-1.148l-11.264,6.932l-7.542-4.656L22.125,19l8.459,5L42,16.975z"
/>
<polygon fill="#0277BD" points="27,41.46 6,37.46 6,9.46 27,5.46 " />
<path
fill="#FFFFFF"
d="M21.216,18.311c-1.098-1.275-2.546-1.913-4.328-1.913c-1.892,0-3.408,0.669-4.554,2.003c-1.144,1.337-1.719,3.088-1.719,5.246c0,2.045,0.564,3.714,1.69,4.986c1.126,1.273,2.592,1.91,4.378,1.91c1.84,0,3.331-0.652,4.474-1.975c1.143-1.313,1.712-3.043,1.712-5.199C22.869,21.281,22.318,19.595,21.216,18.311z M19.049,26.735c-0.568,0.769-1.339,1.152-2.313,1.152c-0.939,0-1.699-0.394-2.285-1.187c-0.581-0.785-0.87-1.861-0.87-3.211c0-1.336,0.289-2.414,0.87-3.225c0.586-0.81,1.368-1.211,2.355-1.211c0.962,0,1.718,0.393,2.267,1.178c0.555,0.795,0.833,1.895,0.833,3.31C19.907,24.906,19.618,25.968,19.049,26.735z"
/>
</svg>
);
export default OutlookIconSVG;

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" width="23px" height="23px"><path fill="#03A9F4" d="M21,31c0,1.104,0.896,2,2,2h17c1.104,0,2-0.896,2-2V16c0-1.104-0.896-2-2-2H23c-1.104,0-2,0.896-2,2V31z"/><path fill="#B3E5FC" d="M42,16.975V16c0-0.428-0.137-0.823-0.367-1.148l-11.264,6.932l-7.542-4.656L22.125,19l8.459,5L42,16.975z"/><polygon fill="#0277BD" points="27,41.46 6,37.46 6,9.46 27,5.46 "/><path fill="#FFFFFF" d="M21.216,18.311c-1.098-1.275-2.546-1.913-4.328-1.913c-1.892,0-3.408,0.669-4.554,2.003c-1.144,1.337-1.719,3.088-1.719,5.246c0,2.045,0.564,3.714,1.69,4.986c1.126,1.273,2.592,1.91,4.378,1.91c1.84,0,3.331-0.652,4.474-1.975c1.143-1.313,1.712-3.043,1.712-5.199C22.869,21.281,22.318,19.595,21.216,18.311z M19.049,26.735c-0.568,0.769-1.339,1.152-2.313,1.152c-0.939,0-1.699-0.394-2.285-1.187c-0.581-0.785-0.87-1.861-0.87-3.211c0-1.336,0.289-2.414,0.87-3.225c0.586-0.81,1.368-1.211,2.355-1.211c0.962,0,1.718,0.393,2.267,1.178c0.555,0.795,0.833,1.895,0.833,3.31C19.907,24.906,19.618,25.968,19.049,26.735z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -229,6 +229,7 @@ export const SIDEBAR_CATEGORIES = [
];
export const SIDEBAR_BUNDLES = [
{ display_name: "Outlook", name: "outlook", icon: "Outlook" },
{
display_name: "Language Models",
name: "languagemodels",
@ -238,6 +239,7 @@ export const SIDEBAR_BUNDLES = [
{ display_name: "Memories", name: "memories", icon: "Cpu" },
{ display_name: "Amazon", name: "amazon", icon: "Amazon" },
{ display_name: "Gmail", name: "gmail", icon: "Gmail" },
{ display_name: "Outlook", name: "outlook", icon: "Outlook" },
{ display_name: "GitHub", name: "github", icon: "Github" },
{
display_name: "Googlecalendar",
@ -339,6 +341,7 @@ export const nodeIconToDisplayIconMap: Record<string, string> = {
ChatInput: "MessagesSquare",
ChatOutput: "MessagesSquare",
//Integration Icons
Outlook: "Outlook",
AIML: "AI/ML",
AgentQL: "AgentQL",
LanguageModels: "BrainCircuit",