Agent DocsDeveloper documentation
Reference

Protocols (A2A, AG-UI, A2UI, MCP)

How the 4 interoperability protocols work together with governance

Protocol Implementation Guide

The TSI Agentic Hub uses four interoperability protocols to handle communication across every boundary in the platform. Each protocol serves a distinct purpose:

ProtocolBoundaryTransportSpecVersion
AG-UIAgent ↔ FrontendSSE (Server-Sent Events)ag-ui-protocol/ag-ui1.0
A2AAgent ↔ AgentJSON-RPC 2.0 over HTTPGoogle A2A v1.01.0 (with v0.3 compat)
A2UIAgent → User InputJSONL inside AG-UI CUSTOM events or A2A DataPartsa2ui.org/specification/v0.80.8
MCPAgent → ToolJSON-RPC 2.0 over stdio / SSE / Streamable HTTPModel Context ProtocolNov 2025

All four protocols are wrapped by a unified governance layer (Cedar policies, SPIFFE identity, OTel tracing, audit logging) so that every cross-boundary call is authorized, attributed, and observable.

Protocol Layering (No Cross-Contamination)

The protocols are cleanly layered — each operates at a specific boundary with no type leakage between layers:

LayerProtocolResponsibilityNever Touches
Frontend ↔ GatewayAG-UISSE event streaming, text deltas, tool call lifecycleMCP wire format, A2A JSON-RPC
Agent ↔ AgentA2ADiscovery (Agent Cards), task lifecycle (JSON-RPC 2.0)AG-UI events, MCP transport
Agent → User (UI)A2UIDeclarative UI surfaces for HITLDirect DOM, framework-specific widgets
Agent → ToolMCPTool discovery + execution, credential injectionAG-UI events, A2A task state

A2UI transport bindings — A2UI surfaces travel via three transports depending on the protocol boundary:

  • AG-UI path (Portal): CUSTOM SSE events with name: "a2ui"
  • A2A path (agent-to-agent): DataPart with mediaType: "application/json+a2ui"
  • MCP path (embedded resources): a2ui:// URI scheme in MCP resource responses

This separation ensures that protocol-specific concerns (SSE framing, JSON-RPC envelopes, MCP tool schemas) never leak across boundaries.


1. AG-UI (Agent-to-UI Protocol)

AG-UI is the streaming protocol between the API Gateway and the Portal frontend. It uses Server-Sent Events to deliver a structured sequence of typed events as the agent executes.

Event Types

Defined in packages/types/src/ag-ui-events.ts as the AGUIEventType union:

Lifecycle events control the run boundary:

  • RUN_STARTED -- carries threadId (conversation) and runId
  • RUN_FINISHED -- signals completion with optional result
  • RUN_ERROR -- error with message and optional code
  • STEP_STARTED / STEP_FINISHED -- named sub-steps within a run

Text streaming events deliver the assistant's response token by token:

  • TEXT_MESSAGE_START -- opens a message with messageId and role
  • TEXT_MESSAGE_CONTENT -- incremental delta string fragment
  • TEXT_MESSAGE_END -- closes the message

Tool call events follow the "agent declares, platform executes" pattern:

  • TOOL_CALL_START -- agent declares intent with toolCallId and toolCallName
  • TOOL_CALL_ARGS -- streamed JSON fragment (accumulate all deltas, then parse)
  • TOOL_CALL_END -- agent finished declaring this tool call
  • TOOL_CALL_RESULT -- platform injects the execution result back

State management events for shared state across segments:

  • STATE_SNAPSHOT / STATE_DELTA -- full snapshot or RFC 6902 JSON Patch
  • MESSAGES_SNAPSHOT -- full conversation history sync

Activity events for in-progress operation tracking:

  • ACTIVITY_SNAPSHOT / ACTIVITY_DELTA -- research progress, plan building, etc.

Extension events:

  • CUSTOM -- namespaced extension point (A2UI messages travel here as { name: "a2ui", value: <A2UIMessage> })
  • RAW -- pass-through for unstructured data

SSE Emitters

The API Gateway emits AG-UI events via helper functions in services/api-gateway/src/routes/chat-helpers.ts:

// Emit any AG-UI event to the SSE stream
async function emitAGUI(stream: SSEStreamingApi, event: Record<string, unknown>)

// Emit the handshake (first event in every stream)
async function emitHandshake(stream: SSEStreamingApi)
// Sends: { type: "CUSTOM", name: "ag-ui:handshake", value: { version: "1.0", capabilities: ["streaming", "tool_calls", "hitl", "a2ui"] } }

// Emit a complete tool call sequence (START + ARGS + RESULT + END)
async function emitToolCallAGUI(stream: SSEStreamingApi, toolCall: {...}, messageId: string)

Main Chat Endpoint

POST /api/chat/:agentId/message in services/api-gateway/src/routes/chat.ts opens an SSE stream and emits AG-UI events throughout the agent execution lifecycle. The event sequence for a platform-managed agent is:

CUSTOM (ag-ui:handshake)
RUN_STARTED { threadId, runId }
  STEP_STARTED { stepName: "llm-inference" }
    TEXT_MESSAGE_CONTENT { delta: "..." }  // repeated per token
  STEP_FINISHED
  TOOL_CALL_START { toolCallId, toolCallName }
  TOOL_CALL_ARGS { delta: "..." }
  TOOL_CALL_RESULT { content: "..." }
  TOOL_CALL_END
  TEXT_MESSAGE_CONTENT { delta: "..." }    // continued response after tool result
RUN_FINISHED { threadId, runId }

External Agent AG-UI Integration

External agents (LangGraph, CrewAI, etc.) implement the AG-UI protocol by exposing a POST /ag-ui endpoint. The platform sends an AGUIRunInput:

interface AGUIRunInput {
  threadId: string;           // conversation ID
  runId: string;              // unique run identifier
  messages: AGUIMessage[];    // full history including tool results
  tools?: AGUIToolDef[];      // available tools the agent can declare
  state?: Record<string, unknown>;  // shared state from previous segments
  clientCapabilities?: { supportedCatalogIds: string[] };  // A2UI support
}

The agent responds with an SSE stream of AGUIEvent[]. The platform intercepts TOOL_CALL_START/ARGS/END events, executes the declared tools through the MCP Gateway (with D2 access control and HITL gates), and injects TOOL_CALL_RESULT back into the stream. This is configured per-agent via externalConfig.agUiEnabled and externalConfig.agUiEndpointUrl in the agent config.

Multi-Segment AG-UI Flow (Temporal Durable Workflows)

The platform's Temporal durable workflow splits agent execution into segments. Each tool call boundary creates a new segment — this gives per-tool retry, HITL gates, and checkpoint/resume semantics.

Critical: STATE_SNAPSHOT must be emitted by the agent (or SDK) to preserve state between segments. Without it, the platform starts each segment with empty state, causing the agent to lose track of its execution phase.

Segment 0 (initial):
  Platform → POST /ag-ui { messages: [user msg], state: {} }
  Agent    → TEXT_MESSAGE_CONTENT ("Searching...")
  Agent    → TOOL_CALL_START/ARGS/END (web_search)
  Agent    → STATE_SNAPSHOT { phase: "awaiting_search_results", query: "..." }
  Agent    → RUN_FINISHED
  Platform → Executes web_search via MCP Gateway

Segment 1 (with tool results):
  Platform → POST /ag-ui { messages: [user msg, assistant msg, tool result], state: { phase: "awaiting_search_results", query: "..." } }
  Agent    → TEXT_MESSAGE_CONTENT ("Here are the results...")
  Agent    → STATE_SNAPSHOT { phase: "awaiting_approval", ... }
  Agent    → CUSTOM { name: "a2ui", value: { surfaceUpdate: ... } }  // A2UI approval surface
  Agent    → RUN_FINISHED

Message format between segments:

AG-UI messages use { role: string, content: string } format. Tool results arrive as messages with role: "tool" and toolCallId:

// AG-UI message format (what the SDK's /ag-ui endpoint receives)
interface AGUIMessage {
  role: 'user' | 'assistant' | 'tool';
  content: string;        // plain text or JSON string for tool results
  toolCallId?: string;    // present only for role: 'tool'
}

The SDK converts these to the internal A2A v1.0 format (A2AMessage with content: A2APart[]) and extracts toolResults from role: 'tool' messages before passing them to the agent's onTurn() handler.

Sequence Diagram: AG-UI Chat Flow

Scroll to zoom · Drag to pan · 100%

2. A2A (Agent-to-Agent Protocol) — v1.0

A2A enables agents to invoke other agents. Based on Google's A2A v1.0 specification (JSON-RPC 2.0), extended with platform governance. The platform supports both A2A v1.0 and legacy v0.3 method names for backward compatibility.

A2A v1.0 Changes

Conceptv0.3 (Legacy)v1.0 (Current)
Method namesagent/sendMessage, agent/getTaskSendMessage, GetTask, CancelTask, ListTasks
Task state valuessubmitted, working, completed, failedTASK_STATE_SUBMITTED, TASK_STATE_WORKING, TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED, TASK_STATE_INPUT_REQUIRED
Message format{ role: "user", parts: [...] }{ role: "ROLE_USER", content: [...] }
Task fieldartifactsmessages (with content: A2APart[])

The platform's JSON-RPC dispatcher accepts both v0.3 and v1.0 method names. The TASK_STATE_INPUT_REQUIRED state is new in v1.0 and is used for HITL flows — when an agent needs user input, it returns this state along with A2UI surfaces.

Agent Cards

Every agent can publish a discovery card at GET /.well-known/agent.json containing metadata, capabilities, supported input/output modalities, and skill declarations. The platform generates these from the Agent model (defined in packages/types/src/agent.ts) including defaultInputModes, defaultOutputModes, and AgentCardPublishConfig.

Invocation Types

Defined in packages/types/src/a2a.ts:

interface A2AInvokeRequest {
  sourceAgentId: string;
  targetAgentId: string;
  payload: {
    message: string;
    context?: Record<string, unknown>;
    attachments?: Array<{ mimeType: string; name?: string; uri?: string }>;
  };
  delegationDepth?: number;      // incremented per hop
  delegationChain?: string[];    // full chain of agent IDs
  conversationId?: string;
  userContext?: A2AUserContext;   // end-user identity propagated through chain
}

interface A2AInvokeResponse {
  invocationId: string;
  sourceAgentId: string;
  targetAgentId: string;
  status: 'completed' | 'error' | 'approval_required';
  result?: { message: string; tokenUsage?: { input: number; output: number; cost: number } };
  error?: string;
  approvalId?: string;
  delegationDepth: number;
  delegationChain: string[];
  durationMs: number;
}

User Context Propagation

The A2AUserContext carries the end user's identity through the entire delegation chain:

interface A2AUserContext {
  userId: string;
  tenantId: string;
  token?: string;  // JWT for OBO token exchange
}

This enables credential resolution (user-scoped BYOK keys), audit trail attribution, and HITL approval tracking at every hop.

External Agent Registration

External agents self-register via POST /api/a2a/register with an admin-issued registration token. The response includes an invocationSecret (shown once) and an a2aInvokeUrl for the agent to invoke other platform agents.

Governance Extension (Dimension 3)

The platform wraps every A2A invocation with Cedar policy enforcement. The full pipeline in services/api-gateway/src/lib/a2a-invoker.ts:

  1. Loop detection -- checks if the target agent already appears in the delegationChain
  2. Interaction policy check (D3) -- verifies source's canInvoke list AND target's invocableBy list via checkInteractionPolicy() in services/api-gateway/src/middleware/interaction-policy-check.ts
  3. Delegation depth enforcement -- configurable per-tenant (default: 5), also per-grant via maxDelegationsPerExecution
  4. HITL approval -- if requireApproval is set on the invoke grant, creates an approval request and returns status: 'approval_required'
  5. Capability attenuation -- effective tool permissions = intersection of source grants and target grants, preventing privilege escalation through delegation (MCP Nov 2025 section 7.1). Three modes: full, readwrite, readonly
  6. Cedar PDP overlay -- additional checkAgentInteractionPolicy() call to the Cedar policy engine for fine-grained D3 rules
  7. Target execution -- routes to the appropriate runtime (external pro-code, external n8n, legacy callback, or platform-managed LLM)
  8. Tracing and execution recording -- OTel trace span and execution record stored for observability

Interaction Policy Check

Defined in services/api-gateway/src/middleware/interaction-policy-check.ts. The check is bidirectional:

  • Source must list target in interactionPolicy.canInvoke[] with an AgentInvokeGrant
  • Target must accept source in interactionPolicy.invocableBy[] with an AgentCallerGrant
  • Target agent must not be suspended or deprecated
  • Self-invocation is always blocked (loop prevention)

Sequence Diagram: A2A Invocation with Policy Checks

Scroll to zoom · Drag to pan · 100%

3. A2UI (Agent-to-User Input Protocol) — v0.8

A2UI is a JSONL-based streaming protocol that enables agents to generate platform-agnostic UI definitions during execution. The Portal renders these progressively using native widgets.

Transport Bindings

A2UI surfaces are transported via three protocol-specific bindings:

1. AG-UI binding (Portal ↔ Agent): A2UI messages travel inside AG-UI CUSTOM events:

{ "type": "CUSTOM", "name": "a2ui", "value": <A2UIMessage> }

2. A2A binding (Agent ↔ Agent): A2UI surfaces travel as DataPart entries in A2A task messages:

{
  "role": "ROLE_AGENT",
  "content": [{ "data": <A2UIMessage>, "mediaType": "application/json+a2ui" }]
}

When an A2A task returns TASK_STATE_INPUT_REQUIRED, the SDK automatically generates A2UI surfaces from the agent's statePatch HITL metadata and includes them as DataParts.

3. MCP binding (embedded resources): A2UI surfaces can be embedded in MCP resource responses via the a2ui:// URI scheme.

A2UI registers with A2A as an extension at URI https://a2ui.org/a2a-extension/a2ui/v0.8.

SDK Surface Builders

Both the Python and TypeScript SDKs provide surface builders that automatically generate A2UI v0.8 surfaces from HITL metadata in statePatch. The dispatcher function buildA2UIFromHITL(statePatch, runId) reads hitl_type from the state patch and calls the appropriate builder:

hitl_typeBuilderUI Surface
"plan_selection"buildPlanSelectorSurface()MultipleChoice list with selectable options
"parameter_edit"buildParameterEditorSurface()Form with TextField/Slider inputs per parameter
"user_input"buildUserInputSurface()Single TextField (text, textarea, or number)
"approval"buildApprovalSurface()Card with tool name, reasoning, Approve/Reject buttons

Python:

from agentic_sdk import request_approval, message
return request_approval(hitl_type="approval", options={"tool": "create_ticket"}, message=message("assistant", "Approve?"))

TypeScript:

import { buildApprovalSurface, buildA2UIFromHITL } from '@agentic-platform/sdk';
// Low-level: build surfaces directly
const surfaces = buildApprovalSurface(requestId, 'create_ticket', args, 0.5, 'Creating ticket');
// High-level: dispatch from statePatch (used by SDK internals)
const surfaces = buildA2UIFromHITL(statePatch, runId);

The SDK's AG-UI endpoint (POST /ag-ui) and A2A endpoint (POST /) both automatically call buildA2UIFromHITL() when the agent returns TASK_STATE_INPUT_REQUIRED.

Message Types (Server to Client)

Defined in packages/types/src/a2ui-protocol.ts:

surfaceUpdate -- add or modify components in a surface. The first update with a new surfaceId implicitly creates the surface. Components use an adjacency list model with ID references.

interface A2UISurfaceUpdate {
  surfaceId: string;
  components: A2UIComponentEntry[];  // adjacency list of UI components
}

dataModelUpdate -- modify application state for a surface. Data is separate from UI structure for efficient partial updates.

interface A2UIDataModelUpdate {
  surfaceId: string;
  path?: string;                     // e.g., "/form/inputs"
  contents: A2UIDataEntry[];         // adjacency list of data entries
}

beginRendering -- signal that a surface is ready to render. Prevents flash of incomplete content.

interface A2UIBeginRendering {
  surfaceId: string;
  root: string;       // root component ID
  catalogId?: string; // defaults to standard catalog
}

deleteSurface -- remove a surface when no longer needed (e.g., after HITL resolution).

Message Types (Client to Server)

userAction -- sent when a user interacts with a component (button click, form submit, selection change):

interface A2UIUserAction {
  name: string;                    // action identifier from component's action.name
  surfaceId: string;
  sourceComponentId: string;
  timestamp: string;               // ISO 8601
  context: Record<string, unknown>; // resolved key-value pairs from action definition
}

Component Catalog (v0.8)

The standard catalog defines these component types, all rendered by A2UIProtocolRenderer in packages/ui/src/components/a2ui-protocol/A2UIProtocolRenderer.tsx:

ComponentPurposeKey Props
TextDisplay texttext (BoundValue), usageHint (h1-h5, caption, body)
ButtonInteractive actionlabel, action (ActionDef), primary
CardContainer with borderchild (component ID)
ColumnVertical layoutchildren (explicit or template)
RowHorizontal layoutchildren
TextFieldText inputvalue, label, placeholder, inputType
CheckBoxBoolean togglevalue, label
MultipleChoiceSelection (checkbox or chips)value, options, variant
SliderNumeric rangevalue, min, max, label
ImageDisplay imageurl, fit, sizeHint
DividerVisual separator--
ListDynamic item renderingchildren (template)
TabsTabbed containerchildren, labels
ModalOverlay dialogchild, title

Data Binding

All component properties use A2UIBoundValue for dynamic data binding:

interface A2UIBoundValue {
  literalString?: string;   // static value
  literalNumber?: number;
  literalBoolean?: boolean;
  literalArray?: unknown[];
  path?: string;            // data model path, e.g., "/user/name"
}

Three binding modes:

  1. Literal only -- { literalString: "Hello" } is static
  2. Path only -- { path: "/user/name" } resolves dynamically from the surface data model
  3. Both -- path is updated with the literal value, then bound for future updates

Rendering Flow

Scroll to zoom · Drag to pan · 100%

4. MCP (Model Context Protocol)

MCP is the universal tool interoperability protocol. The MCP Gateway (services/api-gateway/src/lib/mcp-gateway.ts) manages server connections, discovers tools, routes execution requests, and enforces access control.

Transport Modes

The gateway supports three MCP transports:

TransportURI SchemeUse Case
stdiomcp://Local development; gateway spawns child process
SSEmcp+sse://Docker/K8s deployments; HTTP SSE endpoint
Streamable HTTPmcp+http://Nov 2025 MCP spec; single HTTP endpoint with reconnection

Built-in MCP servers can be overridden to SSE via environment variables:

  • MCP_BUILTIN_ENDPOINT -- platform tools (web search, KB search) on port 3210
  • MCP_CODE_EXEC_ENDPOINT -- code execution tools on port 3201

Gateway Architecture

Scroll to zoom · Drag to pan · 100%

Tool Execution Pipeline

When executeTool(request: ToolExecutionRequest) is called:

Scroll to zoom · Drag to pan · 100%

Tool Registration and Discovery

Tools are registered in the mcp_tools database table. When the gateway connects to an MCP server:

  1. Calls client.listTools() to discover available tools
  2. Matches discovered tools against existing DB records using sanitizeToolName() (e.g., "Knowledge Base Search" matches knowledge_base_search)
  3. Known tools get routing entries (toolId → serverId)
  4. New tools from external servers are auto-registered with riskLevel: 'medium' and category: 'read-only'

D2 Access Control (Agent to Tool)

Defined in packages/types/src/agent.ts as AgentToolGrants:

interface AgentToolGrants {
  tools: ToolGrant[];
  dynamicDiscovery: boolean;        // default: false
  maxToolCallsPerExecution: number; // default: 20
}

interface ToolGrant {
  toolId: string;
  permissions: ('read' | 'write' | 'execute')[];
  conditions?: {
    maxCallsPerHour?: number;
    requireApproval?: boolean;
    timeWindow?: { start: string; end: string };
    approvalPolicy?: ApprovalPolicy;
  };
}

The checkToolGrant() middleware enforces that the agent has an explicit grant for the tool, with matching permissions and condition checks.

Tool Signing (Sigstore)

Before execution, checkSignatureEnforcement() verifies the tool's supply-chain signature via Sigstore. If enforcement is enabled and the signature check fails, the tool call is rejected with TOOL_SIGNATURE_FAILED.

MCP Sampling

When an MCP server requests LLM completion via sampling/createMessage, the gateway routes it through the platform's LLM Gateway (T-Systems AIFS). This enables multi-tenant credential resolution, token tracking, cost attribution, and D4 model access policy enforcement within MCP server execution.

Circuit Breaker

Per-server failure tracking prevents cascading failures:

StateBehavior
CLOSEDNormal operation; failures counter increments
OPENAfter 5 consecutive failures; fast-rejects all calls for 30 seconds
HALF_OPENAfter recovery timeout; allows one probe call

5. How They Work Together

A single user message can traverse all four protocols. Here is the full lifecycle of a request that involves LLM inference, an MCP tool call, an A2A agent delegation, and an A2UI user input surface.

Full Request Lifecycle

Portal (user types message)
  │
  ├─ AG-UI ─► API Gateway opens SSE stream
  │             │
  │             ├─ Guardrails: input policy check
  │             ├─ Memory: retrieve context from Redis/Qdrant/Neo4j
  │             ├─ Knowledge: RAG retrieval from attached KBs
  │             │
  │             ├─ LLM inference (streaming via AIFS)
  │             │   └─ AG-UI events: TEXT_MESSAGE_CONTENT tokens
  │             │
  │             ├─ LLM declares tool_call: "web_search"
  │             │   ├─ AG-UI: TOOL_CALL_START + TOOL_CALL_ARGS
  │             │   │
  │             │   ├─ MCP ─► MCP Gateway
  │             │   │           ├─ D2: checkToolGrant (agent → tool)
  │             │   │           ├─ Sigstore signature verification
  │             │   │           ├─ HITL gate (if requireApproval)
  │             │   │           ├─ Credential injection (OAuth/API key)
  │             │   │           ├─ Circuit breaker check
  │             │   │           ├─ client.callTool() via MCP transport
  │             │   │           └─ Audit + OTel trace
  │             │   │
  │             │   └─ AG-UI: TOOL_CALL_RESULT + TOOL_CALL_END
  │             │
  │             ├─ LLM declares tool_call: "invoke_agent" (target: agent-research)
  │             │   ├─ AG-UI: TOOL_CALL_START + TOOL_CALL_ARGS
  │             │   │
  │             │   ├─ A2A ─► A2A Invoker
  │             │   │           ├─ Loop detection (delegation chain)
  │             │   │           ├─ D3: checkInteractionPolicy (agent → agent)
  │             │   │           ├─ Cedar PDP overlay
  │             │   │           ├─ Capability attenuation (least privilege)
  │             │   │           ├─ HITL gate (if requireApproval)
  │             │   │           ├─ Forward userContext (userId, tenantId, JWT)
  │             │   │           ├─ Execute target agent
  │             │   │           └─ Trace + execution recording
  │             │   │
  │             │   └─ AG-UI: TOOL_CALL_RESULT + TOOL_CALL_END
  │             │
  │             ├─ LLM needs user input (e.g., confirmation)
  │             │   │
  │             │   ├─ A2UI ─► via AG-UI CUSTOM events
  │             │   │           ├─ surfaceUpdate (components)
  │             │   │           ├─ dataModelUpdate (state)
  │             │   │           ├─ beginRendering (root component)
  │             │   │           │
  │             │   │           ├─ Portal renders A2UIProtocolRenderer
  │             │   │           ├─ User interacts (button click, form submit)
  │             │   │           ├─ userAction sent back to gateway
  │             │   │           │
  │             │   │           └─ deleteSurface (cleanup)
  │             │   │
  │             │   └─ Agent continues with user's response
  │             │
  │             ├─ Guardrails: output policy check
  │             ├─ Memory: extract and store conversation memories
  │             │
  │             └─ AG-UI: RUN_FINISHED

Sequence Diagram: All Four Protocols in One Flow

Scroll to zoom · Drag to pan · 100%

6. Governance Layer

All four protocols are wrapped by a unified governance layer that enforces security, authorization, and observability at every boundary.

Cedar Policy Enforcement

Cedar policies are evaluated at three protocol boundaries:

DimensionBoundaryPolicy TypeEnforcement Point
D1User to AgentEntitlement checkAuth middleware (checkUserAgentAccess)
D2Agent to ToolTool grant checkMCP Gateway (checkToolGrant)
D3Agent to AgentInteraction policyA2A Invoker (checkInteractionPolicy + checkAgentInteractionPolicy)
D4Agent to ModelModel access policyLLM Gateway (checkModelAccess + checkAgentModelPolicy)

Cedar PDP calls are non-fatal (fail-open with warning log) to prevent policy engine outages from blocking all agent execution.

SPIFFE Agent Identity

Each agent is assigned a SPIFFE identity (spiffe://platform/tenant/<tenantId>/agent/<agentId>) via the SPIRE infrastructure. This identity is used for:

  • mTLS between agent containers and the API Gateway
  • Cryptographic proof of agent identity in A2A invocations
  • Audit trail attribution at every protocol boundary

OBO Token Exchange

When an agent needs to access downstream services on behalf of a user, the platform performs RFC 8693 token exchange (or SAP BTP Destination Service flow). Configured per-agent via oboTargets in AgentConfig:

interface OBOTarget {
  audience: string;       // e.g., "sap-s4hana", "salesforce"
  scopes: string[];       // e.g., ["read:orders", "write:tickets"]
  description?: string;
  type?: 'rfc8693' | 'sap-destination';
  sapDestinationName?: string;
}

The user's JWT is propagated through A2A delegation chains via A2AUserContext.token, enabling OBO exchange at every hop. External agent callbacks receive user identity via X-User-Id and X-Tenant-Id headers.

Audit Logging

Every protocol boundary records an audit event with:

  • Agent ID and name
  • Tenant ID
  • Action performed (e.g., oauth:credential_resolved, a2a:invoke, tool:execute)
  • Outcome (success / blocked / error)
  • Risk level
  • Access control dimension (1-4)
  • Principal ID (user or agent)
  • Resource ID (tool, agent, or model)

Rate Limiting and Circuit Breakers

MechanismScopeConfiguration
Tool rate limitsPer-agent per-toolToolGrant.conditions.maxCallsPerHour
Max tool callsPer-executionAgentToolGrants.maxToolCallsPerExecution (default: 20)
Delegation depthPer-tenant / per-grantTenant config maxDelegationDepth (default: 5), grant maxDelegationsPerExecution
MCP circuit breakerPer-server5 failures trips to OPEN, 30s recovery timeout
Execution quotasPer-tenantConcurrent execution limits via checkExecutionQuota
Budget limitsPer-agent / per-subagentSubagentResourceConfig.tokenBudget, costBudget, timeoutMs
Model cost capsPer-agentAgentModelAccess.maxCostPerRequest, maxCostPerDay

7. Key Source Files

FilePurpose
Types
packages/types/src/ag-ui-events.tsAG-UI event type definitions
packages/types/src/google-a2a.tsA2A v1.0 types (Task, Message, Part, AgentCard)
packages/types/src/a2a-compat.tsA2A v0.3 → v1.0 compatibility layer
packages/types/src/a2a.tsA2A invocation and registration types
packages/types/src/a2ui-protocol.tsA2UI protocol types (v0.8)
packages/types/src/agent.tsAgent config including OBO, interaction policy, tool grants, model access
Gateway
services/api-gateway/src/routes/chat.tsMain chat route orchestrator (SSE streaming)
services/api-gateway/src/routes/chat-helpers.tsAG-UI emitters (emitAGUI, emitHandshake, emitToolCallAGUI)
services/api-gateway/src/routes/chat-durable.tsTemporal durable workflow chat handler (multi-segment AG-UI)
services/api-gateway/src/routes/chat-external.tsExternal agent handler (non-durable, debug fallback)
services/api-gateway/src/routes/google-a2a.tsA2A v1.0 JSON-RPC endpoint (POST /api/a2a)
services/api-gateway/src/lib/a2a-invoker.tsA2A invocation pipeline with policy enforcement
services/api-gateway/src/lib/a2a-sse-bridge.tsAG-UI → A2A bridge (exposes AG-UI agents to A2A callers)
services/api-gateway/src/lib/a2a-task-manager.tsA2A task lifecycle management
services/api-gateway/src/lib/external-agent-executor.tsExternal agent HTTP client (AG-UI POST /ag-ui)
services/api-gateway/src/lib/mcp-gateway.tsMCP Gateway (connections, routing, tool execution)
services/api-gateway/src/lib/capability-attenuation.tsCapability attenuation for A2A delegation
services/api-gateway/src/lib/credential-resolver.ts4-tier credential resolution
services/api-gateway/src/lib/tool-signer.tsSigstore tool signing verification
services/api-gateway/src/lib/policy-engine.tsCedar PDP integration
services/api-gateway/src/middleware/interaction-policy-check.tsD3 interaction policy check
services/api-gateway/src/middleware/tool-grant-check.tsD2 tool grant check
services/api-gateway/src/middleware/model-access-pep.tsD4 model access policy enforcement
SDKs
sdks/python/agentic_sdk/server.pyPython SDK: FastAPI server with AG-UI + A2A v1.0 endpoints
sdks/python/agentic_sdk/a2ui.pyPython SDK: A2UI surface builders (4 builders + dispatcher)
sdks/typescript/src/server.tsTypeScript SDK: Hono server with AG-UI + A2A v1.0 endpoints
sdks/typescript/src/agent.tsTypeScript SDK: AgenticAgent base class with multi-segment tool result extraction
sdks/typescript/src/a2ui.tsTypeScript SDK: A2UI surface builders (parity with Python)
Frontend
packages/ui/src/components/a2ui-protocol/A2UIProtocolRenderer.tsxA2UI frontend renderer