@agentic-profile/a2a-client
TypeScript icon, indicating that this package has built-in type declarations

0.6.2 • Public • Published

Typescript/Javascript A2A Client with Agentic Profile support

This project contains a TypeScript client implementation for the Agent-to-Agent (A2A) communication protocol that is derived from Google's A2A sample code. This client is suitable for use in browsers or servers and is available as an easy-to-use NPM package.

For a demonstration of this library and examples of its implemention, please download the SDK

Additional support has been added for Agentic Profiles which scope agents by users and businesses, give those entities globally unique ids, and provide universal authentication. All these new capabilites are accomplished with standards (W3C DID documents, IETF JWK) and minimal glue code.

Key Features of the Client

  • Globally Unique Agent Ids: Scoped to users and businesses, to enable much easier discovery and powerful features like reputation.
  • Universal Authentication: Leverages DID document authentication methods such as JSON Web Keys.
  • JSON-RPC Communication: Handles sending requests and receiving responses (both standard and streaming via Server-Sent Events) according to the JSON-RPC 2.0 specification.
  • A2A Methods: Implements standard A2A methods like sendTask, sendTaskSubscribe, getTask, cancelTask, setTaskPushNotification, getTaskPushNotification, and resubscribeTask.
  • Error Handling: Provides basic error handling for network issues and JSON-RPC errors.
  • Streaming Support: Manages Server-Sent Events (SSE) for real-time task updates (sendTaskSubscribe, resubscribeTask).
  • Extensibility: Allows providing a custom fetch implementation for different environments (e.g., Node.js).

Quickstart

For a demonstration of this library and examples of its implemention, please download the SDK and follow the instructions there.

Basic Usage

import {
  A2AClient,
  Task,
  TaskQueryParams,
  TaskSendParams
} from "@agentic-profile/a2a-client";
import { v4 as uuidv4 } from "uuid"; // Example for generating task IDs

const client = new A2AClient("http://localhost:41241"); // Replace with your server URL

async function run() {
  try {
    // Send a simple task (pass only params)
    const taskId = uuidv4();
    const sendParams: TaskSendParams = {
      id: taskId,
      message: { role: "user", parts: [{ text: "Hello, agent!", type: "text" }] },
    };
    // Method now returns Task | null directly
    const taskResult: Task | null = await client.sendTask(sendParams);
    console.log("Send Task Result:", taskResult);

    // Get task status (pass only params)
    const getParams: TaskQueryParams = { id: taskId };
    // Method now returns Task | null directly
    const getTaskResult: Task | null = await client.getTask(getParams);
    console.log("Get Task Result:", getTaskResult);
  } catch (error) {
    console.error("A2A Client Error:", error);
  }
}

run();

Streaming Usage

import {
  A2AClient,
  TaskStatusUpdateEvent,
  TaskArtifactUpdateEvent,
  TaskSendParams, // Use params type directly
} from "@agentic-profile/a2a-client";
import { v4 as uuidv4 } from "uuid";

const client = new A2AClient("http://localhost:41241");

async function streamTask() {
  const streamingTaskId = uuidv4();
  try {
    console.log(`\n--- Starting streaming task ${streamingTaskId} ---`);
    // Construct just the params
    const streamParams: TaskSendParams = {
      id: streamingTaskId,
      message: { role: "user", parts: [{ text: "Stream me some updates!", type: "text" }] },
    };
    // Pass only params to the client method
    const stream = client.sendTaskSubscribe(streamParams);

    // Stream now yields the event payloads directly
    for await (const event of stream) {
      // Type guard to differentiate events based on structure
      if ("status" in event) {
        // It's a TaskStatusUpdateEvent
        const statusEvent = event as TaskStatusUpdateEvent; // Cast for clarity
        console.log(
          `[${streamingTaskId}] Status Update: ${statusEvent.status.state} - ${
            statusEvent.status.message?.parts[0]?.text ?? "No message"
          }`
        );
        if (statusEvent.final) {
          console.log(`[${streamingTaskId}] Stream marked as final.`);
          break; // Exit loop when server signals completion
        }
      } else if ("artifact" in event) {
        // It's a TaskArtifactUpdateEvent
        const artifactEvent = event as TaskArtifactUpdateEvent; // Cast for clarity
        console.log(
          `[${streamingTaskId}] Artifact Update: ${
            artifactEvent.artifact.name ??
            `Index ${artifactEvent.artifact.index}`
          } - Part Count: ${artifactEvent.artifact.parts.length}`
        );
        // Process artifact content (e.g., artifactEvent.artifact.parts[0].text)
      } else {
        console.warn("Received unknown event structure:", event);
      }
    }
    console.log(`--- Streaming task ${streamingTaskId} finished ---`);
  } catch (error) {
    console.error(`Error during streaming task ${streamingTaskId}:`, error);
  }
}

streamTask();

This client is designed to work with servers implementing the A2A protocol specification.

Enhancing A2A with the Agentic Profile

The Agentic Profile is a thin layer over A2A, MCP, and other HTTP protocols, and provides:

  • Globally unique - user and business scoped - agent identity
  • Universal authentication

The Agentic Profile is standards based:

  • W3C DIDs and DID documents provide globally unique ids that are scoped to users and businesses
  • IETF JSON Web Keys provide universal authentication

Why do we need user and business scoped agent identity?

Identity is essential for digital communication between parties because it establishes trust, accountability, and context — without which meaningful, secure interaction is nearly impossible.

Current agent protocols focus on individual agent identity, which while accomplishing the communications goal, does not establish trust and accountability which derive from clear relationships with the people or business the agent represents.

For example, you trust an employee of a bank because they are in the bank building, behind the counter, and wearing a company nametag.

How does the Agentic Profile solve this?

The Agentic Profile provides the digital equivalent of how we judge employees, by using a verifiable document provided by the person or business, and declaring all the agents that represent the person or business.

For example the business at the DNS domain matchwise.ai can have a "chat-agent", which combined becomes matchwise.ai#chat-agent. Concensys helped create the DID specification which has a URI format that results in did:web:matchwise.ai#chat-agent. DID documents (what you find using the did:web:matchwise.ai URI) provides a list of HTTP services, which are equivalent to agents. The Agentic Profile simply lists the agents in the DID document services.

With the Agentic Profile, the person or business is the first class citizen, and all the agents that represent them are clearly defined.

How does A2A fit in?

Very easily. For each DID document service/agent, we specify the "type" as "A2A" and use the serviceEndpoint to reference the agent.json file.

Why do we need decentralized authentication?

Most agent authentication is done using shared keys and HTTP Authorization headers. While this is easy to implement, it is very insecure.

Another popular option is OAuth, but that has another host of problems including dramatically increasing the attack surface and the challenges of making sure both agents agree on the same authentication service provider. OAuth is really good for human-to-service authentication, but not very good for dynamic environments where the agent might have to create a new account with a new authentication service or complete MFA.

How does the Agentic Profile solve this?

Public key cryptography, which is used extensively for internet communication, is ideal for decentralized authentication. It is very easy to publish an agents public key via the Agentic Profile, and then the agent can use its secret key to authenticate. JSON Web Tokens + EdDSA are mature and widely used standards, and the ones Agentic Profile uses.

With great options like JWT+EdDSA, centralized authentication systems like OAuth are unecessary.

Readme

Keywords

none

Package Sidebar

Install

npm i @agentic-profile/a2a-client

Weekly Downloads

84

Version

0.6.2

License

Apache-2

Unpacked Size

780 kB

Total Files

69

Last publish

Collaborators

  • mikeprince