1.1 Two Teams, Two Agents — Orchestration vs. Specialization (ADK & A2A)¶
When our loan officer asks, "Can you verify Julian Sterling's income?", the first workload to wake up is an AI agent.
In a laptop prototype, a single agent usually handles everything: chatting with the user, knowing every underwriting rule, and calling every backend database. In an enterprise, however, the team that owns the customer channel is rarely the team that owns core mortgage underwriting.
This section explains how Esmeralda splits reasoning across two specialized agents owned by two independent teams—the CX Mortgage Orchestrator (cx-mortgage-orchestrator) and the AI CoE Mortgage Specialist (ai-coe-mortgage-specialist)—how both run as Bring-Your-Own-Container (BYOC) workloads on Vertex AI Agent Runtime, and how multi-turn conversation context is persisted in managed Vertex AI Sessions without provisioning an external database.
1. Orchestrators Meet Specialists¶
Think of how a modern financial institution is organized:
- The Customer Experience (CX) Team builds conversational assistants for web portals, mobile apps, and loan-officer desktops. They care about user intent, tone, session continuity, and routing questions to the right department.
- The AI Center of Excellence (AI CoE) Team builds deep domain capabilities—such as mortgage underwriting, fraud analysis, or credit scoring—that should be built once, audited rigorously, and reused by every customer channel across the bank.
In Esmeralda, each team owns its own agent inside its own isolated GCP project:
| Agent | Owning Team | Role in Julian Sterling's Request | GCP Project | Terraform Module |
|---|---|---|---|---|
cx-mortgage-orchestrator |
CX Product Team | User-facing Google ADK orchestrator. Greets the loan officer, understands that the request requires mortgage underwriting, and delegates the task. | esm-<env>-cx-agents-<sfx> |
modules/5-workloads/agents/adk-agent |
ai-coe-mortgage-specialist |
AI CoE Team | Reusable A2A (Agent-to-Agent) specialist. Advertises its skills (Document Search, Income Verification, Corporate Email) in an Agent Card and calls the MCP tool servers to verify Julian Sterling's file. | esm-<env>-ai-coe-agents-<sfx> |
modules/5-workloads/agents/a2a-agent |
What is Vertex AI Agent Engine (Agent Runtime) with BYOC?¶
Both agents run on Vertex AI Agent Engine (also called Agent Runtime), Google Cloud's managed, serverless runtime for AI agents. Each deployed agent is a ReasoningEngine resource.
Rather than uploading raw Python pickles, Esmeralda uses BYOC (Bring Your Own Container): you build a standard, immutable Docker image with uv and the esmeralda runtime library, and Agent Runtime executes that container inside an isolated micro-VM with a cryptographic SPIFFE Agent Identity (identity_type = AGENT_IDENTITY) and a mandatory binding to the Central Agent Gateway.
Following Julian Sterling's Request Across Both Agents¶
sequenceDiagram
autonumber
participant Client as Loan Officer / Client
participant Orch as cx-mortgage-orchestrator (CX)
participant AGW as Central Agent Gateway (Layer 4)
participant EP as Entry Point (*.esmeralda.internal, direct)
participant Spec as ai-coe-mortgage-specialist (AI CoE)
participant DMS as legacy-dms (Cloud Run MCP)
Client->>Orch: 1. streamQuery ("Can you verify Julian Sterling's income?")
Orch->>Orch: 2. transfer_to_agent -> mortgage_tools_agent (RemoteA2aAgent)
Orch->>AGW: 3. A2A task to ai-coe-mortgage-specialist.esmeralda.internal (caller's access token)
AGW->>EP: 4. Agent Registry + iap.egressor check -> PSC to internal LB
EP->>Spec: 5. Route by Host: PSC NEG to Agent Runtime, host + path rewrite
Spec->>AGW: 6. MCP tools/call search_documents & verify_applicant (caller's ID token)
AGW->>EP: 7. Same governance checks & private path
EP->>DMS: 8. Route by Host: serverless NEG, Cloud Run IAM checks ID token
DMS-->>Spec: 9. Julian Sterling's W-2, tax return & payroll verification
Spec-->>Orch: 10. Structured A2A underwriting assessment
Orch-->>Client: 11. Final verification response stream
How each hop is authorized and how private TLS certificates work on this path is detailed in 2.1 Central Agent Gateway §4.
2. Why We Designed It This Way: Key Decisions & Trade-offs¶
In many organizations, deploying a multi-agent workflow requires coordinating across separate platform, networking, and security silos. Esmeralda eliminates those handoffs through deliberate design choices:
| Decision | Why We Made It | What We Avoided |
|---|---|---|
Separate GCP Projects per Agent Team (cx-agents vs. ai-coe-agents) |
Isolates IAM permissions, SPIFFE principal sets, model quotas, and FinOps token chargeback per department. The CX team consumes the specialist solely via its *.esmeralda.internal URL. |
Cross-team IAM tangles where a bug in a customer chatbot can access another team's storage or exhaust its quota. |
| BYOC Containers Pinned by SHA-256 Digest | Guarantees that the exact container bytes tested in dev are promoted to prd (release/prd.yaml), with zero environment secrets or certificates baked into the image. |
"Works in dev, breaks in prod" drift caused by rebuilding Python dependencies or pickle payloads per environment. |
Managed ADK Sessions Keyed by A2A context_id |
Persists multi-turn conversation history in Vertex AI Agent Engine managed sessions (VertexAiSessionService) keyed by the A2A context_id, while keeping transient A2A task state (InMemoryTaskStore) in process with max_instances: 1. |
Paying 24/7 for an idle relational database instance and managing VPC database bootstrap jobs just to preserve multi-turn chat context. |
Clear Team Boundaries¶
| Engineering Persona | Role & Daily Responsibilities | What They Own | What They NEVER Touch |
|---|---|---|---|
| AI Reasoning Engineer (CX or AI CoE Team) | Prompt engineering, multi-agent delegation, tool orchestration, and response quality evaluation. | apps/agents/<agent>/ (Python/ADK code, Dockerfile, agent.yaml). Shared SDK: packages/esmeralda/. |
VPC subnetting, KMS keys, or IAM project bindings. |
| Platform Lead | Ensuring zero public IPs, digest-pinned BYOC deployments, and private gateway routing. | infrastructure/modules/5-workloads/agents/, gateway backends, and entry point routing. |
Agent prompt engineering or LLM temperature settings. |
| SecOps / Identity Auditor | Enforcing cryptographic SPIFFE Agent Identity and per-target Agent Gateway egress policies. | Service accounts (sa-cx-mortgage-orch-<env>, sa-ai-coe-mortgage-spec-<env>), Agent Identity grants and per-caller invoke grants. |
Python business logic. |
3. How It Works & CLI in Practice¶
Capabilities Common to Both Agents (infrastructure/modules/5-workloads/agents/)¶
- BYOC Image Promotion: Built with
make build-ai-coe-mortgage-specialist/make build-cx-mortgage-orchestratorinto the shared Layer 0 CI/CD Artifact Registry. Terraform pinscontainer_spec.image_urito an immutable SHA-256 digest: indevit resolves the tag fromenv.yaml(container_tag); inprdit reads the verified digest fromrelease/prd.yaml. - Cryptographic SPIFFE Agent Identity: Setting
identity_type = AGENT_IDENTITYassigns each engine a verifiable identity. IAM and egress grants target the team project's principal set (principalSet://agents.global.org-<ORG>.system.id.goog/attribute.platformContainer/aiplatform/projects/<PROJECT_NUMBER>), keeping CX and AI CoE authorization completely separate. - Central Agent Gateway Binding:
deployment_spec.agent_gateway_config.agent_to_anywhere_config.agent_gatewaybinds the runtime to the Layer 4 gateway. When bound, the module omitspsc_interface_configso 100% of outbound traffic (Gemini, Google APIs, MCP tools, A2A) traverses the Central Agent Gateway. - Runtime Trust Bundle Injection: The Layer 4 certificate bundle (gateway inspection roots + Esmeralda's internal Root CA) is injected via
AGENT_GATEWAY_ROOT_CERTIFICATESand installed into the container's trust store at startup by theesmeralda runentrypoint (see 2.1 Central Agent Gateway §6). - Automatic Credential Selection for
*.esmeralda.internal:SERVICE_ACCOUNT_EMAILis not set, so the agent mints its outbound tokens as its own Agent Identity, in the exact token kind required by each target host: an ID token for Cloud Run MCP hosts (requested unbound withbind_id_token=False, see Outbound tokens and the Agent Gateway) and an OAuth2 access token for Agent Runtime hosts served by thedirectbackend. Each callee grants the calling agent'sprincipal://from the catalogcallers.esmeralda.auth.token_kind(url)selects the token automatically fromACCESS_TOKEN_HOSTS, which Terraform populates from the service catalog (see 1.3 Entry Point → Token Kinds). The deprecatedlegacy_shared_invoker = truefallback (env.yaml, one release) setsSERVICE_ACCOUNT_EMAILto the sharedsa-mcp-invoker-<env>again. - Per-Agent Storage & Analytics: Provisions dedicated staging, artifacts, and logs Cloud Storage buckets, plus a BigQuery dataset (
<agent>_logs_<env>) wired into central FinOps views. - Declarative
agent.yamlContract:apps/agents/<agent>/agent.yamldefines the agent's name, compute scaling (CPU, memory, min/max instances, concurrency), skills, and default environment variables, while Terraform overlays live environment URLs and certificates at deploy time.
Inside the AI CoE Mortgage Specialist (agents/a2a-agent/main.tf)¶
- A2A Protocol Server: Exposes the standard Agent-to-Agent JSON-RPC methods (
on_message_send,handle_authenticated_agent_card,on_get_task,on_cancel_task) alongside the Agent Card declared inagent.yaml(advertising Document Search, Income Verification, and Corporate Email skills). - Agent Card in Agent Registry:
google_agent_registry_service.agent_cardregisters the specialist (A2A_AGENT_CARD, URLhttps://ai-coe-mortgage-specialist.esmeralda.internal) in the central governance project's Agent Registry—the exact allowlist entry that authorizes the CX orchestrator to call it through the Central Agent Gateway. - MCP Tool Bindings: Injects
DMS_MCP_URL,INCOME_VERIFICATION_URL, andEMAIL_MCP_URLpointing athttps://<svc>.esmeralda.internal/mcp(detailed in 1.2 MCP Tool Servers). - Managed Sessions vs. In-Memory Task Store: Multi-turn conversation history across follow-up A2A calls sharing a
context_idis stored in Vertex AI managed sessions (VertexAiSessionService, enabled byUSE_IN_MEMORY_SESSIONS: "0"inagent.yaml), while A2ATaskobjects (task_idstatus and artifacts) useInMemoryTaskStoreby default.
Info
Single-Worker & max_instances: 1 Invariant for In-Memory A2A Task Stores: Because InMemoryTaskStore is per-process, A2A agents that do not export a custom a2a_task_store_builder must run a single uvicorn worker process with resources.max_instances: 1 in agent.yaml (esmeralda serve and esmeralda contracts warn if max_instances > 1 without a custom builder). Follow-up messages in the same context_id always resolve their conversation history from VertexAiSessionService; a shared TaskStore (a2a_task_store_builder) is only needed if you scale max_instances > 1 while relying on cross-instance tasks/get polling, stream resubscribe, or resuming input-required tasks.
Inside the CX Mortgage Orchestrator (agents/adk-agent/main.tf)¶
- Google ADK Coordinator: Defines an ADK
Agentnamedcx_mortgage_orchestrator(exported asroot_agent) equipped with aRemoteA2aAgentsub-agent (mortgage_tools_agent). At runtime, it fetches the specialist's Agent Card from${A2A_AGENT_URL}/v1/cardand delegates underwriting queries viatransfer_to_agent. Because it is stateless, it provisions no database. - Entry-Point URL Pinning: Although the specialist's Agent Card reports its internal
aiplatform.googleapis.comresource URL,esmeralda.a2a.remote_agentpins every outbound RPC toA2A_AGENT_URL(https://ai-coe-mortgage-specialist.esmeralda.internal), ensuring all traffic flows through the Central Agent Gateway and the private entry point. - Consumer, Not Owner: The CX team never deploys or configures the specialist or the MCP servers. It only needs the specialist's internal hostname, its Agent Registry entry, and an
iap.egressorgrant for the CX project's agent identities.
Running & Verifying Agents in Practice¶
1. Local Iteration & Live Queries (uv run esmeralda)¶
Use the esmeralda CLI to test either agent locally (automatically launching local FastMCP servers) or to inspect logs and verify deployed engines:
# Query the CX orchestrator locally (delegates to the specialist & local MCP tools)
uv run esmeralda query apps/agents/cx-mortgage-orchestrator \
-q "Can you verify Julian Sterling's income?"
# Query the AI CoE specialist directly during prompt development
uv run esmeralda query apps/agents/ai-coe-mortgage-specialist \
-q "Check Julian Sterling's income and tax documents."
# Plan or apply an agent unit in dev
uv run esmeralda plan layer-5-workloads/agents/cx-mortgage-orchestrator --env dev
uv run esmeralda apply layer-5-workloads/agents/cx-mortgage-orchestrator --env dev
# Stream structured agent logs or run full end-to-end verification in GCP
uv run esmeralda logs cx-mortgage-orchestrator --env dev
uv run esmeralda verify --env dev
2. End-to-End Multi-Agent Suite (make)¶
# Test the specialist alone, then orchestrator -> specialist through the Agent Gateway and entry point
make test-e2e ENV=dev
# Or test each remote engine individually
make test-ai-coe-mortgage-specialist-remote ENV=dev
make test-cx-mortgage-orchestrator-remote ENV=dev # TEST_VERBOSE=1 dumps raw A2A/ADK events
# Probe every catalog host through the entry point, including a live orchestrator query
make test-gateway ENV=dev
3. Direct A2A Verification from the Private Test VM¶
To inspect the raw Agent Card and A2A JSON-RPC payload inside the Shared VPC:
CX_PROJ=$(cd infrastructure/live/dev/layer-1-projects && terragrunt output -raw cx_agents_project_id)
gcloud compute ssh test-vm-dev --zone=us-central1-f --project=$CX_PROJ --tunnel-through-iap \
--command="bash -s" < scripts/test_a2a_through_gateway.sh
# If the specialist host is routed through an adapter (e.g. Envoy), pass an ID token instead:
gcloud compute ssh test-vm-dev --zone=us-central1-f --project=$CX_PROJ --tunnel-through-iap \
--command="TOKEN_KIND=id bash -s" < scripts/test_a2a_through_gateway.sh
The script verifies TLS against Esmeralda's internal Root CA (/tmp/root-ca.pem), fetches /v1/card, and sends an A2A message through https://ai-coe-mortgage-specialist.esmeralda.internal.
Next, let's see how the specialist actually checks Julian Sterling's W-2s, payroll records, and loan-officer emails in 1.2 Wrapping Enterprise Systems as MCP Tool Servers.