Starting from API version 26.0.0, AgentAbilityExtension can implement Agent to Agent (A2A) protocol communication.
The A2A protocol is used for communication between agents. The A2A server is responsible for receiving client requests, triggering agents to execute tasks, updating the task status, and returning execution results.
With Agent Framework Kit, you can build an agent server that supports the A2A protocol within the ArkTS app and deliver the following capabilities:
The A2A protocol supports efficient communication between agents. Its core functions include:
This module provides server APIs for the A2A protocol. For details about the APIs, please refer to the A2A server module API reference.
The following table describes the key APIs.
| API | Description |
|---|---|
| createA2AServer | Creates and obtains a server instance for handling A2A protocol communication. |
| Server | Server instance API responsible for handling agent communication and task lifecycle management. |
| RequestContext | Request context API, which provides context information for the request. |
| OnDataCallback | Event callback function that is triggered when the A2A server receives a client request, initiating the execution of the agent's business logic. |
| Message | Message unit in A2A communication. |
| Task | A2A task, including the task status, artifacts, and message history. |
import { hilog } from '@kit.PerformanceAnalysisKit';
import { common, Want, AgentExtensionAbility } from '@kit.AbilityKit';
import { RequestContext, createA2AServer, Server, TaskState, Role } from '@kit.AgentFrameworkKit'; It is recommended that the server extend AgentExtensionAbility to support inter-process communication (IPC). AgentExtensionAbility provides an IPC-based callback API for handling requests.
Follow the steps below to implement each method in AgentExtensionAbility.
Create the OnDataCallback function to define the agent's business logic.
const TAG = '=====A2AServer===='
export default class MyAgentExtensionAbility extends AgentExtensionAbility {
private server: Server | null = null;
// OnDataCallback function.
private agentOnData = (method: string, context: RequestContext) => {
// Obtain information such as the agent ID from the structured context parameter.
const agentId: string = context.getAgentId() ?? '';
if (!agentId) {
hilog.error(0x0000, TAG, 'Agent ID not found in request context');
return;
}
const taskId: string = context.getTaskId() ?? '';
switch (method) {
case 'Execute':
// Use server.updateStatus to update the task execution status.
this.server?.updateStatus(taskId, {
state: TaskState.WORKING,
message: {
messageId: 'msg1',
role: Role.AGENT,
parts: [{
mediaType: 'text/plain',
text: 'Starting work on your request...'
}]
}
});
// Wait for the agent to generate artifacts.
this.server?.addArtifact(taskId, {
artifactId: 'result-artifact',
parts: [{
mediaType: 'text/plain',
text: '{"action": "completed", "result": "Task finished successfully"}'
}]
});
// Notify the client of task completion.
this.server?.updateStatus(taskId, {
state: TaskState.COMPLETED,
message: {
messageId: 'msg3',
role: Role.AGENT,
parts: [{
mediaType: 'text/plain',
text: 'Task completed successfully!'
}]
}
});
break;
case 'Cancel':
// Instruct the agent to handle the task cancellation request based on the agent ID.
hilog.info(0x0000, TAG, 'Cancel called');
break;
case 'PerceptionSuggest':
hilog.info(0x0000, TAG, `Perception suggest called, metadata: ${JSON.stringify(context.getMetadata(), null, 2)}`);
break;
default:
break;
}
}
} Implement the onCreate method to ensure that the createA2AServer method is called to create an A2A server object when the request is received for the first time.
async onCreate(want: Want) {
try {
const card = this.context.agentCard;
this.server = createA2AServer(card, this.agentOnData, want=want);
} catch (error) {
hilog.error(0x0000, TAG, `Failed to create server: ${error}`);
}
} Implement onConnect, which is triggered when a client establishes a connection, to start the server.
onConnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is connected.
this.server?.start();
} Implement onData, which is triggered when a client request is received, and call server.onMessage to pass the request body.
async onData(proxy: common.AgentHostProxy, data: string) {
// Callback for handling requests.
this.server?.onMessage(data, (response: string) => {
proxy.sendData(response);
});
} Implement onDisconnect to shut down the server when a client connection is terminated.
onDisconnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is disconnected.
this.server?.stop();
} Implement onDestroy to clean up resources when the service object is destroyed.
onDestroy() {
// Clean up resources.
this.server?.stop();
} import { hilog } from '@kit.PerformanceAnalysisKit';
import { common, Want, AgentExtensionAbility } from '@kit.AbilityKit';
import { RequestContext, createA2AServer, Server, TaskState, Role } from '@kit.AgentFrameworkKit';
const TAG = '=====A2AServer===='
export default class MyAgentExtensionAbility extends AgentExtensionAbility {
private server: Server | null = null;
// OnDataCallback function.
private agentOnData = (method: string, context: RequestContext) => {
// Obtain information such as the agent ID from the structured context parameter.
const agentId: string = context.getAgentId() ?? '';
if (!agentId) {
hilog.error(0x0000, TAG, 'Agent ID not found in request context');
return;
}
const taskId: string = context.getTaskId() ?? '';
switch (method) {
case 'Execute':
// Use server.updateStatus to update the task execution status.
this.server?.updateStatus(taskId, {
state: TaskState.WORKING,
message: {
messageId: 'msg1',
role: Role.AGENT,
parts: [{
mediaType: 'text/plain',
text: 'Starting work on your request...'
}]
}
});
// Wait for the agent to generate artifacts.
this.server?.addArtifact(taskId, {
artifactId: 'result-artifact',
parts: [{
mediaType: 'text/plain',
text: '{"action": "completed", "result": "Task finished successfully"}'
}]
});
// Notify the client of task completion.
this.server?.updateStatus(taskId, {
state: TaskState.COMPLETED,
message: {
messageId: 'msg3',
role: Role.AGENT,
parts: [{
mediaType: 'text/plain',
text: 'Task completed successfully!'
}]
}
});
break;
case 'Cancel':
// Instruct the agent to handle the task cancellation request based on the agent ID.
hilog.info(0x0000, TAG, 'Cancel called');
break;
case 'PerceptionSuggest':
hilog.info(0x0000, TAG, `Perception suggest called, metadata: ${JSON.stringify(context.getMetadata(), null, 2)}`);
this.server?.updateStatus(taskId, {
state: TaskState.COMPLETED,
message: {
messageId: 'onChipsMsg1',
role: Role.AGENT,
parts: [{
mediaType: 'text/plain',
text: 'On chips task completed successfully!'
}]
}
});
default:
break;
}
}
async onCreate(want: Want) {
try {
const card = this.context.agentCard;
this.server = createA2AServer(card, this.agentOnData, want=want);
} catch (error) {
hilog.error(0x0000, TAG, `Failed to create server: ${error}`);
}
}
onConnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is connected.
this.server?.start();
}
async onData(proxy: common.AgentHostProxy, data: string) {
// Callback for handling requests.
this.server?.onMessage(data, (response: string) => {
proxy.sendData(response);
});
}
onDisconnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is disconnected.
this.server?.stop();
}
onDestroy() {
// Clean up resources.
this.server?.stop();
}
} The AgentChips request is used by Celia to detect the app currently used by the user and request recommended content from the agent. This section provides an example of how an app responds to a Celia AgentChips request.
Celia sends a PerceptionSuggest request to the app where AgentExtensionAbility is located.
By defining the handling logic for the 'PerceptionSuggest' method in OnDataCallback, the agent can respond according to the sample message format defined in the Celia AgentChips interaction flow.
The following is an example of implementing OnDataCallback in the AgentChips scenario:
export default class MyAgentExtensionAbility extends AgentExtensionAbility {
private server: Server | null = null;
// Define the business processing logic of the agent.
private agentOnData: OnDataCallback = (method: string, context: RequestContext) => {
switch (method) {
// Type of the request from Celia.
case 'PerceptionSuggest':
// Obtain the task ID.
const taskId = context.getTaskId();
// Generate an artifact ID. A fixed value is used in this example.
const artId = 'artifact-1';
if (!taskId) {
console.error(TAG, "Task ID not found in request context");
return;
}
// Simulate the agent analyzing recommendation results and return the recommendations to Celia.
this.server?.addArtifact(taskId, {
artifactId: artId,
parts: [
{
data: {
suggestionCandidates: [
{
text: "Latest TV series",
reply: "Latest TV series",
}
]
},
mediaType: "application/json"
}
],
append: false,
lastChunk: true
});
// Notify the client of the completion of the AgentChips task.
this.server?.updateStatus(taskId, {
state: TaskState.COMPLETED,
message: {
messageId: "demo-msg-123",
role: Role.AGENT,
parts: [{
mediaType: "text/plain",
text: "Task completed successfully!"
}]
}
});
default:
break;
}
}
async onCreate(want: Want) {
try {
const card = this.context.agentCard;
this.server = createA2AServer(card, this.agentOnData, want=want);
} catch (error) {
hilog.error(0x0000, TAG, `Failed to create server: ${error}`);
}
}
onConnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is connected.
this.server?.start();
}
async onData(proxy: common.AgentHostProxy, data: string) {
// Callback for handling requests.
this.server?.onMessage(data, (response: string) => {
proxy.sendData(response);
});
}
onDisconnect(want: Want, proxy: common.AgentHostProxy) {
// Callback triggered when the client is disconnected.
this.server?.stop();
}
onDestroy() {
// Clean up resources.
this.server?.stop();
}
}