Files
mailu-openapi-agent/agent.py
a2a-platform c2768d3117 deploy
2026-06-04 22:28:19 +00:00

1069 lines
66 KiB
Python

from __future__ import annotations
import base64
import json
import re
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 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'.", 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="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]:
tools: list[StructuredTool] = []
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.",
"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.",
"",
"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)
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 _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()