@artinet/sdk
Version:
TypeScript SDK for Agentic Communication
567 lines (427 loc) • 22.8 kB
Markdown
[](https://www.npmjs.com/package/@artinet/sdk)
[](https://www.npmjs.com/package/@artinet/sdk)
[](LICENSE)
[](https://snyk.io/test/npm/@artinet/sdk)
<!-- [](https://coveralls.io/github/the-artinet-project/artinet-sdk?branch=main) -->
# artinet SDK
The artinet SDK is a Full Stack Agent builder 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 supports multiple agentic communication protocols, offering a production-ready solution with a focus on developer experience, reliability, and comprehensive features.
### Quick Start
To build your own agent/server use the [`create-quick-agent`](https://www.npmjs.com/package/@artinet/create-quick-agent) command:
```bash
npx /create-quick-agent
```
It has [serveral template projects](https://github.com/the-artinet-project/create-quick-agent) that you can use to get started building agents today.
## Table of Contents
- [artinet SDK](#artinet-sdk)
- [Quick Start](#quick-start)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Installation](#installation)
- [Requirements](#requirements)
- [Documentation](#documentation)
- [Example](#example)
- [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 `ExpressServer` handles Transport-layer complexity, routing, protocol compliance, and Server-Sent Events (SSE) streaming mechanics automatically. Just provide your core agent logic (`AgentEngine`) and configuration via `ExpressServerOptions`.
- **TypeScript First:** Fully written in TypeScript with comprehensive type definitions for a robust developer experience.
- **Protocol Compliance:** Implements the complete A2A specification with growing support for recieving commands via MCP & ACP.
- **Code Deployment (Experimental)** | Bundle, test, and deploy agent code onto the artinet. Includes bundler, task wrapper, and deployment utilities.
| Component/Feature | Description | Key Classes/Types |
| :------------------ | :-------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- |
| **Client** | Interact with A2A-compliant agents. Supports standard & streaming requests. | `A2AClient`, `RpcError` |
| **Server** | Host agents that can communicate using a variety of protocols. Handles protocol details, routing, SSE. | `ExpressServer`, `ExpressServerOptions` |
| **Reqeust Handling** | Define agent logic using async generators. | `AgentEngine`, `ExecutionContext`, `UpdateEvent` |
| **Storage** | Persist event state. In-memory and file-based options included. | `Store`, `InMemoryTaskStore`, `FileStore` |
| **Streaming (SSE)** | Handle real-time updates via SSE. | |
| **Logging** | Configure structured logging for debugging and monitoring. | `logger`, `configureLogger`, `LogLevel` |
| **Advanced Server** | Customize the underlying JSON-RPC server or integrate into existing apps. | `CreateJSONRPCServerParams`, `createJSONRPCMethod` |
| **Core Types** | Based on the official JSON Schemas. | `Tool`,`AgentCard`, `Task`, `Message`, `Part`, `Artifact`, etc. |
| **Agent Utilities (for Sandboxed Environments)** | Standardized utilities for agents in managed environments to interact with the host system for task lifecycle, inter-agent communication, and external API calls. | `artinet.v0.taskManager`, `artinet.v0.connect`, `artinet.v0.agent`, `TaskProxy`, `ConnectAPICallback`, `ClientProxy`, `ClientFactory` |
## Installation
```bash
npm install /sdk
```
## Requirements
- Node.js (v22.0.0 or higher recommended, check `package.json` engines for exact requirement)
## Documentation
For more detailed documentation visit our documentation site [here](https://the-artinet-project.github.io/artinet-documentation/).
## Example
A basic A2A server and client interaction. For more detailed examples, see the `examples/` directory.
**1. Server (`quick-server.ts`)**
```typescript
import {
ExpressServer,
ExecutionContext,
AgentEngine,
InMemoryTaskStore,
} from "@artinet/sdk";
// Minimal agent logic: receive text, yield working state, yield completed state with echo
const quickAgentLogic: AgentEngine = async function* (context: ExecutionContext) {
const params = context.getRequestParams() as MessageSendParams; //for A2A requests
const userInput = params.message.parts[0].kind === "text"
? context.userMessage.parts[0].text
: "";
yield { state: "working" };
// Simulate some work if needed, check context.isCancelled()
yield {
state: "completed",
message: {
role: "agent",
parts: [{ kind: "text", text: `You said: ${userInput}` }],
},
};
};
const server = new A2AServer({
handler: 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 = {
messageId: "test-message-id",
kind: "message",
role: "user",
parts: [{ kind: "text", text: "Hello Quick Start!" }],
};
const stream = client.sendStreamingMessage({ message });
for await (const update of stream) {
// process the update
...
}
console.log("Stream finished.");
}
runClient().catch(console.error);
```
## 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 message using `message/send`.
```typescript
import { A2AClient, Message } from "@artinet/sdk";
async function runBasicTask() {
const client = new A2AClient("https://your-a2a-server.com/a2a");
const message: Message = {
messageId: "test-message",
kind: "message",
role: "user",
parts: [{ kind: "text", text: "What is the capital of France?" }],
};
const task = await client.sendMessage({ message });
console.log("Task Completed:", task);
}
```
#### Streaming Updates
Receive real-time updates via SSE using `message/stream` (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.sendStreamingMessage({ 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,
ExecutionContext,
AgentEngine,
InMemoryTaskStore,
} from "@artinet/sdk";
const myAgent: AgentEngine = async function* (context: ExecutionContext) {
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({
handler: 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 parameters (i.e. `SendMessageRequest["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., `defaultSendMessageMethod`), create your own using dedicated A2A method types(`SendMessageMethod`) 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: SendMessageMethod = (
deps,
requestParams,
callback
) => {
const { taskStore, taskHandler, createTaskContext } = deps;
const { id: taskId } = requestParams;
const { message, sessionId, metadata } = requestParams;
...
callback(null, ...);
};
const myCustomRPCServer: JSONRPCServerFactory = (
params: CreateJSONRPCServerParams
): JSONRPCServerType => {
//Use a custom message/send method
const messageSendMethod = createJSONRPCMethod(params, myCustomSendMethod, "message/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/pushNotificationConfig/set");
const taskPushNotificationGetMethod = createJSONRPCMethod(params, defaultGetTaskPushNotificationMethod, "tasks/pushNotificationConfig/get");
const rpcServer = new JSONRPCServer({
"message/send": messageSendMethod,
"tasks/get": taskGetMethod,
"tasks/cancel": taskCancelMethod,
"tasks/pushNotificationConfig/set": taskPushNotificationSetMethod,
"tasks/pushNotificationConfig/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 `message/stream` 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.
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.
**QUICK-AGENTS** Use the `fullDeployment` utility, which allows direct deployment of your bundled agent code and `AgentCard` to the Artinet platform (requires an `ARTINET_API_KEY`).
To join the beta waitlist, please email us at humans.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:** Streamline agent logic for quick and easy deployments. The new `artinet.v0` namespace (accessible via `/sdk/agents`) provides `taskManager`, `connect`, and `agent`.
- `artinet.v0.taskManager`: Manages the agent's lifecycle by iterating over the agent's `TaskHandler` and communicating updates to the host environment.
- `artinet.v0.connect`: Replaces the deprecated `fetchResponseProxy`. Allows agents to make proxied calls to other agents or LLMs via the host environment.
- `artinet.v0.agent`: A factory function to obtain a `ClientProxy` for type-safe communication with other agents, managed by the host environment.
Example of using the new `artinet.v0` utilities in an agent:
```typescript
import { TaskContext, TaskYieldUpdate, Task } from "@artinet/sdk";
import { artinet } from "@artinet/sdk/agents";
export async function* myAgentLogic(context: TaskContext): AsyncGenerator<TaskYieldUpdate, Task | void, unknown> {
yield { state: "working" };
// Call another agent/LLM using artinet.v0.connect
const llmResponse = await artinet.v0.connect({
agentId: "SomeLLMAgentID",
messages: [{ role: "user", content: "Tell me a joke." }]
});
// Or communicate tasks with artinet.v0.agent
const anotherAgent = artinet.v0.agent({
baseUrl: "https://agents.artinet.io/agentId=456",
});
const taskResult = await anotherAgent.sendTask({
...
});
}
// The host environment will invoke this taskManager with the agent's logic.
await artinet.v0.taskManager({ taskHandler: myAgentLogic });
```
*Note: The `taskHandlerProxy` and `fetchResponseProxy` utilities are now deprecated in favor of `artinet.v0.taskManager` and `artinet.v0.connect` respectively.*
- **Test-Agents (Experimental):** 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
}
```
- **Full Deployment (Experimental):** Deploy your agent to the Artinet platform using the `fullDeployment` utility.
```typescript
import { fullDeployment, ServerDeploymentRequestParams } from "@artinet/sdk";
const deploymentParams: ServerDeploymentRequestParams = {
name: "My Awesome Agent",
agentCard: { /* your agent card */ },
code: "/* bundled code string */",
};
const deploymentResult = await fullDeployment(deploymentParams); // Requires an ARTINET_API_KEY environment variable
console.log("Deployment Result:", deploymentResult);
```
- **Dedicated Endpoints:** Once deployed your agent will be available On-Demand at its dedicated enpoint. (e.g. "https://agents.artinet.io/agentId=0xabf698845743538727a81352bfcfdb724e5c2bbe3113a26362482248f9f3e5fa/.well-known/agent.json")
- **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`. New types for sandboxed agent interactions (`TaskProxy`, `ConnectAPICallback`, `ClientProxy`, etc.) are in `src/types/proxy.ts`.
**QUICK-AGENT FAQs**
- Test-Agents expire after 60s (need more time? let us know .io)
- Quick-Agents do not have access to a filesystem or networking (limited persistance & networking capabalities are on the project roadmap).
- Quick-Agents v0 does not support streaming, push notifications or state transition history (these capabilities are on the project roadmap).
- Larger deployments can take significant time to deploy which may cause `fullDeployment` to timeout. In such cases wait to see if the listing has been added to your account before trying to deploy again.
- Quick-Agent logic is public, therefore the artinet project is not liable for any sensitive material held within a deployment.
- Only availble with version 0.5.3 of the SDK.
Sign-up at [artinet.io](https://artinet.io/) to deploy your Quick-Agent today!
## 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/A2A) initiated by Google. It utilizes the official [A2A JSON Schema](https://github.com/google-a2a/A2A/blob/main/specification/json/a2a.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.