https://github.com/the-artinet-project/artinet-sdk
A JS/TS SDK for the Agent2Agent Protocol
https://github.com/the-artinet-project/artinet-sdk
a2a a2a-protocol agent2agent agents ai aiagents aiagentsframework artificial-intelligence mcp
Last synced: 5 months ago
JSON representation
A JS/TS SDK for the Agent2Agent Protocol
- Host: GitHub
- URL: https://github.com/the-artinet-project/artinet-sdk
- Owner: the-artinet-project
- License: apache-2.0
- Created: 2025-04-25T20:10:21.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-05-10T17:55:55.000Z (5 months ago)
- Last Synced: 2025-05-10T17:58:12.511Z (5 months ago)
- Topics: a2a, a2a-protocol, agent2agent, agents, ai, aiagents, aiagentsframework, artificial-intelligence, mcp
- Language: TypeScript
- Homepage: https://artinet.io/
- Size: 196 KB
- Stars: 12
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-a2a - Artinet SDK - artinet-project](https://github.com/the-artinet-project) [](https://github.com/the-artinet-project/artinet-sdk) - TypeScript (Node.js) A2A compliant server/client simplifying interoperable AI agent creation, focusing on DX and production-readiness. (⚙️ Implementations & Libraries)
README
[](https://www.npmjs.com/package/@artinet/sdk)
[](https://www.npmjs.com/package/@artinet/sdk)
[](LICENSE)
[](https://snyk.io/test/npm/@artinet/sdk)# Artinet SDK
Artinet SDK is a [Agent2Agent (A2A) Protocol](https://github.com/google/A2A) compliant server and client written in TypeScript for [node.js](https://nodejs.org/) that aims to simplify the creation of interoperable AI agents. Learn more at [the artinet project](https://artinet.io/).
This SDK significantly enhances the foundational A2A concepts and samples provided by Google, offering a production-ready solution with a focus on developer experience, reliability, and comprehensive features.
## Table of Contents
- [Artinet SDK](#artinet-sdk)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Installation](#installation)
- [Requirements](#requirements)
- [Example](#example)
- [Class Documentation](#class-documentation)
- [Core Classes](#core-classes)
- [Key Types \& Interfaces](#key-types--interfaces)
- [Running Tests](#running-tests)
- [Typescript](#typescript)
- [Usage](#usage)
- [Client](#client)
- [Basic Client Usage](#basic-client-usage)
- [Streaming Updates](#streaming-updates)
- [Authentication](#authentication)
- [Server](#server)
- [Implementing an A2A Agent](#implementing-an-a2a-agent)
- [Persistent Storage](#persistent-storage)
- [Logging](#logging)
- [Server Registration \& Discovery](#server-registration--discovery)
- [Advanced Server Customization](#advanced-server-customization)
- [Quick-Agents (Alpha)](#quick-agents-alpha)
- [Contributing](#contributing)
- [License](#license)
- [Acknowledgements](#acknowledgements)## Features
- **Plug-and-Play Server:** Built on Express.js, the `A2AServer` handles JSON-RPC complexity, routing, protocol compliance, and Server-Sent Events (SSE) streaming mechanics automatically. Just provide your core agent logic (`TaskHandler`) and configuration via `A2AServerParams`.
- **Enhanced Client:** `A2AClient` features refined error handling (`RpcError`), flexible header management for authentication, and clear separation of concerns.
- **TypeScript First:** Fully written in TypeScript with comprehensive type definitions for a robust developer experience.
- **Flexible Storage:** Offers built-in `InMemoryTaskStore` (development/testing) and `FileStore` (persistent), with the `TaskStore` interface allowing custom storage solutions.
- **Protocol Compliance:** Implements the complete A2A specification using the official JSON schema, ensuring interoperability.
- **Robust Streaming:** Reliable SSE support for `tasks/sendSubscribe` & `tasks/resubscribe` using `eventsource-parser`.
- **Configurable Logging:** Integrated structured logging via `pino`. Configurable levels using `configureLogger` and `LogLevel`.
- **Advanced Customization:** Allows providing a custom `JSONRPCServerFactory` for fine-grained control over the JSON-RPC server, enabling integration with existing Express apps or adding custom methods.
- **Comprehensive Testing:** Includes a suite of tests to ensure reliability and maintainability.
- **Code Deployment (Beta)** | Bundle, test, and (soon) deploy agent code. Includes bundler, task wrapper, and test deployment utility. | `bundle`, `testDeployment`, `taskHandlerProxy`, `fetchResponseProxy`, `ServerDeploymentRequestParams`, `ServerDeploymentResponse` || Component/Feature | Description | Key Classes/Types |
| :------------------ | :-------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- |
| **Client** | Interact with A2A-compliant agents. Supports standard & streaming requests. | `A2AClient`, `RpcError` |
| **Server** | Host A2A-compliant agents. Handles protocol details, routing, SSE. | `A2AServer`, `A2AServerParams` |
| **Task Handling** | Define agent logic using async generators. | `TaskHandler`, `TaskContext`, `TaskYieldUpdate` |
| **Storage** | Persist task state. In-memory and file-based options included. | `TaskStore`, `InMemoryTaskStore`, `FileStore` |
| **Streaming (SSE)** | Handle real-time updates via SSE for `tasks/sendSubscribe`/`resubscribe`. | `TaskStatusUpdateEvent`, `TaskArtifactUpdateEvent` |
| **Logging** | Configure structured logging for debugging and monitoring. | `logger`, `configureLogger`, `LogLevel` |
| **Advanced Server** | Customize the underlying JSON-RPC server or integrate into existing apps. | `JSONRPCServerFactory`, `CreateJSONRPCServerParams`, `createJSONRPCMethod`, A2A Method Types |
| **Core Types** | Based on the official A2A JSON Schema. | `AgentCard`, `Task`, `Message`, `Part`, `Artifact`, etc. |## Installation
```bash
npm install @artinet/sdk
```## Requirements
- Node.js (v22.0.0 or higher recommended, check `package.json` engines for exact requirement)
## Example
A basic A2A server and client interaction. For more detailed examples, see the `examples/` directory.**1. Server (`quick-server.ts`)**
```typescript
import {
A2AServer,
TaskContext,
TaskHandler,
InMemoryTaskStore,
} from "@artinet/sdk";// Minimal agent logic: receive text, yield working state, yield completed state with echo
const quickAgentLogic: TaskHandler = async function* (context: TaskContext) {
const userInput =
context.userMessage.parts[0].type === "text"
? context.userMessage.parts[0].text
: "";
yield { state: "working" };
// Simulate some work if needed, check context.isCancelled()
yield {
state: "completed",
message: {
role: "agent",
parts: [{ type: "text", text: `You said: ${userInput}` }],
},
};
};const server = new A2AServer({
taskHandler: quickAgentLogic,
taskStore: new InMemoryTaskStore(),
port: 4000,
basePath: "/a2a",
card: {
name: "QuickStart Agent",
url: "http://localhost:4000/a2a",
version: "0.1.0",
capabilities: { streaming: true },
skills: [{ id: "echo", name: "Echo Skill" }],
},
});server.start();
console.log("A2A Server running at http://localhost:4000/a2a");
```**2. Client (`quick-client.ts`)**
```typescript
import { A2AClient, TaskStatusUpdateEvent } from "@artinet/sdk";async function runClient() {
const client = new A2AClient("http://localhost:4000/a2a");const message = {
role: "user" as const,
parts: [{ type: "text" as const, text: "Hello Quick Start!" }],
};const stream = client.sendTaskSubscribe({ id: "quick-task-1", message });
for await (const update of stream) {
// process the update
...
}
console.log("Stream finished.");
}runClient().catch(console.error);
```## Class Documentation
The Artinet SDK provides several core classes and interfaces for building A2A clients and servers.
### Core Classes
| Class | Description |
| :------------------ | :------------------------------------------------------------------ |
| `A2AClient` | Client for interacting with A2A servers. |
| `A2AServer` | Express-based server implementation for hosting A2A agents. |
| `RpcError` | Represents client-side errors encountered during A2A communication. |
| `InMemoryTaskStore` | Simple in-memory task persistence (ideal for development/testing). |
| `FileStore` | File-based task persistence (stores task data in the filesystem). |### Key Types & Interfaces
| Type/Interface | Description |
| :-------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
| `TaskHandler` | Async generator function defining the core agent logic (`async function*(context: TaskContext): AsyncGenerator`). |
| `TaskContext` | Provides task details (`task`, `userMessage`, `history`, `isCancelled()`) to the `TaskHandler`. |
| `TaskStore` | Interface defining the contract for task persistence implementations (like `InMemoryTaskStore`, `FileStore`). |
| `TaskYieldUpdate` | Union type for updates yielded by a `TaskHandler` (representing status changes or generated artifacts). |
| `A2AServerParams` | Configuration object passed to the `A2AServer` constructor (port, store, card, basePath, handler, etc.). |
| `AgentCard` | Describes the agent's capabilities, metadata, skills, and endpoint URL. |
| `Message`, `Part`, `Artifact`, `Task`, `TaskStatus`, etc. | Core types mirroring the structures defined in the A2A JSON Schema specification. Used for requests, responses, and task state. |
| `TaskStatusUpdateEvent`, `TaskArtifactUpdateEvent` | Specific types for Server-Sent Events (SSE) received during streaming operations (`tasks/sendSubscribe`, `tasks/resubscribe`). |
| `LogLevel` | Enum defining logging levels (`error`, `warn`, `info`, `debug`, `trace`) used with the built-in logger. |
| `JSONRPCServerFactory` | Function signature for providing a custom JSON-RPC server creation logic to `A2AServer` for advanced customization. |
| `CreateJSONRPCServerParams` | Object containing dependencies provided _to_ a `JSONRPCServerFactory` function. |
| `SendTaskMethod`, `GetTaskMethod`, ... | Type signatures for specific A2A method handlers, used when implementing custom server logic with `createJSONRPCMethod`. |## Running Tests
```bash
npm test
```To run tests with coverage:
```bash
npm run test:coverage
```## Typescript
The Artinet SDK is written entirely in TypeScript and includes comprehensive type definitions, providing strong typing and enhanced developer experience.
## Usage
### Client
Interact with A2A-compliant agents using the `A2AClient`. See `examples/` for more.
#### Basic Client Usage
Send a task using `tasks/send`.
```typescript
import { A2AClient, Message } from "@artinet/sdk";async function runBasicTask() {
const client = new A2AClient("https://your-a2a-server.com/a2a");
const message: Message = {
role: "user",
parts: [{ type: "text", text: "What is the capital of France?" }],
};const task = await client.sendTask({ id: "basic-task-1", message });
console.log("Task Completed:", task);
}
```#### Streaming Updates
Receive real-time updates via SSE using `tasks/sendSubscribe` (recommended).
```typescript
import {
A2AClient,
Message,
TaskStatusUpdateEvent,
TaskArtifactUpdateEvent,
} from "@artinet/sdk";async function runStreamingTask() {
const client = new A2AClient("https://your-a2a-server.com/a2a");
const message: Message = {
role: "user",
parts: [{ type: "text", text: "Tell me a short story." }],
};const stream = client.sendTaskSubscribe({ id: "streaming-task-1", message });
for await (const update of stream) {
if ((update as TaskStatusUpdateEvent).status) {
console.log("Status:", (update as TaskStatusUpdateEvent).status.state);
} else if ((update as TaskArtifactUpdateEvent).artifact) {
console.log(
"Artifact:",
(update as TaskArtifactUpdateEvent).artifact.name
);
}
}
console.log("Stream finished.");
}
```#### Authentication
Add headers using `addHeader` or `setHeaders`.
```typescript
import { A2AClient } from "@artinet/sdk";const client = new A2AClient("https://your-secure-a2a-server.com/a2a");
// Add a single header
client.addHeader("Authorization", "Bearer your-api-token");// Set multiple headers (overwrites existing)
client.setHeaders({ Authorization: "Bearer ...", "X-Custom": "value" });
```### Server
Host agents using `A2AServer`. Handles protocol details. See `examples/` for more.
#### Implementing an A2A Agent
Define agent behavior with an async generator `TaskHandler`.
```typescript
import {
A2AServer,
TaskContext,
TaskHandler,
InMemoryTaskStore,
} from "@artinet/sdk";const myAgent: TaskHandler = async function* (context: TaskContext) {
yield {
state: "working",
message: {
role: "agent",
parts: [{ type: "text", text: "Processing..." }],
},
};// Check context.isCancelled() if operation is long
// await someAsyncTask();
...yield {
name: "result.txt",
mimeType: "text/plain",
parts: [{ type: "text", text: "Report data" }],
};yield {
state: "completed",
message: {
role: "agent",
parts: [{ type: "text", text: "Finished processing." }],
},
};
};const myServer = new A2AServer({
taskHandler: myAgent,
taskStore: new InMemoryTaskStore(),
port: 3000,
basePath: "/a2a",
card: {
name: "Example Agent",
url: "http://localhost:3000/a2a",
version: "1.0.0",
capabilities: { streaming: true },
skills: [{ id: "processor", name: "Text Processor" }],
},
});myServer.start();
console.log("A2A Server running on http://localhost:3000/a2a");
```#### Persistent Storage
Use `FileStore` for file-based persistence. Ensure the directory exists.
```typescript
import path from "path";
import fs from "fs";const dataDir = path.join(process.cwd(), "a2a-data");
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}const myStore = new FileStore(dataDir);
const myServer = new A2AServer({
taskStore: myStore,
...
});
```#### Logging
Use the built-in `pino`-based logger. Configure with `configureLogger`.
```typescript
import { logger, configureLogger, LogLevel, logDebug } from "@artinet/sdk";// Configure logging level (optional)
configureLogger({ level: "debug" });logger.info("Server starting...");
//use helper functions
logDebug("LoggerTest", { taskId: "task-123" }, "Task status updated.");// Create child logger with bound context
const taskLogger = logger.child({ taskId: "abc" });
taskLogger.info("Processing step X");
```#### Server Registration & Discovery
The SDK includes features to help make your agent discoverable:
- **Automatic Registration:** You can configure your `A2AServer` to automatically register your `AgentCard` with the [A2A Registry](https://artinet.io) upon startup by setting `register: true` (default: `false`) in the server parameters.
```typescript
const myServer = new A2AServer({
...
card: {
...
url: "http://my-public-domain:3000/my-agent", // Publicly accessible URL
...
},
register: true, // Enable automatic registration on start
});
```- **Custom Agent Card Path:** By default, the server exposes its `AgentCard` at `/.well-known/agent.json` [RFC8615](https://datatracker.ietf.org/doc/html/rfc8615) and a fallback at `/agent-card`. You can specify a different fallback path using the `fallbackPath` option in `A2AServerParams`.
```typescript
const myServer = new A2AServer({
...
basePath: "/apiV2"
fallbackPath: "/apiV2/custom-card-info", // Agent card available here
...
});
// The AgentCard is now accessible at http://localhost:3001/apiV2/custom-card-info
```#### Advanced Server Customization
Provide a custom `createJSONRPCServer` function (implementing `JSONRPCServerFactory`) for fine-grained control over the underlying RPC server.
This factory function receives objects of type `CreateJSONRPCServerParams` & `RequestParams` containing the necessary SDK dependencies (`taskHandler`, `taskStore`, `agentCard`, `activeCancellations`, `createTaskContext`, `closeStreamsForTask`) and the specific method paramaters (i.e. `SendTaskRequest["params"]`). You can use these dependencies to configure the standard A2A methods and add your own custom JSON-RPC methods.
The SDK exports default handlers for the standard A2A methods (e.g., `defaultSendTaskMethod`), create your own using dedicated A2A method types(`SendTaskMethod`) and use `createJSONRPCMethod` to easily wrap these methods with dependency injection and error handling.
See `src/server/lib/middleware/factory.ts` and `src/server/lib/middleware/a2a-methods.ts` for implementation details.
**Example:**
```typescript
const myCustomSendMethod: SendTaskMethod = (
deps,
requestParams,
callback
) => {
const { taskStore, taskHandler, createTaskContext } = deps;
const taskId = extractTaskId(requestParams.id);
const { message, sessionId, metadata } = requestParams;
...
callback(null, ...);
};const myCustomRPCServer: JSONRPCServerFactory = (
params: CreateJSONRPCServerParams
): JSONRPCServerType => {
//Use a custom task/send method
const taskSendMethod = createJSONRPCMethod(params, myCustomSendMethod, "tasks/send");
const taskGetMethod = createJSONRPCMethod(params, defaultGetTaskMethod, "tasks/get");
const taskCancelMethod = createJSONRPCMethod(params, defaultCancelTaskMethod, "tasks/cancel");// Note: Push notifications are not fully implemented yet
const taskPushNotificationSetMethod = createJSONRPCMethod(params, defaultSetTaskPushNotificationMethod, "tasks/pushNotification/set");
const taskPushNotificationGetMethod = createJSONRPCMethod(params, defaultGetTaskPushNotificationMethod, "tasks/pushNotification/get");const rpcServer = new JSONRPCServer({
"tasks/send": taskSendMethod,
"tasks/get": taskGetMethod,
"tasks/cancel": taskCancelMethod,
"tasks/pushNotification/set": taskPushNotificationSetMethod,
"tasks/pushNotification/get": taskPushNotificationGetMethod,
});return rpcServer;
};const server = new A2AServer({
createJSONRPCServer: myCustomRPCServer,
...
});
```**Using the Custom Factory**
Pass your factory function via the `createJSONRPCServer` option during `A2AServer` initialization.
**Important:** The default `A2AServer` setup automatically adds Express middleware to handle Server-Sent Events (SSE) for `tasks/sendSubscribe` and `tasks/resubscribe`, as well as the `/agent/card` (and `/.well-known/agent.json`) GET endpoints. If you are **not** using `A2AServer` and integrating the Jayson server middleware into your own Express application, you **must** implement these SSE and card endpoints yourself to maintain full A2A compliance, especially for streaming functionality. See `src/server/lib/express-server.ts` for how the default server handles these routes.
### Quick-Agents (Alpha)
We are excited to introduce new capabilities for deploying agents directly onto the artinet.
In this weeks release, we've added a `testDeployment` utility which is available for all users letting you bundle and test your agent logic in a temporary sandboxed environment.
**ARTINET BETA USERS!** You'll soon be getting access to full deployment functionalities allowing you to host your agents on the artinet for free!
To join the beta waitlist, please email us at humans@artinet.io and stay tuned for more updates!
Key features include:
- **Easy Agent Bundling:** Bundle your agent's code and dependencies into a single file using the `bundle` utility.
```typescript
import { bundle } from "@artinet/sdk";const bundledCode = await bundle(new URL('./your-agent.ts', import.meta.url));
```- **Sandboxed Enviroments:** Utilities like `taskHandlerProxy` and `fetchResponseProxy` streamline agent logic for quick and easy deployments.
```typescript
import { taskHandlerProxy, fetchResponseProxy } from "@artinet/sdk/";async function myAgent(context) {
//call any other agent in the artinet with fetchResponseProxy
const friendResponse = await fetchResponseProxy("MyFriendlyAgent",
[{ role: "user", content: "Tell me a joke."}]
);
yield { state: "completed", message: { role: "agent", parts: [{type: "text", text: freiendResponse.choices[0].message.content }] } };
}await taskHandlerProxy(myAgent);
```- **Test-Agents:** Simulate and test your agents @ agents.artinet.io/test/deploy using the `testDeployment` tool.
```typescript
import { testDeployment, ServerDeploymentRequestParams, SendTaskRequest } from "@artinet/sdk";const deploymentParams: ServerDeploymentRequestParams = {
code: "/* bundled code string */",
};
//create a list of tasks for your agent to complete once deployed
const testRequests: SendTaskRequest[] = [
{ id: "t1", message: { role: "user", parts: [{ type: "text", text: "Hi!" }] } }
];for await (const result of testDeployment(deploymentParams, testRequests)) {
console.log(result); //process the task completion requests as they come in to confirm your agents logic
}
```- **New Types:** To support these features, new types for server deployment requests and responses (such as `ServerDeploymentRequestParams`, `ServerDeploymentResponse`) have been added to `src/types/extended-schema.ts`.
- **QUICK-AGENT FAQs**
- Test-Agents expire after 60s (need more time? let us know @humans@artinet.io)
- Quick-Agents do not have access to a filesystem or networking (limited persistance & networking capabalities are on the project roadmap).## Contributing
Contributions are welcome! Please open an issue or submit a Pull Request on [GitHub](https://github.com/the-artinet-project/artinet-sdk).
Ensure code adheres to the project style and passes linting (`npm run lint`) and tests (`npm test`).
## License
This project is licensed under the Apache License 2.0 - see the `LICENSE` file for details.
## Acknowledgements
This SDK builds upon the concepts and specifications of the [Agent2Agent (A2A) Protocol](https://github.com/google/A2A) initiated by Google. It utilizes the official [A2A JSON Schema](https://github.com/google/A2A/tree/main/specification/json) for protocol compliance.
Libraries used include:
- [Express.js](https://expressjs.com/) for the server framework.
- [Jayson](https://github.com/tedeh/jayson) for JSON-RPC handling.
- [Pino](https://getpino.io/) for logging.
- [EventSource Parser](https://github.com/rexxars/eventsource-parser) for SSE streaming.