from __future__ import annotations import asyncio import base64 from contextlib import asynccontextmanager from email.header import decode_header, make_header from email.message import EmailMessage from email.parser import BytesParser from email.policy import default as default_email_policy from email.utils import formatdate, make_msgid, parsedate_to_datetime import imaplib import json import re import smtplib import ssl from typing import Any import httpx from deepagents import create_deep_agent from langchain_core.messages import BaseMessage from langchain_core.tools import StructuredTool from langchain_openai import ChatOpenAI from pydantic import BaseModel, Field from a2a_pack import ( A2AAgent, ConsumerSetup, ConsumerSetupField, ConsumerSetupMissing, EgressPolicy, LLMProvisioning, Pricing, Resources, RunContext, skill, ) DEFAULT_BASE_URL = "https://mail.a2acloud.io/api/v1" OPERATIONS = json.loads("{\n \"create_alias\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new alias\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_alias\",\n \"parameters\": [],\n \"path\": \"/alias\",\n \"request_body\": {\n \"$ref\": \"#/definitions/Alias\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_alias\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new alias\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"create_alternative\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new alternative (for domain)\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_alternative\",\n \"parameters\": [],\n \"path\": \"/alternative\",\n \"request_body\": {\n \"$ref\": \"#/definitions/AlternativeDomain\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_alternative\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new alternative (for domain)\",\n \"tags\": [\n \"alternative\"\n ]\n },\n \"create_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new domain\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_domain\",\n \"parameters\": [],\n \"path\": \"/domain\",\n \"request_body\": {\n \"$ref\": \"#/definitions/Domain\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"create_manager\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new domain manager for the specified domain\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_manager\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/manager\",\n \"request_body\": {\n \"$ref\": \"#/definitions/ManagerCreate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_manager\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new domain manager for the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"create_relay\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new relay\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_relay\",\n \"parameters\": [],\n \"path\": \"/relay\",\n \"request_body\": {\n \"$ref\": \"#/definitions/Relay\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_relay\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new relay\",\n \"tags\": [\n \"relay\"\n ]\n },\n \"create_token\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new token\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_token\",\n \"parameters\": [],\n \"path\": \"/token\",\n \"request_body\": {\n \"$ref\": \"#/definitions/TokenPost\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_token\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new token\",\n \"tags\": [\n \"token\"\n ]\n },\n \"create_token_2\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new token for the specified user\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_token_2\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/tokenuser/{email}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/TokenPost2\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_token_2\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new token for the specified user\",\n \"tags\": [\n \"token\"\n ]\n },\n \"create_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Create a new user\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_user\",\n \"parameters\": [],\n \"path\": \"/user\",\n \"request_body\": {\n \"$ref\": \"#/definitions/UserCreate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"create_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Create a new user\",\n \"tags\": [\n \"user\"\n ]\n },\n \"delete_alias\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified alias\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_alias\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"alias\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alias/{alias}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_alias\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified alias\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"delete_alternative\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified alternative (for domain)\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_alternative\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"alt\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alternative/{alt}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_alternative\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified alternative (for domain)\",\n \"tags\": [\n \"alternative\"\n ]\n },\n \"delete_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified domain\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_domain\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"delete_manager\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified manager of the specified domain\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_manager\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/manager/{email}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_manager\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified manager of the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"delete_relay\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified relay\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_relay\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"name\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/relay/{name}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_relay\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified relay\",\n \"tags\": [\n \"relay\"\n ]\n },\n \"delete_token\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified token\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_token\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"token_id\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/token/{token_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_token\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified token\",\n \"tags\": [\n \"token\"\n ]\n },\n \"delete_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Delete the specified user\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_user\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/user/{email}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"delete_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Delete the specified user\",\n \"tags\": [\n \"user\"\n ]\n },\n \"find_alias\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the specified alias\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_alias\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"alias\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alias/{alias}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_alias\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the specified alias\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"find_alias_filter_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the aliases of the specified domain\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_alias_filter_domain\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alias/destination/{domain}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_alias_filter_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the aliases of the specified domain\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"find_alternative\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the specified alternative (of domain)\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_alternative\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"alt\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alternative/{alt}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_alternative\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the specified alternative (of domain)\",\n \"tags\": [\n \"alternative\"\n ]\n },\n \"find_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the specified domain\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_domain\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"find_manager\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Check if the specified user is a manager of the specified domain\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_manager\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/manager/{email}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_manager\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Check if the specified user is a manager of the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"find_relay\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the specified relay\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_relay\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"name\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/relay/{name}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_relay\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the specified relay\",\n \"tags\": [\n \"relay\"\n ]\n },\n \"find_token\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Find the specified token\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_token\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"token_id\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/token/{token_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_token\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Find the specified token\",\n \"tags\": [\n \"token\"\n ]\n },\n \"find_tokens_of_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up all the tokens of the specified user\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_tokens_of_user\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/tokenuser/{email}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_tokens_of_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up all the tokens of the specified user\",\n \"tags\": [\n \"token\"\n ]\n },\n \"find_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Look up the specified user\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"find_user\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/user/{email}\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"find_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Look up the specified user\",\n \"tags\": [\n \"user\"\n ]\n },\n \"generate_dkim\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Generate new DKIM/DMARC keys for the specified domain\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"generate_dkim\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/dkim\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"generate_dkim\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Generate new DKIM/DMARC keys for the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"list_alias\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all aliases\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_alias\",\n \"parameters\": [],\n \"path\": \"/alias\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_alias\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all aliases\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"list_alternative\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all alternatives\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_alternative\",\n \"parameters\": [],\n \"path\": \"/alternative\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_alternative\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all alternatives\",\n \"tags\": [\n \"alternative\"\n ]\n },\n \"list_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all domains\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_domain\",\n \"parameters\": [],\n \"path\": \"/domain\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all domains\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"list_managers\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all managers of the specified domain\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_managers\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/manager\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_managers\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all managers of the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"list_relays\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all relays\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_relays\",\n \"parameters\": [],\n \"path\": \"/relay\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_relays\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all relays\",\n \"tags\": [\n \"relay\"\n ]\n },\n \"list_tokens\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all tokens\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_tokens\",\n \"parameters\": [],\n \"path\": \"/token\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_tokens\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all tokens\",\n \"tags\": [\n \"token\"\n ]\n },\n \"list_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all users\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_user\",\n \"parameters\": [],\n \"path\": \"/user\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all users\",\n \"tags\": [\n \"user\"\n ]\n },\n \"list_user_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"List all the users from the specified domain\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_user_domain\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}/users\",\n \"request_body\": null,\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"list_user_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"List all the users from the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"update_alias\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Update the specfied alias\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_alias\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"alias\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/alias/{alias}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/AliasUpdate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"update_alias\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Update the specfied alias\",\n \"tags\": [\n \"alias\"\n ]\n },\n \"update_domain\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Update the specified domain\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_domain\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"domain\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/domain/{domain}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/DomainUpdate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"update_domain\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Update the specified domain\",\n \"tags\": [\n \"domain\"\n ]\n },\n \"update_relay\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Update the specified relay\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_relay\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"name\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/relay/{name}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/RelayUpdate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"update_relay\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Update the specified relay\",\n \"tags\": [\n \"relay\"\n ]\n },\n \"update_token\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Update the specified token\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_token\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"token_id\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/token/{token_id}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/TokenPost2\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"update_token\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Update the specified token\",\n \"tags\": [\n \"token\"\n ]\n },\n \"update_user\": {\n \"base_url\": \"https://mail.a2acloud.io/api/v1\",\n \"base_url_field\": \"OPENAPI_BASE_URL\",\n \"description\": \"Update the specified user\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_user\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"email\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/user/{email}\",\n \"request_body\": {\n \"$ref\": \"#/definitions/UserUpdate\"\n },\n \"security\": [\n {\n \"Bearer\": []\n }\n ],\n \"skill_name\": \"update_user\",\n \"source_index\": 1,\n \"source_openapi_url\": \"https://mail.a2acloud.io/api/v1/swagger.json\",\n \"source_title\": \"Mailu API\",\n \"summary\": \"Update the specified user\",\n \"tags\": [\n \"user\"\n ]\n }\n}") ROOT_SECURITY = json.loads("[\n {\n \"Bearer\": []\n }\n]") SECURITY_SCHEMES = json.loads("{\n \"Bearer\": {\n \"in\": \"header\",\n \"name\": \"Authorization\",\n \"type\": \"apiKey\"\n }\n}") SECURITY_FIELDS = json.loads("{\n \"Bearer\": {\n \"field\": \"AUTHORIZATION\",\n \"kind\": \"apiKey\",\n \"location\": \"header\",\n \"name\": \"Authorization\"\n }\n}") PATH_PARAMETER_RE = re.compile(r"{([^}/]+)}") class OperationInput(BaseModel): parameters: dict[str, Any] = Field( default_factory=dict, description="Path, query, header, and cookie parameters keyed by OpenAPI parameter name.", ) body: Any | None = Field(default=None, description="JSON request body, when the operation accepts one.") class SendEmailInput(BaseModel): email: str = Field(description="Mailbox email address to send as. A temporary Mailu token is minted internally.") to: list[str] = Field(description="Recipient email addresses.") subject: str = Field(description="Message subject.") text_body: str = Field(description="Plain text message body.") cc: list[str] = Field(default_factory=list, description="CC recipients.") bcc: list[str] = Field(default_factory=list, description="BCC recipients.") reply_to: str | None = Field(default=None, description="Optional Reply-To address.") smtp_host: str = Field(default="mail.a2acloud.io", description="SMTP submission host.") smtp_port: int = Field(default=587, description="SMTP port. Use 587 for STARTTLS or 465 for implicit TLS.") class ReadInboxInput(BaseModel): email: str = Field(description="Mailbox email address to read. A temporary Mailu token is minted internally.") mailbox: str = Field(default="INBOX", description="IMAP mailbox name.") limit: int = Field(default=10, ge=1, le=50, description="Maximum number of newest messages to return.") unread_only: bool = Field(default=True, description="Only return unread messages.") mark_seen: bool = Field(default=False, description="Mark returned messages as read.") max_body_chars: int = Field(default=4000, ge=0, le=20000, description="Maximum plain text body characters per message.") imap_host: str = Field(default="mail.a2acloud.io", description="IMAPS host.") imap_port: int = Field(default=993, description="IMAPS port.") class MarkEmailReadInput(BaseModel): email: str = Field(description="Mailbox email address. A temporary Mailu token is minted internally.") uid: str = Field(description="IMAP UID returned by read_inbox.") mailbox: str = Field(default="INBOX", description="IMAP mailbox name.") imap_host: str = Field(default="mail.a2acloud.io", description="IMAPS host.") imap_port: int = Field(default=993, description="IMAPS port.") class MailuOpenapiAgent(A2AAgent): name = "mailu-openapi-agent" description = "Mailu administration agent generated from the live Mailu OpenAPI spec." version = "1.0" consumer_setup = ConsumerSetup.from_fields( ConsumerSetupField.config("OPENAPI_BASE_URL", label="API base URL", description="Override the default API server (https://mail.a2acloud.io/api/v1).", required=False, input_type="url"), ConsumerSetupField.secret("AUTHORIZATION", label="Bearer API key", description="Sent as header parameter 'Authorization'. Also used to mint temporary per-user Mailu mailbox tokens for SMTP/IMAP skills.", required=True), ) llm_provisioning = LLMProvisioning.PLATFORM pricing = Pricing( price_per_call_usd=0.0, caller_pays_llm=False, notes="Uses a scoped platform LLM grant through ctx.llm.", ) resources = Resources(cpu="200m", memory="512Mi") egress = EgressPolicy( allow_hosts=('mail.a2acloud.io',), deny_internet_by_default=True, ) tools_used = ("openapi", "deepagents") capabilities = { "openapi_auto_agent": { "operation_count": len(OPERATIONS), "default_base_url": DEFAULT_BASE_URL, "source_openapi_url": 'https://mail.a2acloud.io/api/v1/swagger.json', "source_openapi_urls": ['https://mail.a2acloud.io/api/v1/swagger.json'], "server_urls": ['https://mail.a2acloud.io/api/v1'], "regenerable": True, "security_schemes": list(SECURITY_SCHEMES), } } @skill( name="auto", description="Use the OpenAPI service to complete a natural-language goal.", tags=("openapi", "auto"), timeout_seconds=180, ) async def auto(self, ctx: RunContext, goal: str) -> dict[str, Any]: creds = ctx.llm if not creds.api_key: return { "error": "llm_credentials_missing", "final": ( "LLM credentials were not available for this run. Hosted " "generated OpenAPI agents should receive a platform LLM grant." ), "messages": [], } model_kwargs: dict[str, Any] = { "model": creds.model, "base_url": creds.base_url, "api_key": creds.api_key, } if creds.temperature_mode != "omit" and creds.temperature is not None: model_kwargs["temperature"] = creds.temperature if creds.extra_body: model_kwargs["extra_body"] = dict(creds.extra_body) model = ChatOpenAI(**model_kwargs) graph = create_deep_agent( model=model, tools=self._operation_tools(ctx), system_prompt=self._system_prompt(), ) result = await graph.ainvoke({"messages": [{"role": "user", "content": goal}]}) messages = result.get("messages", []) if isinstance(result, dict) else [] final = _message_text(messages[-1]) if messages else result return { "final": final, "messages": [_message_to_dict(message) for message in messages[-8:]], } @skill( name="send_email", description="Mint a temporary Mailu token for a mailbox, send an email over SMTP submission, then delete the token.", tags=("mailbox", "smtp", "email"), timeout_seconds=120, ) async def send_email( self, ctx: RunContext, email: str, to: list[str], subject: str, text_body: str, cc: list[str] | None = None, bcc: list[str] | None = None, reply_to: str | None = None, smtp_host: str = "mail.a2acloud.io", smtp_port: int = 587, ) -> dict[str, Any]: if not to: return {"ok": False, "error": "recipient_required"} async with self._temporary_mail_token(ctx, email, "send_email") as token_info: return await asyncio.to_thread( _send_email_sync, email, token_info["token"], to, subject, text_body, cc or [], bcc or [], reply_to, smtp_host, smtp_port, ) @skill( name="read_inbox", description="Mint a temporary Mailu token for a mailbox, read messages over IMAPS, then delete the token.", tags=("mailbox", "imap", "email"), timeout_seconds=120, ) async def read_inbox( self, ctx: RunContext, email: str, mailbox: str = "INBOX", limit: int = 10, unread_only: bool = True, mark_seen: bool = False, max_body_chars: int = 4000, imap_host: str = "mail.a2acloud.io", imap_port: int = 993, ) -> dict[str, Any]: async with self._temporary_mail_token(ctx, email, "read_inbox") as token_info: return await asyncio.to_thread( _read_inbox_sync, email, token_info["token"], mailbox, limit, unread_only, mark_seen, max_body_chars, imap_host, imap_port, ) @skill( name="mark_email_read", description="Mint a temporary Mailu token for a mailbox, mark one IMAP UID as read, then delete the token.", tags=("mailbox", "imap", "email"), timeout_seconds=60, ) async def mark_email_read( self, ctx: RunContext, email: str, uid: str, mailbox: str = "INBOX", imap_host: str = "mail.a2acloud.io", imap_port: int = 993, ) -> dict[str, Any]: async with self._temporary_mail_token(ctx, email, "mark_email_read") as token_info: return await asyncio.to_thread( _mark_email_read_sync, email, token_info["token"], uid, mailbox, imap_host, imap_port, ) @skill( name="create_alias", description="POST /alias - Create a new alias", tags=('alias',), timeout_seconds=120, ) async def create_alias( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_alias", parameters=parameters or {}, body=body, ) @skill( name="list_alias", description="GET /alias - List all aliases", tags=('alias',), timeout_seconds=60, ) async def list_alias( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_alias", parameters=parameters or {}, body=body, ) @skill( name="find_alias_filter_domain", description="GET /alias/destination/{domain} - Look up the aliases of the specified domain", tags=('alias',), timeout_seconds=60, ) async def find_alias_filter_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_alias_filter_domain", parameters=parameters or {}, body=body, ) @skill( name="update_alias", description="PATCH /alias/{alias} - Update the specfied alias", tags=('alias',), timeout_seconds=120, ) async def update_alias( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "update_alias", parameters=parameters or {}, body=body, ) @skill( name="delete_alias", description="DELETE /alias/{alias} - Delete the specified alias", tags=('alias',), timeout_seconds=120, ) async def delete_alias( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_alias", parameters=parameters or {}, body=body, ) @skill( name="find_alias", description="GET /alias/{alias} - Look up the specified alias", tags=('alias',), timeout_seconds=60, ) async def find_alias( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_alias", parameters=parameters or {}, body=body, ) @skill( name="create_alternative", description="POST /alternative - Create a new alternative (for domain)", tags=('alternative',), timeout_seconds=120, ) async def create_alternative( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_alternative", parameters=parameters or {}, body=body, ) @skill( name="list_alternative", description="GET /alternative - List all alternatives", tags=('alternative',), timeout_seconds=60, ) async def list_alternative( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_alternative", parameters=parameters or {}, body=body, ) @skill( name="delete_alternative", description="DELETE /alternative/{alt} - Delete the specified alternative (for domain)", tags=('alternative',), timeout_seconds=120, ) async def delete_alternative( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_alternative", parameters=parameters or {}, body=body, ) @skill( name="find_alternative", description="GET /alternative/{alt} - Look up the specified alternative (of domain)", tags=('alternative',), timeout_seconds=60, ) async def find_alternative( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_alternative", parameters=parameters or {}, body=body, ) @skill( name="create_domain", description="POST /domain - Create a new domain", tags=('domain',), timeout_seconds=120, ) async def create_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_domain", parameters=parameters or {}, body=body, ) @skill( name="list_domain", description="GET /domain - List all domains", tags=('domain',), timeout_seconds=60, ) async def list_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_domain", parameters=parameters or {}, body=body, ) @skill( name="update_domain", description="PATCH /domain/{domain} - Update the specified domain", tags=('domain',), timeout_seconds=120, ) async def update_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "update_domain", parameters=parameters or {}, body=body, ) @skill( name="delete_domain", description="DELETE /domain/{domain} - Delete the specified domain", tags=('domain',), timeout_seconds=120, ) async def delete_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_domain", parameters=parameters or {}, body=body, ) @skill( name="find_domain", description="GET /domain/{domain} - Look up the specified domain", tags=('domain',), timeout_seconds=60, ) async def find_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_domain", parameters=parameters or {}, body=body, ) @skill( name="generate_dkim", description="POST /domain/{domain}/dkim - Generate new DKIM/DMARC keys for the specified domain", tags=('domain',), timeout_seconds=120, ) async def generate_dkim( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "generate_dkim", parameters=parameters or {}, body=body, ) @skill( name="create_manager", description="POST /domain/{domain}/manager - Create a new domain manager for the specified domain", tags=('domain',), timeout_seconds=120, ) async def create_manager( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_manager", parameters=parameters or {}, body=body, ) @skill( name="list_managers", description="GET /domain/{domain}/manager - List all managers of the specified domain", tags=('domain',), timeout_seconds=60, ) async def list_managers( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_managers", parameters=parameters or {}, body=body, ) @skill( name="delete_manager", description="DELETE /domain/{domain}/manager/{email} - Delete the specified manager of the specified domain", tags=('domain',), timeout_seconds=120, ) async def delete_manager( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_manager", parameters=parameters or {}, body=body, ) @skill( name="find_manager", description="GET /domain/{domain}/manager/{email} - Check if the specified user is a manager of the specified domain", tags=('domain',), timeout_seconds=60, ) async def find_manager( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_manager", parameters=parameters or {}, body=body, ) @skill( name="list_user_domain", description="GET /domain/{domain}/users - List all the users from the specified domain", tags=('domain',), timeout_seconds=60, ) async def list_user_domain( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_user_domain", parameters=parameters or {}, body=body, ) @skill( name="create_relay", description="POST /relay - Create a new relay", tags=('relay',), timeout_seconds=120, ) async def create_relay( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_relay", parameters=parameters or {}, body=body, ) @skill( name="list_relays", description="GET /relay - List all relays", tags=('relay',), timeout_seconds=60, ) async def list_relays( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_relays", parameters=parameters or {}, body=body, ) @skill( name="update_relay", description="PATCH /relay/{name} - Update the specified relay", tags=('relay',), timeout_seconds=120, ) async def update_relay( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "update_relay", parameters=parameters or {}, body=body, ) @skill( name="delete_relay", description="DELETE /relay/{name} - Delete the specified relay", tags=('relay',), timeout_seconds=120, ) async def delete_relay( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_relay", parameters=parameters or {}, body=body, ) @skill( name="find_relay", description="GET /relay/{name} - Look up the specified relay", tags=('relay',), timeout_seconds=60, ) async def find_relay( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_relay", parameters=parameters or {}, body=body, ) @skill( name="create_token", description="POST /token - Create a new token", tags=('token',), timeout_seconds=120, ) async def create_token( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_token", parameters=parameters or {}, body=body, ) @skill( name="list_tokens", description="GET /token - List all tokens", tags=('token',), timeout_seconds=60, ) async def list_tokens( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_tokens", parameters=parameters or {}, body=body, ) @skill( name="update_token", description="PATCH /token/{token_id} - Update the specified token", tags=('token',), timeout_seconds=120, ) async def update_token( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "update_token", parameters=parameters or {}, body=body, ) @skill( name="delete_token", description="DELETE /token/{token_id} - Delete the specified token", tags=('token',), timeout_seconds=120, ) async def delete_token( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_token", parameters=parameters or {}, body=body, ) @skill( name="find_token", description="GET /token/{token_id} - Find the specified token", tags=('token',), timeout_seconds=60, ) async def find_token( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_token", parameters=parameters or {}, body=body, ) @skill( name="create_token_2", description="POST /tokenuser/{email} - Create a new token for the specified user", tags=('token',), timeout_seconds=120, ) async def create_token_2( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_token_2", parameters=parameters or {}, body=body, ) @skill( name="find_tokens_of_user", description="GET /tokenuser/{email} - Look up all the tokens of the specified user", tags=('token',), timeout_seconds=60, ) async def find_tokens_of_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_tokens_of_user", parameters=parameters or {}, body=body, ) @skill( name="create_user", description="POST /user - Create a new user", tags=('user',), timeout_seconds=120, ) async def create_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "create_user", parameters=parameters or {}, body=body, ) @skill( name="list_user", description="GET /user - List all users", tags=('user',), timeout_seconds=60, ) async def list_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "list_user", parameters=parameters or {}, body=body, ) @skill( name="update_user", description="PATCH /user/{email} - Update the specified user", tags=('user',), timeout_seconds=120, ) async def update_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "update_user", parameters=parameters or {}, body=body, ) @skill( name="delete_user", description="DELETE /user/{email} - Delete the specified user", tags=('user',), timeout_seconds=120, ) async def delete_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "delete_user", parameters=parameters or {}, body=body, ) @skill( name="find_user", description="GET /user/{email} - Look up the specified user", tags=('user',), timeout_seconds=60, ) async def find_user( self, ctx: RunContext, parameters: dict[str, Any] | None = None, body: Any | None = None, ) -> dict[str, Any]: return await self._request( ctx, "find_user", parameters=parameters or {}, body=body, ) def _operation_tools(self, ctx: RunContext) -> list[StructuredTool]: async def send_email_tool( email: str, to: list[str], subject: str, text_body: str, cc: list[str] | None = None, bcc: list[str] | None = None, reply_to: str | None = None, smtp_host: str = "mail.a2acloud.io", smtp_port: int = 587, ) -> dict[str, Any]: return await self.send_email( ctx, email=email, to=to, subject=subject, text_body=text_body, cc=cc, bcc=bcc, reply_to=reply_to, smtp_host=smtp_host, smtp_port=smtp_port, ) async def read_inbox_tool( email: str, mailbox: str = "INBOX", limit: int = 10, unread_only: bool = True, mark_seen: bool = False, max_body_chars: int = 4000, imap_host: str = "mail.a2acloud.io", imap_port: int = 993, ) -> dict[str, Any]: return await self.read_inbox( ctx, email=email, mailbox=mailbox, limit=limit, unread_only=unread_only, mark_seen=mark_seen, max_body_chars=max_body_chars, imap_host=imap_host, imap_port=imap_port, ) async def mark_email_read_tool( email: str, uid: str, mailbox: str = "INBOX", imap_host: str = "mail.a2acloud.io", imap_port: int = 993, ) -> dict[str, Any]: return await self.mark_email_read( ctx, email=email, uid=uid, mailbox=mailbox, imap_host=imap_host, imap_port=imap_port, ) tools: list[StructuredTool] = [ StructuredTool.from_function( coroutine=send_email_tool, name="send_email", description="Send email through Mailu SMTP. Provide the mailbox email; the tool mints and deletes a temporary Mailu user token internally.", args_schema=SendEmailInput, ), StructuredTool.from_function( coroutine=read_inbox_tool, name="read_inbox", description="Read Mailu mailbox messages through IMAPS. Provide the mailbox email; the tool mints and deletes a temporary Mailu user token internally.", args_schema=ReadInboxInput, ), StructuredTool.from_function( coroutine=mark_email_read_tool, name="mark_email_read", description="Mark a Mailu mailbox message as read by IMAP UID. Provide the mailbox email; the tool mints and deletes a temporary Mailu user token internally.", args_schema=MarkEmailReadInput, ), ] for operation_id, operation in OPERATIONS.items(): async def call( parameters: dict[str, Any] | None = None, body: Any | None = None, *, _operation_id: str = operation_id, ) -> dict[str, Any]: return await self._request( ctx, _operation_id, parameters=parameters or {}, body=body, ) tools.append( StructuredTool.from_function( coroutine=call, name=operation["skill_name"], description=self._tool_description(operation), args_schema=OperationInput, ) ) return tools def _system_prompt(self) -> str: lines = [ "You operate an API through generated OpenAPI tools.", "Call tools to get real results. Do not invent API responses.", "For write, update, or delete operations, explain the intended action before calling the tool.", "For mailbox tasks, use send_email, read_inbox, and mark_email_read. These tools mint temporary Mailu user tokens internally; never ask the user for or reveal mailbox tokens.", "If an operation reports missing consumer setup, tell the user which setup field is required.", "If an operation returns 404, 405, 410, or a schema/validation error that suggests the live API no longer matches these tools, tell the user this generated agent may need to be refreshed from the latest OpenAPI spec and ask whether they want to refresh it.", "", "Mailbox tools:", "- send_email: WRITE SMTP submission using a temporary per-user token.", "- read_inbox: READ IMAPS mailbox messages using a temporary per-user token.", "- mark_email_read: WRITE IMAP seen flag using a temporary per-user token.", "", "Available operations:", ] for operation in OPERATIONS.values(): marker = "WRITE" if operation.get("destructive") else "READ" lines.append( f"- {operation['skill_name']}: {marker} {operation['method']} {operation['path']} — {operation['summary']}" ) return "\n".join(lines) def _tool_description(self, operation: dict[str, Any]) -> str: parts = [ f"{operation['method']} {operation['path']}", str(operation.get("description") or operation.get("summary") or ""), ] if operation.get("parameters"): parts.append( "Parameters: " + ", ".join( f"{p['name']} in {p['in']}{' required' if p.get('required') else ''}" for p in operation["parameters"] ) ) if operation.get("request_body") is not None: parts.append("Accepts a JSON request body.") return "\n".join(part for part in parts if part) @asynccontextmanager async def _temporary_mail_token( self, ctx: RunContext, email_address: str, purpose: str, ): created = await self._request( ctx, "create_token_2", parameters={"email": email_address}, body={"comment": f"mailu-openapi-agent temporary token for {purpose}"}, ) if not created.get("ok"): raise RuntimeError(f"failed to mint temporary Mailu token: {created}") token_info = _extract_mailu_token(created.get("result")) try: yield token_info finally: token_id = token_info.get("id") if token_id: await self._request( ctx, "delete_token", parameters={"token_id": token_id}, body=None, ) async def _request( self, ctx: RunContext, operation_id: str, *, parameters: dict[str, Any], body: Any | None, ) -> dict[str, Any]: operation = OPERATIONS[operation_id] default_base_url = str(operation.get("base_url") or DEFAULT_BASE_URL).rstrip("/") base_url_field = str(operation.get("base_url_field") or "OPENAPI_BASE_URL") base_url = str(ctx.consumer_config(base_url_field, default_base_url) or default_base_url).rstrip("/") url, query, headers = self._request_parts(ctx, operation, parameters) request_kwargs: dict[str, Any] = { "params": query, "headers": headers, } if body is not None: if isinstance(body, (bytes, bytearray)): body = body.decode("utf-8", errors="replace") if isinstance(body, str): stripped = body.strip() if stripped and stripped[0] in "{[": try: body = json.loads(stripped) except ValueError: pass request_kwargs["json"] = body async with httpx.AsyncClient(timeout=60.0, follow_redirects=True) as client: response = await client.request( operation["method"], f"{base_url}{url}", **request_kwargs, ) content_type = response.headers.get("content-type", "") try: payload: Any = response.json() if "json" in content_type else response.text except ValueError: payload = response.text if response.status_code >= 400: out = { "ok": False, "status_code": response.status_code, "operation_id": operation_id, "error": payload, } if response.status_code in {404, 405, 410, 422}: out["stale_openapi_hint"] = ( "This generated OpenAPI agent may be stale. Ask the user " "whether they want to refresh it from the latest OpenAPI spec." ) return out return { "ok": True, "status_code": response.status_code, "operation_id": operation_id, "result": payload, } def _request_parts( self, ctx: RunContext, operation: dict[str, Any], parameters: dict[str, Any], ) -> tuple[str, dict[str, Any], dict[str, str]]: path = operation["path"] query: dict[str, Any] = {} headers: dict[str, str] = {} cookies: dict[str, Any] = {} for param in operation.get("parameters") or []: name = param["name"] if name not in parameters: if param.get("required"): raise ValueError(f"missing required parameter {name!r}") continue value = parameters[name] location = param["in"] if location == "path": path = path.replace("{" + name + "}", str(value)) elif location == "query": query[name] = value elif location == "header": headers[name] = str(value) elif location == "cookie": cookies[name] = value unresolved = PATH_PARAMETER_RE.findall(path) if unresolved: missing = ", ".join(sorted(set(unresolved))) raise ValueError("missing required path parameter(s): " + missing) if cookies: headers["cookie"] = "; ".join(f"{key}={value}" for key, value in cookies.items()) auth_headers, auth_query = self._auth_for_operation(ctx, operation) headers.update(auth_headers) query.update(auth_query) return path, query, headers def _auth_for_operation(self, ctx: RunContext, operation: dict[str, Any]) -> tuple[dict[str, str], dict[str, Any]]: requirements = operation.get("security") if requirements is None: requirements = ROOT_SECURITY if requirements == []: return {}, {} missing: list[str] = [] for requirement in requirements or []: if not isinstance(requirement, dict) or not requirement: return {}, {} headers: dict[str, str] = {} query: dict[str, Any] = {} ok = True for scheme_name in requirement: mapping = SECURITY_FIELDS.get(scheme_name) or {} secret_name = mapping.get("field") value = _consumer_secret_optional(ctx, secret_name) if secret_name else "" if not value: ok = False if secret_name: missing.append(secret_name) continue kind = mapping.get("kind") if kind == "apiKey": prefix = mapping.get("prefix") or "" sent_value = f"{prefix}{value}" if mapping.get("location") == "query": query[mapping.get("name") or scheme_name] = sent_value else: headers[mapping.get("name") or scheme_name] = sent_value elif kind in {"http", "oauth2"}: scheme = mapping.get("scheme") or "Bearer" if scheme.lower() == "basic": token = base64.b64encode(value.encode("utf-8")).decode("ascii") headers["authorization"] = f"Basic {token}" else: headers["authorization"] = f"{scheme} {value}" else: ok = False if ok: return headers, query if missing: raise ConsumerSetupMissing( "operation requires consumer setup secret(s): " + ", ".join(sorted(set(missing))) ) return {}, {} def _consumer_secret_optional(ctx: RunContext, name: str | None) -> str: if not name: return "" try: return ctx.consumer_secret(name) except ConsumerSetupMissing: return "" def _extract_mailu_token(payload: Any) -> dict[str, str]: if not isinstance(payload, dict): raise RuntimeError("Mailu token response was not a JSON object") token = payload.get("token") token_id = payload.get("id") if not token: nested = payload.get("result") if isinstance(nested, dict): token = nested.get("token") token_id = token_id or nested.get("id") if not token: raise RuntimeError("Mailu token response did not include a token") return {"token": str(token), "id": str(token_id) if token_id is not None else ""} def _send_email_sync( email_address: str, token: str, to: list[str], subject: str, text_body: str, cc: list[str], bcc: list[str], reply_to: str | None, smtp_host: str, smtp_port: int, ) -> dict[str, Any]: recipients = [addr for addr in [*to, *cc, *bcc] if addr] if not recipients: return {"ok": False, "error": "recipient_required"} message = EmailMessage() message["From"] = email_address message["To"] = ", ".join(to) if cc: message["Cc"] = ", ".join(cc) if reply_to: message["Reply-To"] = reply_to message["Subject"] = subject message["Date"] = formatdate(localtime=True) message["Message-ID"] = make_msgid(domain=email_address.split("@")[-1]) message.set_content(text_body) context = ssl.create_default_context() if smtp_port == 465: with smtplib.SMTP_SSL(smtp_host, smtp_port, timeout=30, context=context) as server: server.login(email_address, token) refused = server.send_message(message, from_addr=email_address, to_addrs=recipients) else: with smtplib.SMTP(smtp_host, smtp_port, timeout=30) as server: server.ehlo() server.starttls(context=context) server.ehlo() server.login(email_address, token) refused = server.send_message(message, from_addr=email_address, to_addrs=recipients) return { "ok": not bool(refused), "sent": not bool(refused), "from": email_address, "to": to, "cc": cc, "refused_recipients": refused, } def _read_inbox_sync( email_address: str, token: str, mailbox: str, limit: int, unread_only: bool, mark_seen: bool, max_body_chars: int, imap_host: str, imap_port: int, ) -> dict[str, Any]: limit = max(1, min(limit, 50)) messages: list[dict[str, Any]] = [] with imaplib.IMAP4_SSL(imap_host, imap_port, timeout=30) as imap: imap.login(email_address, token) status, _ = imap.select(mailbox, readonly=not mark_seen) if status != "OK": return {"ok": False, "error": "mailbox_select_failed", "mailbox": mailbox} criteria = "UNSEEN" if unread_only else "ALL" status, data = imap.uid("search", None, criteria) if status != "OK": return {"ok": False, "error": "search_failed", "mailbox": mailbox} uids = (data[0] or b"").split() for uid_bytes in reversed(uids[-limit:]): uid = uid_bytes.decode("ascii", errors="replace") fetch_item = "(FLAGS BODY[])" if mark_seen else "(FLAGS BODY.PEEK[])" status, fetched = imap.uid("fetch", uid, fetch_item) if status != "OK": messages.append({"uid": uid, "ok": False, "error": "fetch_failed"}) continue raw_message = _first_fetch_bytes(fetched) if raw_message is None: messages.append({"uid": uid, "ok": False, "error": "message_missing"}) continue parsed = BytesParser(policy=default_email_policy).parsebytes(raw_message) flags = _fetch_flags(fetched) messages.append(_message_summary(uid, parsed, flags, max_body_chars)) return { "ok": True, "mailbox": mailbox, "email": email_address, "count": len(messages), "messages": messages, } def _mark_email_read_sync( email_address: str, token: str, uid: str, mailbox: str, imap_host: str, imap_port: int, ) -> dict[str, Any]: with imaplib.IMAP4_SSL(imap_host, imap_port, timeout=30) as imap: imap.login(email_address, token) status, _ = imap.select(mailbox) if status != "OK": return {"ok": False, "error": "mailbox_select_failed", "mailbox": mailbox, "uid": uid} status, data = imap.uid("store", uid, "+FLAGS", "(\\Seen)") return { "ok": status == "OK", "mailbox": mailbox, "uid": uid, "result": [part.decode("utf-8", errors="replace") if isinstance(part, bytes) else part for part in data], } def _first_fetch_bytes(fetched: list[Any]) -> bytes | None: for item in fetched: if isinstance(item, tuple) and len(item) >= 2 and isinstance(item[1], bytes): return item[1] return None def _fetch_flags(fetched: list[Any]) -> list[str]: out: list[str] = [] for item in fetched: chunks = item if isinstance(item, tuple) else (item,) for chunk in chunks: if not isinstance(chunk, bytes): continue match = re.search(rb"FLAGS \(([^)]*)\)", chunk) if match: out.extend(flag.decode("ascii", errors="replace") for flag in match.group(1).split()) return sorted(set(out)) def _message_summary(uid: str, message: EmailMessage, flags: list[str], max_body_chars: int) -> dict[str, Any]: date_value = message.get("date") parsed_date = None if date_value: try: parsed_date = parsedate_to_datetime(date_value).isoformat() except (TypeError, ValueError): parsed_date = str(date_value) body = _plain_text_body(message) if max_body_chars >= 0: body = body[:max_body_chars] return { "uid": uid, "message_id": message.get("message-id"), "subject": _decode_header_value(message.get("subject")), "from": _decode_header_value(message.get("from")), "to": _decode_header_value(message.get("to")), "date": parsed_date, "flags": flags, "seen": "\\Seen" in flags, "body": body, } def _plain_text_body(message: EmailMessage) -> str: if message.is_multipart(): for part in message.walk(): if part.get_content_type() == "text/plain" and not part.get_filename(): return _part_text(part) for part in message.walk(): if part.get_content_type() == "text/html" and not part.get_filename(): return _part_text(part) return "" return _part_text(message) def _part_text(part: EmailMessage) -> str: try: content = part.get_content() except (LookupError, UnicodeDecodeError): payload = part.get_payload(decode=True) or b"" charset = part.get_content_charset() or "utf-8" return payload.decode(charset, errors="replace") return content if isinstance(content, str) else str(content) def _decode_header_value(value: str | None) -> str | None: if value is None: return None try: return str(make_header(decode_header(value))) except (LookupError, UnicodeDecodeError, ValueError): return value def _message_text(message: Any) -> Any: content = getattr(message, "content", message) return content def _message_to_dict(message: Any) -> dict[str, Any]: if isinstance(message, BaseMessage): return message.model_dump(mode="json") if hasattr(message, "model_dump"): return message.model_dump(mode="json") if isinstance(message, dict): return message return {"content": str(message)} agent = MailuOpenapiAgent()