990 lines
70 KiB
Python
990 lines
70 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://tasks.a2acloud.io"
|
|
OPERATIONS = json.loads("{\n \"create_crm_entity\": {\n \"description\": \"Create Crm Entity\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_crm_entity\",\n \"parameters\": [],\n \"path\": \"/api/crm/entities\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmEntityCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_crm_entity\",\n \"summary\": \"Create Crm Entity\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"create_crm_pipeline\": {\n \"description\": \"Create Crm Pipeline\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_crm_pipeline\",\n \"parameters\": [],\n \"path\": \"/api/crm/pipelines\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_crm_pipeline\",\n \"summary\": \"Create Crm Pipeline\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"create_crm_pipeline_entry\": {\n \"description\": \"Create Crm Pipeline Entry\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_crm_pipeline_entry\",\n \"parameters\": [],\n \"path\": \"/api/crm/pipeline-entries\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineEntryCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_crm_pipeline_entry\",\n \"summary\": \"Create Crm Pipeline Entry\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"create_crm_pipeline_stage\": {\n \"description\": \"Create Crm Pipeline Stage\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_crm_pipeline_stage\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"pipeline_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Pipeline Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines/{pipeline_id}/stages\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineStageCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_crm_pipeline_stage\",\n \"summary\": \"Create Crm Pipeline Stage\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"create_epic\": {\n \"description\": \"Create Epic\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_epic\",\n \"parameters\": [],\n \"path\": \"/api/epics\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/EpicCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_epic\",\n \"summary\": \"Create Epic\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"create_task\": {\n \"description\": \"Create Task\",\n \"destructive\": true,\n \"method\": \"POST\",\n \"operation_id\": \"create_task\",\n \"parameters\": [],\n \"path\": \"/api/tasks\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/TaskCreate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"create_task\",\n \"summary\": \"Create Task\",\n \"tags\": [\n \"Tasks\"\n ]\n },\n \"delete_crm_entity\": {\n \"description\": \"Delete Crm Entity\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_crm_entity\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entity_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entity Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/entities/{entity_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_crm_entity\",\n \"summary\": \"Delete Crm Entity\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"delete_crm_pipeline\": {\n \"description\": \"Delete Crm Pipeline\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_crm_pipeline\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"pipeline_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Pipeline Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines/{pipeline_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_crm_pipeline\",\n \"summary\": \"Delete Crm Pipeline\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"delete_crm_pipeline_entry\": {\n \"description\": \"Delete Crm Pipeline Entry\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_crm_pipeline_entry\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entry_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entry Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-entries/{entry_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_crm_pipeline_entry\",\n \"summary\": \"Delete Crm Pipeline Entry\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"delete_crm_pipeline_stage\": {\n \"description\": \"Delete Crm Pipeline Stage\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_crm_pipeline_stage\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"stage_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Stage Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-stages/{stage_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_crm_pipeline_stage\",\n \"summary\": \"Delete Crm Pipeline Stage\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"delete_epic\": {\n \"description\": \"Delete Epic\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_epic\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"epic_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Epic Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/epics/{epic_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_epic\",\n \"summary\": \"Delete Epic\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"delete_task\": {\n \"description\": \"Delete Task\",\n \"destructive\": true,\n \"method\": \"DELETE\",\n \"operation_id\": \"delete_task\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"task_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Task Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/tasks/{task_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"delete_task\",\n \"summary\": \"Delete Task\",\n \"tags\": [\n \"Tasks\"\n ]\n },\n \"get_crm_entity\": {\n \"description\": \"Get Crm Entity\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_crm_entity\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entity_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entity Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/entities/{entity_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_crm_entity\",\n \"summary\": \"Get Crm Entity\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"get_crm_pipeline\": {\n \"description\": \"Get Crm Pipeline\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_crm_pipeline\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"pipeline_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Pipeline Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines/{pipeline_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_crm_pipeline\",\n \"summary\": \"Get Crm Pipeline\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"get_crm_pipeline_entry\": {\n \"description\": \"Get Crm Pipeline Entry\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_crm_pipeline_entry\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entry_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entry Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-entries/{entry_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_crm_pipeline_entry\",\n \"summary\": \"Get Crm Pipeline Entry\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"get_crm_pipeline_stage\": {\n \"description\": \"Get Crm Pipeline Stage\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_crm_pipeline_stage\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"stage_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Stage Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-stages/{stage_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_crm_pipeline_stage\",\n \"summary\": \"Get Crm Pipeline Stage\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"get_epic\": {\n \"description\": \"Get Epic\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_epic\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"epic_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Epic Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/epics/{epic_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_epic\",\n \"summary\": \"Get Epic\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"get_fuck_you\": {\n \"description\": \"Get Fuck You\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_fuck_you\",\n \"parameters\": [],\n \"path\": \"/api/fuck-you\",\n \"request_body\": null,\n \"security\": null,\n \"skill_name\": \"get_fuck_you\",\n \"summary\": \"Get Fuck You\",\n \"tags\": [\n \"Utility\"\n ]\n },\n \"get_task\": {\n \"description\": \"Get Task\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_task\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"task_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Task Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/tasks/{task_id}\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"get_task\",\n \"summary\": \"Get Task\",\n \"tags\": [\n \"Tasks\"\n ]\n },\n \"get_tasks_health\": {\n \"description\": \"Healthz\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"get_tasks_health\",\n \"parameters\": [],\n \"path\": \"/healthz\",\n \"request_body\": null,\n \"security\": null,\n \"skill_name\": \"get_tasks_health\",\n \"summary\": \"Healthz\",\n \"tags\": [\n \"Health\"\n ]\n },\n \"list_crm_entities\": {\n \"description\": \"List Crm Entities\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_crm_entities\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"kind\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 32,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Kind\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"q\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 120,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Q\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/crm/entities\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_crm_entities\",\n \"summary\": \"List Crm Entities\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"list_crm_pipeline_entries\": {\n \"description\": \"List Crm Pipeline Entries\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_crm_pipeline_entries\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"pipeline_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Pipeline Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"stage_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Stage Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"entity_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Entity Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"status\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"enum\": [\n \"active\",\n \"won\",\n \"lost\",\n \"archived\"\n ],\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Status\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-entries\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_crm_pipeline_entries\",\n \"summary\": \"List Crm Pipeline Entries\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"list_crm_pipeline_stages\": {\n \"description\": \"List Crm Pipeline Stages\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_crm_pipeline_stages\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"pipeline_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Pipeline Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines/{pipeline_id}/stages\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_crm_pipeline_stages\",\n \"summary\": \"List Crm Pipeline Stages\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"list_crm_pipelines\": {\n \"description\": \"List Crm Pipelines\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_crm_pipelines\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"kind\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 32,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Kind\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"entity_kind\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 32,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Entity Kind\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"q\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 120,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Q\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_crm_pipelines\",\n \"summary\": \"List Crm Pipelines\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"list_epic_tasks\": {\n \"description\": \"List Epic Tasks\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_epic_tasks\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"epic_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Epic Id\",\n \"type\": \"string\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"status\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"enum\": [\n \"todo\",\n \"in_progress\",\n \"done\",\n \"canceled\"\n ],\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Status\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"q\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 120,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Q\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"due_before\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Due Before\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/epics/{epic_id}/tasks\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_epic_tasks\",\n \"summary\": \"List Epic Tasks\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"list_epics\": {\n \"description\": \"List Epics\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_epics\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"status\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"enum\": [\n \"todo\",\n \"in_progress\",\n \"done\",\n \"canceled\"\n ],\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Status\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"q\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 120,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Q\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"due_before\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Due Before\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/epics\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_epics\",\n \"summary\": \"List Epics\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"list_tasks\": {\n \"description\": \"List Tasks\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"list_tasks\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"status\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"enum\": [\n \"todo\",\n \"in_progress\",\n \"done\",\n \"canceled\"\n ],\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Status\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"q\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 120,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Q\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"due_before\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Due Before\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"epic_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Epic Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"crm_entity_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Crm Entity Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"crm_pipeline_entry_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Crm Pipeline Entry Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 50,\n \"maximum\": 200,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n }\n ],\n \"path\": \"/api/tasks\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"list_tasks\",\n \"summary\": \"List Tasks\",\n \"tags\": [\n \"Tasks\"\n ]\n },\n \"search_tasks\": {\n \"description\": \"Search Tasks\",\n \"destructive\": false,\n \"method\": \"GET\",\n \"operation_id\": \"search_tasks\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"query\",\n \"required\": true,\n \"schema\": {\n \"maxLength\": 500,\n \"minLength\": 1,\n \"title\": \"Query\",\n \"type\": \"string\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"status\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"enum\": [\n \"todo\",\n \"in_progress\",\n \"done\",\n \"canceled\"\n ],\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Status\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"due_before\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Due Before\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"epic_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Epic Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"crm_entity_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Crm Entity Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"crm_pipeline_entry_id\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maxLength\": 36,\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Crm Pipeline Entry Id\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"limit\",\n \"required\": false,\n \"schema\": {\n \"default\": 10,\n \"maximum\": 50,\n \"minimum\": 1,\n \"title\": \"Limit\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"offset\",\n \"required\": false,\n \"schema\": {\n \"default\": 0,\n \"minimum\": 0,\n \"title\": \"Offset\",\n \"type\": \"integer\"\n }\n },\n {\n \"description\": \"\",\n \"in\": \"query\",\n \"name\": \"score_threshold\",\n \"required\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"maximum\": 1,\n \"minimum\": 0,\n \"type\": \"number\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"title\": \"Score Threshold\"\n }\n }\n ],\n \"path\": \"/api/tasks/search\",\n \"request_body\": null,\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"search_tasks\",\n \"summary\": \"Search Tasks\",\n \"tags\": [\n \"Tasks\"\n ]\n },\n \"update_crm_entity\": {\n \"description\": \"Update Crm Entity\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_crm_entity\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entity_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entity Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/entities/{entity_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmEntityUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_crm_entity\",\n \"summary\": \"Update Crm Entity\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"update_crm_pipeline\": {\n \"description\": \"Update Crm Pipeline\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_crm_pipeline\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"pipeline_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Pipeline Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipelines/{pipeline_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_crm_pipeline\",\n \"summary\": \"Update Crm Pipeline\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"update_crm_pipeline_entry\": {\n \"description\": \"Update Crm Pipeline Entry\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_crm_pipeline_entry\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"entry_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Entry Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-entries/{entry_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineEntryUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_crm_pipeline_entry\",\n \"summary\": \"Update Crm Pipeline Entry\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"update_crm_pipeline_stage\": {\n \"description\": \"Update Crm Pipeline Stage\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_crm_pipeline_stage\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"stage_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Stage Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/crm/pipeline-stages/{stage_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/CrmPipelineStageUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_crm_pipeline_stage\",\n \"summary\": \"Update Crm Pipeline Stage\",\n \"tags\": [\n \"CRM\"\n ]\n },\n \"update_epic\": {\n \"description\": \"Update Epic\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_epic\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"epic_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Epic Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/epics/{epic_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/EpicUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_epic\",\n \"summary\": \"Update Epic\",\n \"tags\": [\n \"Epics\"\n ]\n },\n \"update_task\": {\n \"description\": \"Update Task\",\n \"destructive\": true,\n \"method\": \"PATCH\",\n \"operation_id\": \"update_task\",\n \"parameters\": [\n {\n \"description\": \"\",\n \"in\": \"path\",\n \"name\": \"task_id\",\n \"required\": true,\n \"schema\": {\n \"title\": \"Task Id\",\n \"type\": \"string\"\n }\n }\n ],\n \"path\": \"/api/tasks/{task_id}\",\n \"request_body\": {\n \"$ref\": \"#/components/schemas/TaskUpdate\"\n },\n \"security\": [\n {\n \"bearerAuth\": []\n },\n {\n \"apiKeyAuth\": []\n }\n ],\n \"skill_name\": \"update_task\",\n \"summary\": \"Update Task\",\n \"tags\": [\n \"Tasks\"\n ]\n }\n}")
|
|
ROOT_SECURITY = json.loads("[]")
|
|
SECURITY_SCHEMES = json.loads("{\n \"apiKeyAuth\": {\n \"description\": \"Use the configured `TASKS_API_KEY` value.\",\n \"in\": \"header\",\n \"name\": \"x-api-key\",\n \"type\": \"apiKey\"\n },\n \"bearerAuth\": {\n \"description\": \"Use `Authorization: Bearer $TASKS_API_KEY`.\",\n \"scheme\": \"bearer\",\n \"type\": \"http\"\n }\n}")
|
|
SECURITY_FIELDS = json.loads("{\n \"apiKeyAuth\": {\n \"field\": \"X_API_KEY\",\n \"kind\": \"apiKey\",\n \"location\": \"header\",\n \"name\": \"x-api-key\"\n },\n \"bearerAuth\": {\n \"field\": \"BEARERAUTH_TOKEN\",\n \"kind\": \"http\",\n \"scheme\": \"bearer\"\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 TasksApi(A2AAgent):
|
|
name = "tasks-api"
|
|
description = "API-only service for tracking tasks in Postgres."
|
|
version = "0.1.0"
|
|
consumer_setup = ConsumerSetup.from_fields(
|
|
ConsumerSetupField.config("OPENAPI_BASE_URL", label="API base URL", description="Override the default API server (https://tasks.a2acloud.io).", required=False, input_type="url"),
|
|
ConsumerSetupField.secret("BEARERAUTH_TOKEN", label="bearerAuth bearer credential", description="Use `Authorization: Bearer $TASKS_API_KEY`.", required=True),
|
|
ConsumerSetupField.secret("X_API_KEY", label="apiKeyAuth API key", description="Use the configured `TASKS_API_KEY` value.", required=True),
|
|
)
|
|
llm_provisioning = LLMProvisioning.PLATFORM
|
|
pricing = Pricing(
|
|
price_per_call_usd=0.0,
|
|
caller_pays_llm=True,
|
|
notes="Uses the caller's saved LLM credential through ctx.llm.",
|
|
)
|
|
resources = Resources(cpu="200m", memory="512Mi")
|
|
egress = EgressPolicy(
|
|
allow_hosts=('tasks.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://tasks.a2acloud.io/openapi.json',
|
|
"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 key required. Add an LLM credential in Settings > "
|
|
"LLM credentials before running this agent."
|
|
),
|
|
"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="get_fuck_you",
|
|
description="GET /api/fuck-you - Get Fuck You",
|
|
tags=('Utility',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_fuck_you(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_fuck_you",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_tasks_health",
|
|
description="GET /healthz - Healthz",
|
|
tags=('Health',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_tasks_health(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_tasks_health",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_crm_entities",
|
|
description="GET /api/crm/entities - List Crm Entities",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_crm_entities(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_crm_entities",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_crm_entity",
|
|
description="POST /api/crm/entities - Create Crm Entity",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_crm_entity(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_crm_entity",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_crm_entity",
|
|
description="GET /api/crm/entities/{entity_id} - Get Crm Entity",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_crm_entity(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_crm_entity",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_crm_entity",
|
|
description="PATCH /api/crm/entities/{entity_id} - Update Crm Entity",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_crm_entity(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_crm_entity",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_crm_entity",
|
|
description="DELETE /api/crm/entities/{entity_id} - Delete Crm Entity",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_crm_entity(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_crm_entity",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_crm_pipelines",
|
|
description="GET /api/crm/pipelines - List Crm Pipelines",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_crm_pipelines(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_crm_pipelines",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_crm_pipeline",
|
|
description="POST /api/crm/pipelines - Create Crm Pipeline",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_crm_pipeline(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_crm_pipeline",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_crm_pipeline",
|
|
description="GET /api/crm/pipelines/{pipeline_id} - Get Crm Pipeline",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_crm_pipeline(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_crm_pipeline",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_crm_pipeline",
|
|
description="PATCH /api/crm/pipelines/{pipeline_id} - Update Crm Pipeline",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_crm_pipeline(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_crm_pipeline",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_crm_pipeline",
|
|
description="DELETE /api/crm/pipelines/{pipeline_id} - Delete Crm Pipeline",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_crm_pipeline(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_crm_pipeline",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_crm_pipeline_stages",
|
|
description="GET /api/crm/pipelines/{pipeline_id}/stages - List Crm Pipeline Stages",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_crm_pipeline_stages(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_crm_pipeline_stages",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_crm_pipeline_stage",
|
|
description="POST /api/crm/pipelines/{pipeline_id}/stages - Create Crm Pipeline Stage",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_crm_pipeline_stage(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_crm_pipeline_stage",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_crm_pipeline_stage",
|
|
description="GET /api/crm/pipeline-stages/{stage_id} - Get Crm Pipeline Stage",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_crm_pipeline_stage(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_crm_pipeline_stage",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_crm_pipeline_stage",
|
|
description="PATCH /api/crm/pipeline-stages/{stage_id} - Update Crm Pipeline Stage",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_crm_pipeline_stage(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_crm_pipeline_stage",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_crm_pipeline_stage",
|
|
description="DELETE /api/crm/pipeline-stages/{stage_id} - Delete Crm Pipeline Stage",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_crm_pipeline_stage(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_crm_pipeline_stage",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_crm_pipeline_entries",
|
|
description="GET /api/crm/pipeline-entries - List Crm Pipeline Entries",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_crm_pipeline_entries(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_crm_pipeline_entries",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_crm_pipeline_entry",
|
|
description="POST /api/crm/pipeline-entries - Create Crm Pipeline Entry",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_crm_pipeline_entry(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_crm_pipeline_entry",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_crm_pipeline_entry",
|
|
description="GET /api/crm/pipeline-entries/{entry_id} - Get Crm Pipeline Entry",
|
|
tags=('CRM',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_crm_pipeline_entry(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_crm_pipeline_entry",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_crm_pipeline_entry",
|
|
description="PATCH /api/crm/pipeline-entries/{entry_id} - Update Crm Pipeline Entry",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_crm_pipeline_entry(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_crm_pipeline_entry",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_crm_pipeline_entry",
|
|
description="DELETE /api/crm/pipeline-entries/{entry_id} - Delete Crm Pipeline Entry",
|
|
tags=('CRM',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_crm_pipeline_entry(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_crm_pipeline_entry",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_epics",
|
|
description="GET /api/epics - List Epics",
|
|
tags=('Epics',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_epics(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_epics",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_epic",
|
|
description="POST /api/epics - Create Epic",
|
|
tags=('Epics',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_epic(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_epic",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_epic",
|
|
description="GET /api/epics/{epic_id} - Get Epic",
|
|
tags=('Epics',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_epic(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_epic",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_epic",
|
|
description="PATCH /api/epics/{epic_id} - Update Epic",
|
|
tags=('Epics',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_epic(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_epic",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_epic",
|
|
description="DELETE /api/epics/{epic_id} - Delete Epic",
|
|
tags=('Epics',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_epic(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_epic",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_epic_tasks",
|
|
description="GET /api/epics/{epic_id}/tasks - List Epic Tasks",
|
|
tags=('Epics',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_epic_tasks(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_epic_tasks",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="list_tasks",
|
|
description="GET /api/tasks - List Tasks",
|
|
tags=('Tasks',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def list_tasks(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"list_tasks",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="create_task",
|
|
description="POST /api/tasks - Create Task",
|
|
tags=('Tasks',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def create_task(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"create_task",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="search_tasks",
|
|
description="GET /api/tasks/search - Search Tasks",
|
|
tags=('Tasks',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def search_tasks(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"search_tasks",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="get_task",
|
|
description="GET /api/tasks/{task_id} - Get Task",
|
|
tags=('Tasks',),
|
|
timeout_seconds=60,
|
|
)
|
|
async def get_task(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"get_task",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="update_task",
|
|
description="PATCH /api/tasks/{task_id} - Update Task",
|
|
tags=('Tasks',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def update_task(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"update_task",
|
|
parameters=parameters or {},
|
|
body=body,
|
|
)
|
|
|
|
@skill(
|
|
name="delete_task",
|
|
description="DELETE /api/tasks/{task_id} - Delete Task",
|
|
tags=('Tasks',),
|
|
timeout_seconds=120,
|
|
)
|
|
async def delete_task(
|
|
self,
|
|
ctx: RunContext,
|
|
parameters: dict[str, Any] | None = None,
|
|
body: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
return await self._request(
|
|
ctx,
|
|
"delete_task",
|
|
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]
|
|
base_url = str(ctx.consumer_config("OPENAPI_BASE_URL", 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 = TasksApi()
|