TrustedAgent
TrustedAgent is a connection handle representing a trusted communication channel to a remote A2A agent. It wraps the A2A protocol client with trust verification, conversation context tracking, and persistent state management.
import { TrustedAgent } from "@a2aletheia/a2a";
Obtaining a TrustedAgent
You do not construct TrustedAgent instances directly. Instead, obtain one through AletheiaA2A.connect():
import { AletheiaA2A } from "@a2aletheia/a2a";
const client = new AletheiaA2A({ registryUrl: "https://registry.example.com" });
const agent = await client.connect("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK");
// agent is a TrustedAgent instance
const response = await agent.send("Hello!");
Properties
did
readonly did: string | null
The DID (Decentralized Identifier) of the connected agent. null if the agent was resolved from an endpoint URL rather than a DID.
agent
agent: Agent | null
The full agent record from the Aletheia registry. Contains metadata like name, trustScore, isLive, isBattleTested. null if the agent was resolved from an endpoint URL without registry lookup.
agentCard
readonly agentCard: AgentCard
The A2A Agent Card describing the agent’s capabilities, skills, and supported interaction modes. This is fetched from the agent’s /.well-known/agent-card.json endpoint.
See: A2A Agent Card Specification
trustInfo
trustInfo: TrustInfo
Trust verification data for the connected agent.
| Property | Type | Description |
|---|---|---|
didVerified |
boolean |
Whether the agent’s DID was cryptographically verified |
isLive |
boolean |
Whether the agent responded to a recent liveness check |
trustScore |
number \| null |
Agent’s trust score from the registry (null if unavailable) |
isBattleTested |
boolean |
Whether the agent has passed battle testing in production |
responseVerified |
boolean \| null |
Whether the response signature was verified (Phase 2+) |
verifiedAt |
Date |
Timestamp of when trust data was last verified |
supportsStreaming
get supportsStreaming(): boolean
Returns true if the agent supports streaming responses via SSE. Determined by checking agentCard.capabilities.streaming.
if (agent.supportsStreaming) {
for await (const event of agent.stream("Hello!")) {
console.log(event.kind, event.event);
}
} else {
const response = await agent.send("Hello!");
}
supportsPushNotifications
get supportsPushNotifications(): boolean
Returns true if the agent supports push notifications for task updates. Determined by checking agentCard.capabilities.pushNotifications.
contextId
get contextId(): string | undefined
The conversation context ID from the most recent exchange. Used to maintain conversation continuity across multiple messages. Populated after the first send() or stream() call.
lastTaskId
get lastTaskId(): string | undefined
The task ID from the most recent exchange. Can be used to query task status or resubscribe to a streaming task.
Methods
restoreContext()
async restoreContext(): Promise<void>
Restores conversation context (contextId and lastTaskId) from the persistent store. Called automatically by AletheiaA2A after constructing a new TrustedAgent instance.
Parameters: None
Returns: Promise<void>
Important: This method is called automatically and rarely needs manual invocation. It’s used internally to survive process restarts or serverless cold-starts when a ContextStore is configured.
// Automatic flow - AletheiaA2A calls this for you
const agent = await client.connect(did);
// Context already restored if persisted previously
// Manual restoration (rarely needed)
await agent.restoreContext();
send(input, options?)
async send(
input: string | MessageInput,
options?: SendOptions
): Promise<TrustedResponse>
Sends a message to the agent and waits for a response. Automatically carries forward conversation context (contextId and lastTaskId) for multi-turn conversations.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
input |
string \| MessageInput |
Yes | The message content. Strings are converted to text parts. Use MessageInput for structured data. |
options |
SendOptions |
No | Additional send configuration |
SendOptions Interface:
| Property | Type | Default | Description |
|---|---|---|---|
acceptedOutputModes |
string[] |
["text/plain", "application/json"] |
MIME types the client accepts |
blocking |
boolean |
true |
Whether to wait for task completion |
contextId |
string |
Tracked context | Explicit context ID (overrides tracked value) |
taskId |
string |
Tracked task | Explicit task ID (overrides tracked value) |
timeoutMs |
number |
- | Request timeout in milliseconds |
MessageInput Interface:
| Property | Type | Description |
|---|---|---|
text |
string |
Text content |
data |
Record<string, unknown> |
Structured data payload |
parts |
Part[] |
Raw A2A message parts |
contextId |
string |
Context ID to use |
taskId |
string |
Task ID to continue |
Returns: Promise<TrustedResponse>
TrustedResponse Interface:
| Property | Type | Description |
|---|---|---|
response |
Task \| Message |
The A2A response object |
trustInfo |
TrustInfo |
Current trust verification data |
agentDid |
string \| null |
Agent’s DID |
agentName |
string |
Agent’s display name |
duration |
number |
Request duration in milliseconds |
Example:
// Simple text message
const response = await agent.send("What is the weather today?");
console.log(response.agentName, "replied in", response.duration, "ms");
// Structured message with data
const response = await agent.send({
text: "Analyze this data",
data: { temperature: 72, humidity: 45 }
});
// First message starts a conversation
const r1 = await agent.send("My name is Alice");
console.log("Context:", agent.contextId); // Defined now
// Subsequent messages continue the conversation
const r2 = await agent.send("What's my name?"); // Context carried forward
Context Tracking: After each send(), contextId and lastTaskId are updated from the response, enabling automatic conversation continuity.
stream(input, options?)
async *stream(
input: string | MessageInput,
options?: SendOptions
): AsyncGenerator<TrustedStreamEvent>
Sends a message and receives streaming events via Server-Sent Events (SSE). Use this for real-time responses from agents that support streaming.
Parameters: Same as send()
Returns: AsyncGenerator<TrustedStreamEvent>
TrustedStreamEvent Interface:
| Property | Type | Description |
|---|---|---|
event |
A2AStreamEventData |
The raw A2A event (Message, Task, StatusUpdate, or ArtifactUpdate) |
kind |
"message" \| "task" \| "status-update" \| "artifact-update" |
Event type discriminator |
agentDid |
string \| null |
Agent’s DID |
trustInfo |
TrustInfo |
Current trust verification data |
Example:
if (!agent.supportsStreaming) {
throw new Error("Agent does not support streaming");
}
for await (const event of agent.stream("Write a poem about AI")) {
switch (event.kind) {
case "status-update":
console.log("Status:", event.event.status?.state);
break;
case "artifact-update":
console.log("Artifact:", event.event.artifact);
break;
case "task":
console.log("Task completed:", event.event.id);
break;
case "message":
console.log("Message:", event.event);
break;
}
}
// Context tracked after streaming completes
console.log("Context ID:", agent.contextId);
Context Tracking: Context is tracked from streaming events. The contextId and lastTaskId are populated from the first task event received.
getTask(taskId)
async getTask(taskId: string): Promise<TrustedTaskResponse>
Retrieves the current state of a task by its ID. Use this to check task status after a non-blocking send() or to poll long-running tasks.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID to query |
Returns: Promise<TrustedTaskResponse>
TrustedTaskResponse Interface:
| Property | Type | Description |
|---|---|---|
response |
Task |
The task object with current state |
trustInfo |
TrustInfo |
Current trust verification data |
agentDid |
string \| null |
Agent’s DID |
agentName |
string |
Agent’s display name |
Example:
// Non-blocking send returns immediately
const response = await agent.send("Generate a report", { blocking: false });
const taskId = response.response.id; // Task ID
// Poll for completion
let task = await agent.getTask(taskId);
while (task.response.status?.state !== "completed") {
await new Promise(r => setTimeout(r, 1000));
task = await agent.getTask(taskId);
}
console.log("Task completed:", task.response.artifacts);
cancelTask(taskId)
async cancelTask(taskId: string): Promise<TrustedTaskResponse>
Cancels a running task by its ID. The agent will attempt to stop processing and mark the task as canceled.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID to cancel |
Returns: Promise<TrustedTaskResponse>
Example:
// Start a long-running task
const response = await agent.send("Process this large file", { blocking: false });
const taskId = response.response.id;
// Cancel if taking too long
setTimeout(async () => {
const canceled = await agent.cancelTask(taskId);
console.log("Task canceled:", canceled.response.status?.state);
}, 30000);
resubscribeTask(taskId)
async *resubscribeTask(taskId: string): AsyncGenerator<TrustedStreamEvent>
Resubscribes to an existing task’s event stream. Use this to reconnect to streaming events after a connection interruption.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID to resubscribe to |
Returns: AsyncGenerator<TrustedStreamEvent> - Same event types as stream()
Example:
// Original streaming connection lost
const taskId = agent.lastTaskId;
// Reconnect to the task stream
for await (const event of agent.resubscribeTask(taskId!)) {
console.log(event.kind, event.event);
}
refreshCard()
async refreshCard(): Promise<AgentCard>
Fetches a fresh Agent Card from the agent’s endpoint and updates the agentCard property. Use this to get updated capabilities or metadata.
Parameters: None
Returns: Promise<AgentCard>
Example:
// Check if agent now supports streaming
const card = await agent.refreshCard();
if (card.capabilities?.streaming) {
console.log("Agent now supports streaming!");
}
refreshTrust()
async refreshTrust(): Promise<TrustInfo>
Re-fetches the agent record from the Aletheia registry and updates trustInfo and agent properties. Call this to get fresh isLive, trustScore, and isBattleTested values.
Parameters: None
Returns: Promise<TrustInfo>
Important: Only works when the agent was resolved via DID from a registry. Returns current trustInfo if agent has no DID or no registry client is configured.
Example:
// Check if agent is still live before critical operation
const trust = await agent.refreshTrust();
if (!trust.isLive) {
throw new Error("Agent is not responding to liveness checks");
}
if (trust.trustScore !== null && trust.trustScore < 0.8) {
console.warn("Agent trust score dropped:", trust.trustScore);
}
resetContext()
resetContext(): void
Clears conversation context (contextId and lastTaskId). The next send() or stream() call will start a fresh conversation.
Parameters: None
Returns: void
When to Use:
- Starting a new conversation with the same agent
- Clearing context after completing a multi-turn interaction
- Resetting after an error that corrupted conversation state
Example:
// Multi-turn conversation
await agent.send("Book a flight to Paris");
await agent.send("Add a hotel reservation");
// Start fresh conversation
agent.resetContext();
await agent.send("What's the weather in Tokyo?"); // New context
Persistence: If a ContextStore is configured, this method also deletes the persisted context from the store.
setUserDelegation(delegation)
setUserDelegation(delegation: UserDelegationEnvelope | null): void
Attach a user delegation envelope to all subsequent outbound messages. Call with null to clear.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
delegation |
UserDelegationEnvelope \| null |
Yes | Delegation envelope from user wallet signature, or null to clear |
Returns: void
When to Use:
- After user signs delegation via MetaMask/wagmi on frontend
- Before calling
send()orstream()that requires user authorization - To clear delegation when switching users
Example:
// Frontend: user signs with wagmi
const signature = await signTypedDataAsync({
domain: DELEGATION_DOMAIN,
types: DELEGATION_TYPES,
primaryType: "UserDelegation",
message: delegation,
});
// Backend: attach to TrustedAgent
agent.setUserDelegation({ delegation, signature });
// Subsequent messages carry the delegation
await agent.send("Book a hotel room");
// Clear when done
agent.setUserDelegation(null);
setTaskPushNotificationConfig(config)
async setTaskPushNotificationConfig(
config: TaskPushNotificationConfig
): Promise<TaskPushNotificationConfig>
Configure push notifications for a task. Requires supportsPushNotifications to be true.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
config |
TaskPushNotificationConfig |
Yes | Push notification configuration |
Returns: Promise<TaskPushNotificationConfig>
Example:
if (agent.supportsPushNotifications) {
await agent.setTaskPushNotificationConfig({
taskId: "task-123",
pushNotificationConfig: {
url: "https://my-app.com/webhook",
},
});
}
getTaskPushNotificationConfig(taskId)
async getTaskPushNotificationConfig(
taskId: string
): Promise<TaskPushNotificationConfig>
Get the push notification configuration for a task.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID |
Returns: Promise<TaskPushNotificationConfig>
listTaskPushNotificationConfig(taskId)
async listTaskPushNotificationConfig(
taskId: string
): Promise<TaskPushNotificationConfig[]>
List all push notification configurations for a task.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID |
Returns: Promise<TaskPushNotificationConfig[]>
deleteTaskPushNotificationConfig(taskId, configId)
async deleteTaskPushNotificationConfig(
taskId: string,
configId: string
): Promise<void>
Delete a push notification configuration.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string |
Yes | The task ID |
configId |
string |
Yes | The push notification config ID |
Returns: Promise<void>
Context Tracking
TrustedAgent automatically tracks conversation context across message exchanges:
How It Works
- First Message:
contextIdandlastTaskIdareundefined - After Response: Both are populated from the A2A response
- Subsequent Messages: Values are automatically included in requests
- Persistence: With a
ContextStore, context survives process restarts
Overriding Context
Explicitly pass contextId or taskId in options to override tracked values:
// Override to join existing conversation
await agent.send("Hello!", { contextId: "existing-context-123" });
// Override to continue specific task
await agent.send("Continue", { taskId: "task-456" });
Context Lifecycle
// New conversation
await agent.send("Hello"); // contextId: undefined -> "ctx-1"
// Continue conversation
await agent.send("How are you?"); // Uses contextId: "ctx-1"
// Reset for new conversation
agent.resetContext(); // contextId: undefined
// Start fresh
await agent.send("New topic"); // contextId: undefined -> "ctx-2"