A2A Agent Task
An A2A Agent Task delegates one process activity to a registered remote agent through A2A
Protocol 1.0. The embedded Process Engine owns the BPMN wait state, state/result mapping, and
response listener. The outbound A2A client in tsm-ai owns transport and the durable local
invocation view. The remote agent owns the authoritative A2A Task. In the initial tSM-to-tSM
integration, tsm-ai calls the remote installation's tSM Gateway, which authenticates the
request and forwards it to its registered A2A binding. The local Gateway is not an outbound proxy.
Use it when the collaborating agent is independently operated, advertises an approved Agent Skill,
and may require progress updates, additional input, authentication, Artifacts, or cancellation.
Use an Agent Task when tsm-ai should perform one local model operation, or an
Agentic Subprocess when tSM should coordinate a bounded local
model-and-tool loop.
Core A2A Concepts
| Concept | Use in an outbound process task |
|---|---|
| Agent Card | Discoverable identity, interfaces, Skills, capabilities, protocol versions, and security requirements |
| Agent Skill | Approved remote capability selected by stable Skill ID |
| Message | User/agent interaction composed of typed Parts |
| Part | Text, structured data, or file/reference carried by a Message or Artifact |
| Task | Stateful unit of work created and owned by the remote A2A server |
taskId | Server-created opaque identifier for one remote Task |
contextId | Server-created opaque grouping for related Tasks and Messages |
| Artifact | Validated Task output composed of Parts |
tsm-ai stores remote identifiers in the Outbound A2A Invocation; the Process Engine references
that record by a2aInvocationId. Any projected identifier is only a correlation value and never
establishes tenant, user, authorization, business key, or process identity.
Agent Registry and Discovery
Every remote agent is onboarded through the tSM Agent Registry. The registry retrieves and pins the standard Agent Card, then applies enterprise trust and data-governance policy.
| Registry property | Purpose |
|---|---|
| Code | Stable identifier used by process configuration |
| Discovery | Approved well-known Agent Card URL, curated card, or private registry source |
| Pinned Agent Card | Versioned card, selected interface, protocol version, and capability snapshot |
| Trust Policy | Allowed provider, domain, certificate/signature, and security scheme |
| Skills | Explicit allow-list of remote Agent Skill IDs |
| Invocation Mapping | Deterministic mapping from the selected Skill to a single-skill agent contract or a required remote routing extension |
| Authentication | Opaque Secret/Vault credentialRef for the existing remote-Gateway X-API-Key flow and server-owned X-Tenant-Id mapping |
| Tenant Mapping | Server-controlled local-to-remote tenant mapping |
| Data Policy | Allowed classifications, media types, sizes, regions, and retention |
| Runtime Limits | Activity deadline/unbounded-wait policy, finite transport-call timeout, retry, rate, concurrency, Message, and Artifact limits |
| Send idempotency evidence | Onboarding test proving that identical messageId, contextId, and canonical payload do not create duplicate work |
| Availability | Health policy, circuit breaker, rollout, and kill switch |
A2A discovery normally starts with:
https://agent.example.com/.well-known/agent-card.json
The standard Agent Card declares supportedInterfaces, protocol versions, capabilities, security,
input/output modes, and Skills. The tSM registry adds curated approval, version pinning, tenant
mapping, and change control. A refreshed card can improve descriptive information; newly introduced
endpoints, Skills, security schemes, or required extensions pass registry approval before use.
Initially Supported A2A Scope
The first tsm-ai outbound client uses a deliberately small A2A 1.0 subset:
| Area | Initial support |
|---|---|
| Protocol binding | JSONRPC over HTTPS |
| Version | A pinned 1.0 interface with A2A-Version: 1.0; no automatic downgrade or binding switch |
| Start or continue work | SendMessage |
| Read remote Task state | GetTask |
| Request cancellation | CancelTask |
| Update delivery | Rate-controlled polling with finite GetTask calls after taskId is known |
| Unknown-Task discovery | Optional approved ListTasks(contextId) support as auxiliary evidence only |
| Result | Direct Message or remote Task |
Streaming, subscription, and push notifications are not part of the initial implementation. They
can later reduce update latency, but polling remains sufficient for durable waiting, restart
recovery, and authoritative state reconciliation after taskId is known.
Initial outbound use is allowed only for a current valid registry entity commit whose onboarding test has proved
idempotent SendMessage handling. The proof repeats the exact same messageId, contextId, and
canonical payload and verifies that the remote side returns or resolves to the same work rather than
starting a duplicate. This is a compatibility requirement even when the remote server claims
idempotency in descriptive metadata.
The registry is a normal versioned and audited tSM entity with standard validity. It stores the exact interface, endpoint, protocol version, Skill mapping, Agent Card hash, and authentication reference. Editing or refreshing it creates ordinary audit/JaVers history; it does not introduce a separate draft, publish, or retire lifecycle. Every invocation pins the exact registry audit commit and Agent Card hash, so a later edit never changes running work. Dispatch-relevant changes require a new successful conformance verification before new invocations can use them.
Skill Invocation Mapping
An Agent Skill ID is part of Agent Card discovery; the core A2A SendMessage request has no
standard skillId field. The tSM Agent Registry therefore stores an explicit Invocation
Mapping for every approved Skill:
| Mapping | Use |
|---|---|
| Single-skill agent contract | The pinned agent/interface exposes one unambiguous approved Skill; the configured Message and result contracts are checked against its advertised input/output modes. |
| Required routing extension | A multi-skill agent declares a required AgentExtension with a URI and metadata schema. The tsm-ai outbound client activates it and writes the selected Skill ID into its namespaced metadata. |
For example, a remote agent can declare https://agent.example.com/extensions/skill-routing/v1 as
required. The registry pins that declaration and its schema, and the tsm-ai outbound client builds:
{
"extensions": [
"https://agent.example.com/extensions/skill-routing/v1"
],
"metadata": {
"https://agent.example.com/extensions/skill-routing/v1": {
"skillId": "resolve-service-incident"
}
}
}
Registration accepts a multi-skill remote agent only when the selected Skill has an unambiguous Invocation Mapping. This keeps Skill selection deterministic while allowing each remote agent to define its own extension URI and schema.
Configuration
| Property | Required | Description |
|---|---|---|
| Remote Agent | Yes | Stable Agent Registry code |
| Agent Skill | Yes | Allowed Skill ID from the pinned Agent Card |
| Invocation Mapping | Inherited | Pinned single-skill contract or required routing extension from the Agent Registry |
| Goal / Message | Yes | Message template and mapped Parts |
| Input Mapping | Yes | Explicit process values mapped to text, data, file, or governed URL/reference Parts |
| Accepted Output Modes | Yes | Media types accepted from the remote agent |
| Initial Request | Yes | SendMessage |
| Update Delivery | Yes | Rate-controlled GetTask polling and reconciliation after remote taskId is known |
| Context Mapping | No | Existing contextId for a documented related interaction |
| State Mapping | Yes | Remote Task states mapped to a local status, variable mapping, lifecycle action, and permitted listener actions |
| State Response Listener | No | One expression or certified Script/delegate implementation; State Mapping is the sole source of trigger states and permitted actions |
| Listener Failure Policy | Conditional | Retry/incident behavior and maximum attempts when a State Response Listener is configured |
| Result Mapping | Yes | Artifact or direct-Message values mapped to typed process variables |
| Input-required Path | Yes | User Task, local Agent Task, or modeled Message path |
| Auth-required Path | Yes | Approval or credential-broker path |
| Activity Deadline and Retry | Yes | Absolute activity deadline or explicit governed UNBOUNDED, finite HTTP-call timeout, exact-message retry, polling, and circuit-breaker policy |
| Cancellation Policy | Yes | Remote cancel attempt, local timeout, and compensation behavior |
| Error Mapping | Yes | Protocol, contract, and transport outcomes mapped to BPMN errors or incidents |
The process selects a registry entry rather than accepting a runtime URL expression. Authentication references remain server-side and are never stored in BPMN, Message Parts, or process variables.
Runtime Lifecycle
- The Process Engine loads the deployed Agent Registry code, Skill, Invocation Mapping, state mapping, listener, and policy references.
- Input Parts are authorized, schema-validated, scanned, and size-limited.
- The engine persists a stable
a2aInvocationId,messageId,contextIdvalue or absence, canonical payload hash, BPMN wait state, and durable request before dispatch. - The
tsm-aioutbound client idempotently creates the Outbound A2A Invocation, or returns its existing admission for a duplicate request; resolves and pins the Agent Card, interface, extension, tenant mapping, trust, authentication, and data policy; materializes the Invocation Mapping; and sendsSendMessagewithA2A-Version: 1.0,X-API-Key, andX-Tenant-Idto the remote tSM Gateway. The Gateway uses its existing API-key exchange and strips the key before forwarding. Each HTTP attempt has a 30-second technical timeout. A long-running request uses immediate return and is subsequently reconciled withGetTaskafter the response suppliestaskId. - A direct Message is validated and may complete short work. A returned Task persists its remote
taskId,contextId, state, interface, and agent identity in the local invocation projection; its initial snapshot is normalized and sequenced as the first state response. - The Process Engine consumes that initial response through the same mapping/listener pipeline as
any later response. If it is non-terminal, the BPMN activity waits while
tsm-aiaccepts, validates, deduplicates, persists, and sequences polled Task snapshots. - The Process Engine consumes every later update idempotently, computes the provisional State Mapping, invokes the optional listener, validates its result, and atomically commits the accepted update, variables, commands, and process action.
INPUT_REQUIREDandAUTH_REQUIREDactivate their explicit process paths and continue with the same remote Task and context.- A terminal response is reconciled with the authoritative remote Task. Its Artifacts are validated and mapped before the process continues.
After taskId is known, local correlation and GetTask reconcile execution after a disconnect,
uncertain response, or restart. Before taskId is known, GetTask cannot help: an uncertain send
may only repeat the exact persisted messageId, contextId, and canonical payload under the
onboarded idempotency guarantee. An approved ListTasks(contextId) capability may help find a
candidate, but it never replaces that guarantee.
Polling state is persisted rather than held in an HTTP request or worker thread. tsm-ai polls after
2 seconds, then 5 seconds, then 10 seconds, and then every 30 seconds until the Task changes or ends.
Only one lease-owning coordinator polls a remote Task at a time, unchanged snapshots are not
republished, and another replica can continue after restart. The overall wait follows the BPMN
activity's absolute deadline or its explicitly governed UNBOUNDED choice; UNBOUNDED never makes
an individual HTTP call unbounded.
Task State Mapping and Response Listener
tsm-ai normalizes every accepted remote update into a durable state response. The Process Engine
maps that response to a local status and process action. These defaults are safe starting points:
| A2A 1.0 state | Default local lifecycle action |
|---|---|
TASK_STATE_UNSPECIFIED | Reconcile with GetTask; remain waiting and create A2A_UNMAPPED_STATE incident if the state cannot be resolved |
TASK_STATE_SUBMITTED | Persist remote Task identity and WAIT |
TASK_STATE_WORKING | Persist status/progress and WAIT |
TASK_STATE_INPUT_REQUIRED | WAIT and start the configured information-collection path or listener reply flow |
TASK_STATE_AUTH_REQUIRED | WAIT and start the configured approval or delegated-authentication path |
TASK_STATE_COMPLETED | Validate Artifacts and result mapping, then COMPLETE |
TASK_STATE_REJECTED | Throw the configured business error, default A2A_REJECTED |
TASK_STATE_FAILED | Apply an explicit business mapping or create an incident |
TASK_STATE_CANCELED | Follow the modeled cancellation, error, or compensation path |
A direct Message is an immediate result path and is not converted to a synthetic Task state.
INPUT_REQUIRED and AUTH_REQUIRED are interrupted states. Terminal Tasks are immutable and
cannot accept another continuation.
State Mapping Configuration
Each configured state entry contains:
| Field | Meaning |
|---|---|
localStatus | Operator-facing status code stored for the activity |
variableMapping | Schema-checked fields copied from status, Message, or Artifact references |
action | Built-in WAIT, COMPLETE, BPMN_ERROR, or INCIDENT behavior |
errorCode | Required for a BPMN_ERROR mapping |
invokeListener | Whether the task's one configured State Response Listener runs for this state |
allowedListenerActions | Subset of listener actions permitted for this state |
Unknown future states never advance the process automatically. State enum order and remote
timestamps are not used as an ordering mechanism: an interrupted Task can legitimately return to
WORKING after a continuation. Conflicting or uncertain delivery is reconciled with GetTask.
A2A State Response Listener
An optional A2A State Response Listener runs after a normalized update has been persisted by
tsm-ai and accepted by the Process Engine. It executes in the process-owning microservice because
it needs process variables, certified Scripts, and the local transaction. It never runs inside a
remote stream or callback transaction.
The listener uses the same expression/delegate configuration shape as other tSM listeners and is
identified as a2aStateListener. One implementation and retry policy are configured on the task.
For each state, State Mapping alone controls invokeListener and allowedListenerActions; there is
no second listener-level state filter or action override. A certified Script receives the immutable
update as #a2aUpdate:
| Field | Meaning |
|---|---|
schemaVersion | Version of the internal response contract |
a2aInvocationId | Stable local outbound invocation identity |
processDefinitionId, processInstanceId, activityInstanceId | Owning BPMN correlation |
remoteAgentCode, agentCardVersion, skillId | Pinned target configuration |
messageId, taskId, contextId | Local Message and opaque remote identifiers |
previousState, state | Previously accepted and current A2A Task states |
statusTimestamp, statusMessage | Validated remote status data |
artifactRefs | Governed references to accepted Artifacts; never unrestricted payloads |
deliveryMode | INITIAL, POLL, or RECONCILIATION in the initial implementation |
updateId, updateSequence | Locally assigned deduplication identity and order |
receivedAt, deadline or unbounded marker, listenerAttempt | Local timing and retry context |
updateId and updateSequence are generated by tsm-ai; A2A status events do not provide a
portable event identity or cross-delivery sequence.
Update Identity and Cross-delivery Deduplication
The same remote state can arrive through a stream, push callback, and later GetTask. tsm-ai
keeps every raw delivery under a unique deliveryId for audit, but publishes a process update only
when the canonical local Task projection changes:
- Validate the delivery and apply its status, Message, and Artifact changes to the previous
canonical projection. A reconciliation response replaces that projection with the verified
GetTasksnapshot. - Canonically serialize the observable projection: remote Task ID, state, status timestamp and Message/Part hashes, Artifact IDs/descriptors/checksums, and approved protocol metadata.
- Compute
snapshotFingerprintfrom that serialization. When a server supplies an approved stable event/revision extension, its value is included but never trusted as authorization. - Reuse the existing
updateIdwhen the fingerprint was already accepted. For a new fingerprint, assign the nextupdateSequenceand derive a stableupdateIdfrom(a2aInvocationId, snapshotFingerprint).
Consequently, a repeated snapshot from another delivery mode cannot run the listener twice, while a new status message, timestamp, Artifact, or state creates a new update even when the state enum is unchanged. Two deliveries with no observable difference are intentionally one semantic update. Raw delivery attempts remain available for transport diagnostics.
An expression listener may return no value and only use outbox-safe local services. A Script or delegate can return this typed result:
{
"action": "USE_MAPPING",
"variables": {
"remoteProgressText": "Validation completed"
},
"reply": null,
"errorCode": null,
"reason": "Progress recorded"
}
| Listener action | Effect |
|---|---|
USE_MAPPING | Keep the built-in state mapping action |
WAIT | Remain at the activity after applying allowed variable mappings |
REPLY | Write a durable continuation command with typed Parts for the same taskId/contextId |
BPMN_ERROR | Throw an allow-listed business error code |
INCIDENT | Keep the activity waiting and create an operator-visible incident |
CANCEL | Write a durable CancelTask command and follow the configured cancellation mapping |
REPLY is allowed only for configured interrupted states. The Process Engine commits it to its
outbox; tsm-ai sends the continuation with a stable new messageId. Authentication challenges
use a server-side credential broker/reference, never credentials in Message Parts.
The mapping restricts which listener actions are legal for each state. A listener cannot complete a non-terminal remote Task, fabricate a terminal state, skip Artifact/result validation, or bypass an approval. Processing order is fixed:
- Deduplicate the response and lock the active BPMN activity.
- Validate the state and referenced content, then compute the provisional mapping and variables; no process transition has happened yet.
- Invoke the listener when
invokeListeneris enabled for that state. - Validate the listener action, variables, terminal-state rules, result contract, and approval.
- Commit the update receipt, listener outcome, variable changes, outbox commands, and final process action in one transaction.
Listener retries reuse the same updateId; exhausted attempts create an incident while the BPMN
activity remains waiting.
Messages, Parts, and Artifacts
An outbound Message contains a unique messageId, role, one or more Parts, and optional
taskId/contextId for a continuation.
| Part | tSM handling |
|---|---|
| Text | UTF-8 content with length, classification, and prompt-injection controls |
| Data | Structured value validated against the configured Form/JSON Schema |
| File | Size-limited content or an authorized governed-document reference |
Task business outputs are read from Artifacts. Every Artifact is verified by media type, size, checksum, schema, caller access, malware policy, and retention policy before it becomes process data. Large inputs and outputs remain in governed document storage and are represented by stable references.
Multi-turn Interaction
- Continue an interrupted Task with its persisted
taskIdandcontextId. - Start permitted related work with an existing
contextIdand notaskId. - Reject a continuation whose IDs do not match the local correlation.
- Apply context expiry and retention independently of process lifetime.
- Route caller input and delegated authentication through explicit modeled paths.
Credentials are exchanged through the configured credential broker or delegated-authentication flow, not through Message Parts.
Update Delivery and Recovery
Polling and reconciliation
Once taskId is persisted, polling calls GetTask after 2, 5, and 10 seconds and then every 30
seconds, always with the 30-second per-call timeout. It is the primary update mode for the initial
implementation and the recovery mode for uncertainty about a known Task. Each changed canonical
snapshot updates the same tsm-ai Outbound A2A Invocation; the remote server remains the Task
authority. Polling policy does not invent a fixed completion time for the remote work.
Future delivery optimizations
SendStreamingMessage, SubscribeToTask, and push-notification configuration may be added later.
Streaming would accelerate updates but would not replace GetTask recovery. Push additionally
requires an authenticated public callback and a bounded callback-credential lifecycle, so it is
outside the initial supported scope.
Cancellation
An interrupting boundary event, process cancellation, or operator action writes a durable cancel
command. The tsm-ai outbound client sends CancelTask for a non-terminal remote Task, reconciles
the authoritative state, and returns the normalized outcome. The Process Engine follows the
configured local cancellation, timeout, or compensation path. A cancellation request and a
business rollback are separate modeled operations.
The Process Engine owns an absolute activity deadline or an explicit UNBOUNDED decision. An
unbounded remote wait is allowed only with visible status, privileged cancellation, and an
escalation/incident path; it is not an implicit default. tsm-ai persists the corresponding local
invocation deadline/unbounded marker. The remote server independently owns its Task and any remote
deadline. Every transport request and polling call remains finite even when the overall activity is
unbounded.
If the remote Task is already terminal or not cancelable, the cancel request does not rewrite that
remote truth. Once local cancellation is durably accepted, however, it is authoritative for the
workflow: a later remote success remains in the invocation and audit history but cannot reactivate or
advance the BPMN activity. The local invocation remains CANCELLATION_PENDING while tsm-ai sends
CancelTask and reconciles the remote Task. Cancellation is best effort and never implies that a
remote business effect was rolled back; an unconfirmed or uncertain effect follows manual review,
incident, and configured compensation policy.
Errors, Retry, and Idempotency
| Condition | Handling |
|---|---|
Authentication challenge / AUTH_REQUIRED | Follow the approved delegated-authentication path |
| Forbidden or unsupported Skill, content, operation, extension, or version | Configuration or authorization incident |
| Task missing or inaccessible | Correlation/security incident |
| Invalid input, Message, reply, or Artifact | Contract incident unless an explicit repair path exists |
Network timeout, rate limit, or temporary server failure before taskId | Retry only the exact persisted Message when the registry's idempotency proof permits it; otherwise stop for review/incident handling |
Network timeout, rate limit, or temporary server failure after taskId | Reconcile with GetTask, then apply bounded transport retry/backoff |
Remote TASK_STATE_FAILED | Apply documented business mapping; otherwise create an incident |
| Delivery uncertainty | Before taskId, exact-message retry under the certified guarantee; after taskId, reconcile with GetTask |
A2A delivery is made safe with the onboarded exact-Message idempotency guarantee, stable Message and
command IDs, the Process Engine outbox/inbox, the tsm-ai invocation inbox/outbox and local update
sequence, and authoritative lookup after the remote Task ID is known. Business side effects and
listener integrations also use their own idempotency keys.
Transport retry, polling, and reconciliation keep the same a2aInvocationId. An uncertain initial
send never fabricates a new Message or changed payload; it retries the exact Message only when the
certified remote contract makes that safe. Once taskId is known, tsm-ai reconciles that remote
Task before continuing. If a terminal A2A activity outcome is mapped to BPMN RETRY, the Process
Engine starts a new linked activity attempt with a new a2aInvocationId. Duplicate delivery of
either start command remains an idempotent no-op, and the activity-level retry/deadline budget spans
all linked invocations.
Security and Operations
- Use TLS to the remote tSM Gateway. The initial integration uses the Gateway's existing
X-API-Keyauthentication andX-Tenant-Idtenant selection; the actual key is resolved only from the configured Secret/Vault reference. - The
tsm-aiclient resolves targets through the tSM Agent Registry and sendsA2A-Version: 1.0. - Enforce tenant, Skill, Invocation Mapping, extension, media type, size, data-egress, rate, concurrency, finite call timeout, and configured activity deadline/unbounded-wait policy before dispatch and on every update.
- Treat remote Messages and Artifacts as untrusted content.
- Keep secrets out of Agent Registry values, BPMN, process variables, databases, events, telemetry,
and logs; sanitize internal errors before external delivery or model context. The remote Gateway
owns API-key exchange/stripping, and
tsm-aiadds no parallel OAuth or token store. - Audit registry/card versions, identity, interface, Skill, Message, remote state, Artifact, retry, approval, cancellation, and resulting business transition.
The process-instance Operations view correlates the BPMN activity with a2aInvocationId, local
messageId, remote taskId/contextId, accepted update sequence, listener attempts, delivery
attempts, current state, Artifacts, incidents, and result mapping. Local Agent Runs appear only when
the process separately invokes tSM Agent Runtime; an Outbound A2A Invocation is a separate record.
Protocol Operations
| Operation | Initial support | Purpose |
|---|---|---|
SendMessage | Yes | Start or continue an interaction |
GetTask | Yes | Read authoritative Task state, Artifacts, and permitted history |
CancelTask | Yes | Request cancellation of a non-terminal Task |
ListTasks(contextId) | Optional | Auxiliary discovery/reconciliation evidence when the approved remote interface supports it; never the sole idempotency guarantee |
SendStreamingMessage | Later | Start or continue while receiving real-time updates |
SubscribeToTask | Later | Subscribe to an existing non-terminal Task stream |
| Push-notification configuration | Later | Manage callback delivery for one Task |
GetExtendedAgentCard | Later | Retrieve identity-scoped additional capabilities |
Standard References
- A2A Protocol 1.0 specification
- Agent discovery and Agent Cards
- Life of an A2A Task
- Streaming and asynchronous operations