This commit is contained in:
a2a-platform
2026-07-13 13:04:27 +00:00
parent 7b11b4c104
commit 9a2e64285d
3 changed files with 104 additions and 30 deletions

View File

@@ -3,7 +3,7 @@
"language": "python", "language": "python",
"name": "customer-integration-engineer", "name": "customer-integration-engineer",
"description": "Guides and validates customer integrations from requirements through a tested handoff while keeping credentials and production changes under customer control.", "description": "Guides and validates customer integrations from requirements through a tested handoff while keeping credentials and production changes under customer control.",
"version": "0.1.5", "version": "0.1.6",
"entrypoint": { "entrypoint": {
"module": "agent", "module": "agent",
"class_name": "CustomerIntegrationEngineer", "class_name": "CustomerIntegrationEngineer",
@@ -24,11 +24,15 @@
"max_retries": 0, "max_retries": 0,
"cost_class": "deterministic", "cost_class": "deterministic",
"allow_scope_expansion": false, "allow_scope_expansion": false,
"grant_mode": null, "grant_mode": "read_write_overlay",
"grant_allow_patterns": [], "grant_allow_patterns": [
"outputs/integrations/**"
],
"grant_deny_patterns": [], "grant_deny_patterns": [],
"grant_outputs_prefix": null, "grant_outputs_prefix": "outputs/integrations/",
"grant_write_prefixes": [], "grant_write_prefixes": [
"outputs/integrations/"
],
"grant_ttl_seconds": null, "grant_ttl_seconds": null,
"grant_run_timeout_seconds": null, "grant_run_timeout_seconds": null,
"grant_approval_timeout_seconds": null, "grant_approval_timeout_seconds": null,
@@ -820,11 +824,15 @@
"max_retries": 0, "max_retries": 0,
"cost_class": "deterministic", "cost_class": "deterministic",
"allow_scope_expansion": false, "allow_scope_expansion": false,
"grant_mode": null, "grant_mode": "read_write_overlay",
"grant_allow_patterns": [], "grant_allow_patterns": [
"outputs/integrations/**"
],
"grant_deny_patterns": [], "grant_deny_patterns": [],
"grant_outputs_prefix": null, "grant_outputs_prefix": "outputs/integrations/",
"grant_write_prefixes": [], "grant_write_prefixes": [
"outputs/integrations/"
],
"grant_ttl_seconds": null, "grant_ttl_seconds": null,
"grant_run_timeout_seconds": null, "grant_run_timeout_seconds": null,
"grant_approval_timeout_seconds": null, "grant_approval_timeout_seconds": null,
@@ -1637,11 +1645,15 @@
"max_retries": 0, "max_retries": 0,
"cost_class": "deterministic", "cost_class": "deterministic",
"allow_scope_expansion": false, "allow_scope_expansion": false,
"grant_mode": null, "grant_mode": "read_write_overlay",
"grant_allow_patterns": [], "grant_allow_patterns": [
"outputs/integrations/**"
],
"grant_deny_patterns": [], "grant_deny_patterns": [],
"grant_outputs_prefix": null, "grant_outputs_prefix": "outputs/integrations/",
"grant_write_prefixes": [], "grant_write_prefixes": [
"outputs/integrations/"
],
"grant_ttl_seconds": null, "grant_ttl_seconds": null,
"grant_run_timeout_seconds": null, "grant_run_timeout_seconds": null,
"grant_approval_timeout_seconds": null, "grant_approval_timeout_seconds": null,
@@ -1987,11 +1999,15 @@
"max_retries": 0, "max_retries": 0,
"cost_class": "deterministic", "cost_class": "deterministic",
"allow_scope_expansion": false, "allow_scope_expansion": false,
"grant_mode": null, "grant_mode": "read_write_overlay",
"grant_allow_patterns": [], "grant_allow_patterns": [
"outputs/integrations/**"
],
"grant_deny_patterns": [], "grant_deny_patterns": [],
"grant_outputs_prefix": null, "grant_outputs_prefix": "outputs/integrations/",
"grant_write_prefixes": [], "grant_write_prefixes": [
"outputs/integrations/"
],
"grant_ttl_seconds": null, "grant_ttl_seconds": null,
"grant_run_timeout_seconds": null, "grant_run_timeout_seconds": null,
"grant_approval_timeout_seconds": null, "grant_approval_timeout_seconds": null,
@@ -2496,11 +2512,15 @@
"max_retries": 0, "max_retries": 0,
"cost_class": "deterministic", "cost_class": "deterministic",
"allow_scope_expansion": false, "allow_scope_expansion": false,
"grant_mode": null, "grant_mode": "read_write_overlay",
"grant_allow_patterns": [], "grant_allow_patterns": [
"outputs/integrations/**"
],
"grant_deny_patterns": [], "grant_deny_patterns": [],
"grant_outputs_prefix": null, "grant_outputs_prefix": "outputs/integrations/",
"grant_write_prefixes": [], "grant_write_prefixes": [
"outputs/integrations/"
],
"grant_ttl_seconds": null, "grant_ttl_seconds": null,
"grant_run_timeout_seconds": null, "grant_run_timeout_seconds": null,
"grant_approval_timeout_seconds": null, "grant_approval_timeout_seconds": null,
@@ -2968,7 +2988,7 @@
"source": "python-a2a-pack", "source": "python-a2a-pack",
"project_manifest": { "project_manifest": {
"name": "customer-integration-engineer", "name": "customer-integration-engineer",
"version": "0.1.5", "version": "0.1.6",
"entrypoint": "agent:CustomerIntegrationEngineer" "entrypoint": "agent:CustomerIntegrationEngineer"
} }
} }

View File

@@ -1,5 +1,5 @@
name: customer-integration-engineer name: customer-integration-engineer
version: 0.1.5 version: 0.1.6
entrypoint: agent:CustomerIntegrationEngineer entrypoint: agent:CustomerIntegrationEngineer
expose: expose:
public: false public: false

View File

@@ -14,7 +14,6 @@ import ipaddress
import json import json
import re import re
import socket import socket
import time
from datetime import UTC, datetime from datetime import UTC, datetime
from typing import Any, Literal from typing import Any, Literal
from urllib.parse import urlparse from urllib.parse import urlparse
@@ -410,7 +409,7 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
"Guides and validates customer integrations from requirements through a tested handoff while " "Guides and validates customer integrations from requirements through a tested handoff while "
"keeping credentials and production changes under customer control." "keeping credentials and production changes under customer control."
) )
version = "0.1.5" version = "0.1.6"
config_model = CustomerIntegrationEngineerConfig config_model = CustomerIntegrationEngineerConfig
auth_model = NoAuth auth_model = NoAuth
@@ -440,7 +439,18 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
ConsumerSetupField.config("ARGOCD_APP_REF", label="Argo CD app reference", description="Optional caller-owned Argo CD app reference.", required=False), ConsumerSetupField.config("ARGOCD_APP_REF", label="Argo CD app reference", description="Optional caller-owned Argo CD app reference.", required=False),
) )
@a2a.tool(description="Capture requirements, produce architecture and field mapping artifacts", input_schema=_tool_input_schema(DesignIntegrationRequest), timeout_seconds=120, idempotent=True, max_retries=0, cost_class="deterministic") @a2a.tool(
description="Capture requirements, produce architecture and field mapping artifacts",
input_schema=_tool_input_schema(DesignIntegrationRequest),
timeout_seconds=120,
idempotent=True,
max_retries=0,
cost_class="deterministic",
grant_mode="read_write_overlay",
grant_allow_patterns=("outputs/integrations/**",),
grant_outputs_prefix="outputs/integrations/",
grant_write_prefixes=("outputs/integrations/",),
)
async def design_integration(self, ctx: RunContext[NoAuth], request: DesignIntegrationRequest) -> DesignIntegrationResult: async def design_integration(self, ctx: RunContext[NoAuth], request: DesignIntegrationRequest) -> DesignIntegrationResult:
req = request.requirements.model_copy( req = request.requirements.model_copy(
update={"dry_run": _effective_dry_run(self, request.dry_run, request.requirements.dry_run)} update={"dry_run": _effective_dry_run(self, request.dry_run, request.requirements.dry_run)}
@@ -478,7 +488,18 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
required_setup=required_setup, required_setup=required_setup,
) )
@a2a.tool(description="Generate a minimal workspace-contained connector scaffold with no deployment or repository mutation", input_schema=_tool_input_schema(GenerateConnectorRequest), timeout_seconds=120, idempotent=True, max_retries=0, cost_class="deterministic") @a2a.tool(
description="Generate a minimal workspace-contained connector scaffold with no deployment or repository mutation",
input_schema=_tool_input_schema(GenerateConnectorRequest),
timeout_seconds=120,
idempotent=True,
max_retries=0,
cost_class="deterministic",
grant_mode="read_write_overlay",
grant_allow_patterns=("outputs/integrations/**",),
grant_outputs_prefix="outputs/integrations/",
grant_write_prefixes=("outputs/integrations/",),
)
async def generate_connector(self, ctx: RunContext[NoAuth], request: GenerateConnectorRequest) -> GenerateConnectorResult: async def generate_connector(self, ctx: RunContext[NoAuth], request: GenerateConnectorRequest) -> GenerateConnectorResult:
req = request.requirements.model_copy( req = request.requirements.model_copy(
update={"dry_run": _effective_dry_run(self, request.dry_run, request.requirements.dry_run)} update={"dry_run": _effective_dry_run(self, request.dry_run, request.requirements.dry_run)}
@@ -532,7 +553,18 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
blocked_actions=blocked_actions, blocked_actions=blocked_actions,
) )
@a2a.tool(description="Validate OpenAPI, JSON Schema, and webhook contracts with deterministic fixtures", input_schema=_tool_input_schema(ValidateContractRequest), timeout_seconds=120, idempotent=True, max_retries=0, cost_class="deterministic") @a2a.tool(
description="Validate OpenAPI, JSON Schema, and webhook contracts with deterministic fixtures",
input_schema=_tool_input_schema(ValidateContractRequest),
timeout_seconds=120,
idempotent=True,
max_retries=0,
cost_class="deterministic",
grant_mode="read_write_overlay",
grant_allow_patterns=("outputs/integrations/**",),
grant_outputs_prefix="outputs/integrations/",
grant_write_prefixes=("outputs/integrations/",),
)
async def validate_contract(self, ctx: RunContext[NoAuth], request: ValidateContractRequest) -> ValidateContractResult: async def validate_contract(self, ctx: RunContext[NoAuth], request: ValidateContractRequest) -> ValidateContractResult:
dry_run = _effective_dry_run(self, request.dry_run) dry_run = _effective_dry_run(self, request.dry_run)
audit = [_audit("contract_validation_started", request.integration_id, {"contracts": len(request.contracts), "dry_run": dry_run})] audit = [_audit("contract_validation_started", request.integration_id, {"contracts": len(request.contracts), "dry_run": dry_run})]
@@ -564,7 +596,18 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
drift_detected=drift, drift_detected=drift,
) )
@a2a.tool(description="Run dry-run or allowlisted acceptance checks using endpoint metadata and secret references", input_schema=_tool_input_schema(RunAcceptanceRequest), timeout_seconds=180, idempotent=True, max_retries=0, cost_class="deterministic") @a2a.tool(
description="Run dry-run or allowlisted acceptance checks using endpoint metadata and secret references",
input_schema=_tool_input_schema(RunAcceptanceRequest),
timeout_seconds=180,
idempotent=True,
max_retries=0,
cost_class="deterministic",
grant_mode="read_write_overlay",
grant_allow_patterns=("outputs/integrations/**",),
grant_outputs_prefix="outputs/integrations/",
grant_write_prefixes=("outputs/integrations/",),
)
async def run_acceptance(self, ctx: RunContext[NoAuth], request: RunAcceptanceRequest) -> RunAcceptanceResult: async def run_acceptance(self, ctx: RunContext[NoAuth], request: RunAcceptanceRequest) -> RunAcceptanceResult:
dry_run = _effective_dry_run(self, request.dry_run) dry_run = _effective_dry_run(self, request.dry_run)
live_network_block = _live_network_unavailable_reason(self) live_network_block = _live_network_unavailable_reason(self)
@@ -635,7 +678,18 @@ class CustomerIntegrationEngineer(A2AAgent[CustomerIntegrationEngineerConfig, No
network_calls_made=network_calls, network_calls_made=network_calls,
) )
@a2a.tool(description="Prepare rollout, rollback, monitoring, and operator handoff documentation with approval-gated delivery planning", input_schema=_tool_input_schema(PrepareHandoffRequest), timeout_seconds=120, idempotent=True, max_retries=0, cost_class="deterministic") @a2a.tool(
description="Prepare rollout, rollback, monitoring, and operator handoff documentation with approval-gated delivery planning",
input_schema=_tool_input_schema(PrepareHandoffRequest),
timeout_seconds=120,
idempotent=True,
max_retries=0,
cost_class="deterministic",
grant_mode="read_write_overlay",
grant_allow_patterns=("outputs/integrations/**",),
grant_outputs_prefix="outputs/integrations/",
grant_write_prefixes=("outputs/integrations/",),
)
async def prepare_handoff(self, ctx: RunContext[NoAuth], request: PrepareHandoffRequest) -> PrepareHandoffResult: async def prepare_handoff(self, ctx: RunContext[NoAuth], request: PrepareHandoffRequest) -> PrepareHandoffResult:
dry_run = _effective_dry_run(self, request.dry_run) dry_run = _effective_dry_run(self, request.dry_run)
audit = [_audit("handoff_started", request.integration_id, {"dry_run": dry_run, "delivery_actions": len(request.delivery_actions)})] audit = [_audit("handoff_started", request.integration_id, {"dry_run": dry_run, "delivery_actions": len(request.delivery_actions)})]