@artinet/sdk 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,23 +40,6 @@ npx @artinet/create-agent@latest
40
40
 
41
41
  It has [several template projects](https://github.com/the-artinet-project/artinet/tree/main/create-agent) to jump right into agent building.
42
42
 
43
- **Or use [`easy-a2a`](https://github.com/the-artinet-project/artinet/tree/main/easy):**
44
-
45
- ```typescript
46
- const agent = a2a({
47
- baseURL: "https://your-api.com/api/v1",
48
- apiKey: "your-api-key",
49
- })
50
- .ai("You are a helpful assistant.")
51
- .createAgent({
52
- agentCard: "MyAgent",
53
- });
54
- ```
55
-
56
- ```bash
57
- npm install easy-a2a
58
- ```
59
-
60
43
  ## Examples
61
44
 
62
45
  **Create an A2A Server**
@@ -64,52 +47,85 @@ npm install easy-a2a
64
47
  Turn your agent into an express server so it can receive messages from anywhere:
65
48
 
66
49
  ```typescript
67
- import { cr8 } from "@artinet/sdk";
50
+ import { cr8 } from '@artinet/sdk';
68
51
 
69
- cr8("QuickStart Agent")
70
- .text(async ({ content }) => `The user said: ${content}`)
71
- //starts an express a2a server on port 3000
72
- .server.start(3000);
52
+ cr8('QuickStart Agent')
53
+ .text(async ({ content }) => `The user said: ${content}`)
54
+ //starts an express a2a server on port 3000
55
+ .server.start(3000);
73
56
  ```
74
57
 
75
58
  - _ensure that the url/path of your AgentCard matches the server._
76
59
 
77
60
  > 🚧 Coming Soon: Support for Hono.
78
61
 
62
+ **Go Serverless**
63
+
64
+ Deploy your agent to AWS Lambda or other serverless platforms:
65
+
66
+ ```typescript
67
+ import { Handler } from 'aws-lambda';
68
+ import { serve } from '@artinet/sdk/serverless';
69
+ import { agent } from './my-agent.js';
70
+
71
+ export const handler: Handler = serve({ agent, basePath: '/a2a' }, { provider: 'aws' });
72
+ ```
73
+
74
+ - _See [**Serverless Deployment**](./docs/customization.md#serverless-deployment) for more information._
75
+
79
76
  **No Servers Needed**
80
77
 
81
78
  Embed agents directly into your app:
82
79
 
83
80
  ```typescript
84
- import { cr8, A2A } from "@artinet/sdk";
81
+ import { cr8, A2A } from '@artinet/sdk';
85
82
 
86
- const agent = cr8("Local Agent").text(
87
- ({ content }) => `The user said: ${content}`
88
- ).agent;
83
+ const agent = cr8('Local Agent').text(({ content }) => `The user said: ${content}`).agent;
89
84
 
90
- const response: A2A.Task | A2A.Message = await agent.sendMessage("Hello");
85
+ const response: A2A.Task | A2A.Message = await agent.sendMessage('Hello');
91
86
  ```
92
87
 
93
88
  - _See [**`cr8`**](./docs/create.md) for more information_
94
89
 
90
+ **Any Agent, Any Framework**
91
+
92
+ Docks agents from any framework into the <em>@artinet/sdk</em>. Letting your OpenAI, Claude, and LangChain agents collaborate.
93
+
94
+ ```typescript
95
+ import { Agent } from '@openai/agents';
96
+ import { dock } from '@artinet/cruiser/openai';
97
+ import { serve } from '@artinet/sdk';
98
+
99
+ const openaiAgent = new Agent({
100
+ name: 'assistant',
101
+ instructions: 'You are a helpful assistant',
102
+ });
103
+
104
+ const agent = await dock(agent, { name: 'My Assistant' });
105
+
106
+ await agent.sendMessage('Hello, World!');
107
+ ```
108
+
109
+ - _See [**`cruiser`**](https://github.com/the-artinet-project/artinet/tree/main/cruiser) for more information_
110
+
95
111
  **Connect to Remote Agents**
96
112
 
97
113
  [`AgentMessenger`](./docs/messenger.md#agentmessenger) provides a streamlined `Client` interface for communicating with remote A2A Servers:
98
114
 
99
115
  ```typescript
100
- import { AgentMessenger, createMessenger } from "@artinet/sdk";
116
+ import { AgentMessenger, createMessenger } from '@artinet/sdk';
101
117
 
102
118
  const messenger: AgentMessenger = await createMessenger({
103
- baseUrl: "http://localhost:3000/a2a",
104
- headers: {
105
- Bearer: "xxxx",
106
- },
119
+ baseUrl: 'http://localhost:3000/a2a',
120
+ headers: {
121
+ Bearer: 'xxxx',
122
+ },
107
123
  });
108
124
 
109
- const stream = messenger.sendMessageStream("Hello World!");
125
+ const stream = messenger.sendMessageStream('Hello World!');
110
126
 
111
127
  for await (const update of stream) {
112
- console.log(update);
128
+ console.log(update);
113
129
  }
114
130
  ```
115
131
 
@@ -120,15 +136,15 @@ for await (const update of stream) {
120
136
  [**`cr8`**](./docs/create.md#agent-orchestration) provides easy to use tools for orchestrating multiple agents:
121
137
 
122
138
  ```typescript
123
- import { cr8 } from "@artinet/sdk";
124
- import { localAgent } from "./local.ts";
125
- import { remoteAgentMessenger as remoteAgent } from "./remote.ts";
126
-
127
- const orchestrator = cr8("Director")
128
- .text("Request Received")
129
- .sendMessage({ agent: localAgent, message: "initiate billing" })
130
- .text("Billing Started")
131
- .sendMessage({ agent: remoteAgent, message: "Retrieve Secrets" }).agent;
139
+ import { cr8 } from '@artinet/sdk';
140
+ import { localAgent } from './local.ts';
141
+ import { remoteAgentMessenger as remoteAgent } from './remote.ts';
142
+
143
+ const orchestrator = cr8('Director')
144
+ .text('Request Received')
145
+ .sendMessage({ agent: localAgent, message: 'initiate billing' })
146
+ .text('Billing Started')
147
+ .sendMessage({ agent: remoteAgent, message: 'Retrieve Secrets' }).agent;
132
148
  ```
133
149
 
134
150
  > _For more robust multi-agent support, checkout [**orc8**](https://github.com/the-artinet-project/artinet), our dynamic agent orchestration library that can be used with any openai compatible API._
@@ -143,7 +159,7 @@ const orchestrator = cr8("Director")
143
159
  | [**Messenger**](docs/messenger.md) | `Messenger` methods, streaming, browser support |
144
160
  | [**Storage**](docs/storage.md) | `FileStore`, `SQLiteStore`, custom storage backends |
145
161
  | [**Configuration**](docs/configuration.md) | Logging (Pino, Winston) and OpenTelemetry setup |
146
- | [**Customization**](docs/customization.md) | `native`, tRPC, and `AgentEngine`s |
162
+ | [**Customization**](docs/customization.md) | `native`, tRPC, `AgentEngine`s, and serverless |
147
163
  | [**MCP Integration**](docs/mcp.md) | Model Context Protocol compatibility |
148
164
  | [**Migration Guide**](docs/migration.md) | Upgrading from v0.5.x to v0.6.0 |
149
165
 
@@ -5,9 +5,7 @@
5
5
  import { A2A } from "../types/index.js";
6
6
  import { v4 as uuidv4 } from "uuid";
7
7
  import { getCurrentTimestamp } from "../utils/utils.js";
8
- import { isMessageParams, Message,
9
- // type BuilderMessageParams,
10
- } from "./message-builder.js";
8
+ import { isMessageParams, Message, } from "./message-builder.js";
11
9
  export const isArtifactParams = (params) => {
12
10
  return (typeof params === "string" ||
13
11
  (typeof params === "object" && params !== null && "parts" in params));
@@ -1 +1 @@
1
- export { createMessenger, A2AClient, AgentMessenger, type MessengerParams, } from "./messenger.js";
1
+ export { createMessenger, A2AClient, AgentMessenger, type MessengerParams, isMessengerParams, } from "./messenger.js";
@@ -1 +1 @@
1
- export { createMessenger, A2AClient, AgentMessenger, } from "./messenger.js";
1
+ export { createMessenger, A2AClient, AgentMessenger, isMessengerParams, } from "./messenger.js";
@@ -5,10 +5,22 @@
5
5
  import { A2A } from "../types/index.js";
6
6
  import * as describe from "../create/describe.js";
7
7
  import { ClientFactoryOptions, ClientConfig, Client, Transport, RequestOptions } from "@a2a-js/sdk/client";
8
- export interface MessengerParams {
8
+ import { z } from "zod/v4";
9
+ export declare const MessengerParamsSchema: z.ZodObject<{
10
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
11
+ authToken: z.ZodOptional<z.ZodString>;
12
+ baseUrl: z.ZodURL;
13
+ fallbackPath: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ type BaseMessengerParams = z.infer<typeof MessengerParamsSchema>;
16
+ /**
17
+ * Checks if the given parameters are a valid MessengerParams object.
18
+ * @param params The parameters to check.
19
+ * @returns True if the parameters are a valid MessengerParams object, false otherwise.
20
+ */
21
+ export declare const isMessengerParams: (params: unknown) => params is MessengerParams;
22
+ export interface MessengerParams extends Omit<BaseMessengerParams, "baseUrl"> {
9
23
  baseUrl: URL | string;
10
- headers?: Record<string, string>;
11
- fallbackPath?: string;
12
24
  factory?: Partial<ClientFactoryOptions>;
13
25
  config?: ClientConfig;
14
26
  }
@@ -7,6 +7,8 @@ import { validateSchema } from "../utils/schema-validation.js";
7
7
  import { logger } from "../config/index.js";
8
8
  import * as describe from "../create/describe.js";
9
9
  import { ClientFactory, ClientFactoryOptions, AgentCardResolver, } from "@a2a-js/sdk/client";
10
+ import { Runtime } from "@artinet/types";
11
+ import { z } from "zod/v4";
10
12
  class HeaderInterceptor {
11
13
  constructor(_getCustomHeaders) {
12
14
  this._getCustomHeaders = _getCustomHeaders;
@@ -52,6 +54,21 @@ class NestedAgentCardResolver {
52
54
  return await validateSchema(A2A.AgentCardSchema, await response.json());
53
55
  }
54
56
  }
57
+ export const MessengerParamsSchema = Runtime.ServerConfigSchema.pick({
58
+ headers: true,
59
+ authToken: true,
60
+ }).extend({
61
+ baseUrl: z.url(),
62
+ fallbackPath: z.string().optional(),
63
+ });
64
+ /**
65
+ * Checks if the given parameters are a valid MessengerParams object.
66
+ * @param params The parameters to check.
67
+ * @returns True if the parameters are a valid MessengerParams object, false otherwise.
68
+ */
69
+ export const isMessengerParams = (params) => {
70
+ return MessengerParamsSchema.safeParse(params).success;
71
+ };
55
72
  /**
56
73
  * Messenger is the main communication client for interacting with remote A2A-compatible services.
57
74
  * It provides methods for sending messages, retrieving tasks, canceling operations, and handling streaming responses.
@@ -261,7 +261,7 @@ export type Engine = (context: Context) => AsyncGenerator<Update, void, unknown>
261
261
  export interface BaseContext extends core.Context<Task> {
262
262
  readonly service: Service;
263
263
  /**
264
- * Considering ommit OnStart & OnComplete from Context consumers.
264
+ * Considering omitting OnStart & OnComplete from Context consumers.
265
265
  * That way the user cannot inadvertently trigger a start/completion out of band.
266
266
  */
267
267
  readonly publisher: EventPublisher;
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from "eventemitter3";
1
+ import { EventEmitter } from 'eventemitter3';
2
2
  import { IStore } from "../storage.js";
3
3
  export interface Service<Params extends object = object, Result extends unknown = void> {
4
4
  execute: (params: Params) => Promise<Result>;
@@ -21,6 +21,7 @@ export interface Manager<T = object> extends IStore<T> {
21
21
  delete: (id: string) => Promise<void>;
22
22
  has?: (id: string) => Promise<boolean>;
23
23
  list?: () => Promise<T[]>;
24
+ search?: (query: string, filter?: (item: T) => Promise<boolean>) => Promise<T[]>;
24
25
  }
25
26
  export type Optional<T extends object = object> = Partial<T> & {
26
27
  contextId: string;
@@ -4,3 +4,5 @@
4
4
  */
5
5
  import { A2A } from "../types/index.js";
6
6
  export declare const FINAL_STATES: A2A.TaskState[];
7
+ export declare const PROCESSING_STATES: A2A.TaskState[];
8
+ export declare const isProcessing: (state: A2A.TaskState) => boolean;
@@ -9,3 +9,8 @@ export const FINAL_STATES = [
9
9
  A2A.TaskState.canceled,
10
10
  A2A.TaskState.rejected,
11
11
  ];
12
+ export const PROCESSING_STATES = [
13
+ A2A.TaskState.working,
14
+ A2A.TaskState.submitted,
15
+ ];
16
+ export const isProcessing = (state) => PROCESSING_STATES.includes(state);
@@ -39,8 +39,9 @@ import { describe } from "./index.js";
39
39
  import { extractTextContent } from "../services/a2a/helpers/content.js";
40
40
  import { logger } from "../config/index.js";
41
41
  import { v4 as uuidv4 } from "uuid";
42
- import { formatJson } from "../utils/index.js";
42
+ import { formatJson } from "../utils/utils.js";
43
43
  import { serve } from "../server/express/server.js";
44
+ import { isProcessing } from "../utils/constants.js";
44
45
  const toFunction = (function_or_ret) => {
45
46
  return typeof function_or_ret === "function"
46
47
  ? function_or_ret
@@ -504,6 +505,7 @@ export function createStepEngine(stepsList) {
504
505
  }
505
506
  const task = await context.getTask();
506
507
  logger.debug(`engine[context:${context.contextId}]: completed task[${task.id}]: ${formatJson(task)}`);
508
+ task.status.state = isProcessing(task.status.state) ? A2A.TaskState.completed : task.status.state;
507
509
  yield task;
508
510
  };
509
511
  }
@@ -5,9 +5,7 @@
5
5
  import { A2A } from "../types/index.js";
6
6
  import { v4 as uuidv4 } from "uuid";
7
7
  import { getCurrentTimestamp } from "../utils/utils.js";
8
- import { isMessageParams, Message,
9
- // type BuilderMessageParams,
10
- } from "./message-builder.js";
8
+ import { isMessageParams, Message, } from "./message-builder.js";
11
9
  export const isArtifactParams = (params) => {
12
10
  return (typeof params === "string" ||
13
11
  (typeof params === "object" && params !== null && "parts" in params));
@@ -1 +1 @@
1
- export { createMessenger, A2AClient, AgentMessenger, type MessengerParams, } from "./messenger.js";
1
+ export { createMessenger, A2AClient, AgentMessenger, type MessengerParams, isMessengerParams, } from "./messenger.js";
@@ -1 +1 @@
1
- export { createMessenger, A2AClient, AgentMessenger, } from "./messenger.js";
1
+ export { createMessenger, A2AClient, AgentMessenger, isMessengerParams, } from "./messenger.js";
@@ -5,10 +5,22 @@
5
5
  import { A2A } from "../types/index.js";
6
6
  import * as describe from "../create/describe.js";
7
7
  import { ClientFactoryOptions, ClientConfig, Client, Transport, RequestOptions } from "@a2a-js/sdk/client";
8
- export interface MessengerParams {
8
+ import { z } from "zod/v4";
9
+ export declare const MessengerParamsSchema: z.ZodObject<{
10
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
11
+ authToken: z.ZodOptional<z.ZodString>;
12
+ baseUrl: z.ZodURL;
13
+ fallbackPath: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ type BaseMessengerParams = z.infer<typeof MessengerParamsSchema>;
16
+ /**
17
+ * Checks if the given parameters are a valid MessengerParams object.
18
+ * @param params The parameters to check.
19
+ * @returns True if the parameters are a valid MessengerParams object, false otherwise.
20
+ */
21
+ export declare const isMessengerParams: (params: unknown) => params is MessengerParams;
22
+ export interface MessengerParams extends Omit<BaseMessengerParams, "baseUrl"> {
9
23
  baseUrl: URL | string;
10
- headers?: Record<string, string>;
11
- fallbackPath?: string;
12
24
  factory?: Partial<ClientFactoryOptions>;
13
25
  config?: ClientConfig;
14
26
  }
@@ -7,6 +7,8 @@ import { validateSchema } from "../utils/schema-validation.js";
7
7
  import { logger } from "../config/index.js";
8
8
  import * as describe from "../create/describe.js";
9
9
  import { ClientFactory, ClientFactoryOptions, AgentCardResolver, } from "@a2a-js/sdk/client";
10
+ import { Runtime } from "@artinet/types";
11
+ import { z } from "zod/v4";
10
12
  class HeaderInterceptor {
11
13
  _getCustomHeaders;
12
14
  constructor(_getCustomHeaders) {
@@ -55,6 +57,21 @@ class NestedAgentCardResolver {
55
57
  return await validateSchema(A2A.AgentCardSchema, await response.json());
56
58
  }
57
59
  }
60
+ export const MessengerParamsSchema = Runtime.ServerConfigSchema.pick({
61
+ headers: true,
62
+ authToken: true,
63
+ }).extend({
64
+ baseUrl: z.url(),
65
+ fallbackPath: z.string().optional(),
66
+ });
67
+ /**
68
+ * Checks if the given parameters are a valid MessengerParams object.
69
+ * @param params The parameters to check.
70
+ * @returns True if the parameters are a valid MessengerParams object, false otherwise.
71
+ */
72
+ export const isMessengerParams = (params) => {
73
+ return MessengerParamsSchema.safeParse(params).success;
74
+ };
58
75
  /**
59
76
  * Messenger is the main communication client for interacting with remote A2A-compatible services.
60
77
  * It provides methods for sending messages, retrieving tasks, canceling operations, and handling streaming responses.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright 2025 The Artinet Project
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import serverless from "serverless-http";
6
+ import { ServerParams } from "../server.js";
7
+ /**
8
+ * Creates a serverless handler for the given parameters and options.
9
+ * @note Streaming capabilities are currently not supported in serverless handlers.
10
+ * @docs https://github.com/dougmoscrop/serverless-http
11
+ *
12
+ * @param params - {@link ServerParams}
13
+ * @param options - {@link serverless.Options}
14
+ * @example
15
+ * ```typescript
16
+ * import { Handler } from "aws-lambda";
17
+ * import { serve } from "@a2a-js/sdk/serverless";
18
+ *
19
+ * const handler: Handler = serve({
20
+ * agent: cr8("MyAgent")
21
+ * .text("Hello, world!")
22
+ * .agent,
23
+ * basePath: "/a2a",
24
+ * }, { provider: "aws" });
25
+ * ```
26
+ * @returns - {@link serverless.Handler}
27
+ */
28
+ export declare function serve(params: ServerParams, options: serverless.Options): serverless.Handler;
29
+ /**
30
+ * @deprecated Use `serve` instead.
31
+ */
32
+ export declare const createServerlessHandler: typeof serve;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright 2025 The Artinet Project
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import serverless from "serverless-http";
6
+ import { serve as serveExpress } from "../server.js";
7
+ import { logger } from "../../../config/index.js";
8
+ /**
9
+ * Creates a serverless handler for the given parameters and options.
10
+ * @note Streaming capabilities are currently not supported in serverless handlers.
11
+ * @docs https://github.com/dougmoscrop/serverless-http
12
+ *
13
+ * @param params - {@link ServerParams}
14
+ * @param options - {@link serverless.Options}
15
+ * @example
16
+ * ```typescript
17
+ * import { Handler } from "aws-lambda";
18
+ * import { serve } from "@a2a-js/sdk/serverless";
19
+ *
20
+ * const handler: Handler = serve({
21
+ * agent: cr8("MyAgent")
22
+ * .text("Hello, world!")
23
+ * .agent,
24
+ * basePath: "/a2a",
25
+ * }, { provider: "aws" });
26
+ * ```
27
+ * @returns - {@link serverless.Handler}
28
+ */
29
+ export function serve(params, options) {
30
+ if (typeof params.agent.agentCard !== "string" && params.agent.agentCard.capabilities?.streaming === true) {
31
+ logger.warn("Streaming capabilities are not supported in serverless handlers");
32
+ }
33
+ const { app } = serveExpress(params);
34
+ return serverless(app, {
35
+ ...options,
36
+ provider: options.provider ?? "aws",
37
+ });
38
+ }
39
+ /**
40
+ * @deprecated Use `serve` instead.
41
+ */
42
+ export const createServerlessHandler = serve;
@@ -2,19 +2,23 @@
2
2
  * Copyright 2025 The Artinet Project
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- /**
6
- * Manager should optionally take a persistent storage object as a constructor parameter,
7
- * That way we don't need to re-implement the same caching logic for each derived manager.
8
- */
9
- export declare abstract class Manager<T> {
10
- private _data;
5
+ import { core } from "../../types/index.js";
6
+ export declare abstract class Manager<T> implements core.Manager<T> {
7
+ private _cache;
11
8
  private throwOnSet;
12
- constructor(_data?: Map<string, T>, throwOnSet?: boolean);
9
+ private storage?;
10
+ constructor(_cache?: Map<string, T>, throwOnSet?: boolean, storage?: core.Manager<T> | undefined);
11
+ get cache(): Map<string, T>;
12
+ /**
13
+ * @deprecated use cache instead
14
+ * @note removing in v0.7
15
+ */
13
16
  get data(): Map<string, T>;
14
17
  set(id: string, data?: T): Promise<void>;
15
18
  get(id: string): Promise<T | undefined>;
16
19
  delete(id: string): Promise<void>;
17
20
  has(id: string): Promise<boolean>;
18
21
  list(): Promise<T[]>;
22
+ search(query: string, filter?: (item: T) => Promise<boolean>): Promise<T[]>;
19
23
  }
20
24
  export declare const ResourceManager: typeof Manager;
@@ -3,46 +3,101 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { logger } from "../../config/index.js";
6
- //TODO: Add persistence layer plugin support and turn Manager into an LRU cache.
7
- /**
8
- * Manager should optionally take a persistent storage object as a constructor parameter,
9
- * That way we don't need to re-implement the same caching logic for each derived manager.
10
- */
6
+ //TODO: Turn Manager into an LRU cache.
7
+ //TODO: Consider warning when size exceeds a certain threshold.
11
8
  export class Manager {
12
- _data;
9
+ _cache;
13
10
  throwOnSet;
14
- constructor(_data = new Map(), throwOnSet = true) {
15
- this._data = _data;
11
+ storage;
12
+ constructor(_cache = new Map(), throwOnSet = true, storage) {
13
+ this._cache = _cache;
16
14
  this.throwOnSet = throwOnSet;
15
+ this.storage = storage;
16
+ //TODO: consider async initialization of storage/lazy loading of cold data (to an upper-bound)
17
17
  }
18
+ get cache() {
19
+ return this._cache;
20
+ }
21
+ /**
22
+ * @deprecated use cache instead
23
+ * @note removing in v0.7
24
+ */
18
25
  get data() {
19
- return this._data;
26
+ return this.cache;
20
27
  }
21
28
  async set(id, data) {
22
29
  logger.debug(`${this.constructor.name}[set]:`, { id });
23
30
  if (!data && this.throwOnSet) {
24
- throw new Error("Data is required");
31
+ throw new Error('Data is required');
25
32
  }
26
33
  else if (!data) {
27
34
  return;
28
35
  }
29
- this.data.set(id, data);
36
+ this.cache.set(id, data);
37
+ if (this.storage) {
38
+ await this.storage.set(id, data);
39
+ }
30
40
  }
31
41
  async get(id) {
32
- // logger.debug(`${this.constructor.name}[get]:`, { id });
33
- return this.data.get(id);
42
+ let data = this.cache.get(id);
43
+ if (!data && this.storage) {
44
+ data = await this.storage.get(id);
45
+ if (data) {
46
+ this.cache.set(id, data);
47
+ }
48
+ }
49
+ return data;
34
50
  }
35
51
  async delete(id) {
36
52
  logger.debug(`${this.constructor.name}[delete]:`, { id });
37
- this.data.delete(id);
53
+ if (this.storage) {
54
+ /** Probably best to delete from storage first to avoid race conditions. */
55
+ await this.storage.delete(id);
56
+ }
57
+ this.cache.delete(id);
38
58
  }
39
59
  async has(id) {
40
- // logger.debug(`${this.constructor.name}[has]:`, { id });
41
- return this.data.has(id);
60
+ if (this.cache.has(id)) {
61
+ return true;
62
+ }
63
+ if (this.storage) {
64
+ const data = await this.storage.get(id);
65
+ if (data) {
66
+ this.cache.set(id, data);
67
+ return true;
68
+ }
69
+ }
70
+ return false;
42
71
  }
43
72
  async list() {
44
- // logger.debug(`${this.constructor.name}[list]:`);
45
- return Array.from(this.data.values());
73
+ const listed = Array.from(this.cache.values());
74
+ if (this.storage) {
75
+ /** Could be an expensive operation */
76
+ listed.push(...((await this.storage.list?.())?.filter((item) => item !== undefined && !listed.includes(item)) ??
77
+ []));
78
+ }
79
+ return listed;
80
+ }
81
+ async search(query, filter) {
82
+ if (!filter && !this.storage) {
83
+ const data = this.cache.get(query);
84
+ if (data) {
85
+ return [data];
86
+ }
87
+ return [];
88
+ }
89
+ const results = [];
90
+ if (filter) {
91
+ results.push(...Array.from(this.cache.values()).filter(filter));
92
+ }
93
+ if (this.storage) {
94
+ const storageFilter = async (item) => {
95
+ return ((await filter?.(item)) ?? true) && !results.includes(item);
96
+ };
97
+ /**Spreads are fine for now, but a for of loop and push is safer at scale. */
98
+ results.push(...((await this.storage.search?.(query, storageFilter)) ?? []));
99
+ }
100
+ return results;
46
101
  }
47
102
  }
48
103
  export const ResourceManager = Manager;
@@ -1,3 +1,8 @@
1
- export * from "./core/index.js";
2
- export * from "./a2a/index.js";
3
- export * from "./mcp/index.js";
1
+ export * from './core/index.js';
2
+ export * from './a2a/index.js';
3
+ /**
4
+ * A lot more modules on the way so we're going to stop exporting everything from here.
5
+ * Instead we'll export them as packages, to reduce dependencies and improve tree shaking.
6
+ * @note MCP Service will be exported as @artinet/sdk/mcp and removed from this file in the next minor release.
7
+ */
8
+ export * from './mcp/index.js';
@@ -1,3 +1,8 @@
1
- export * from "./core/index.js";
2
- export * from "./a2a/index.js";
3
- export * from "./mcp/index.js";
1
+ export * from './core/index.js';
2
+ export * from './a2a/index.js';
3
+ /**
4
+ * A lot more modules on the way so we're going to stop exporting everything from here.
5
+ * Instead we'll export them as packages, to reduce dependencies and improve tree shaking.
6
+ * @note MCP Service will be exported as @artinet/sdk/mcp and removed from this file in the next minor release.
7
+ */
8
+ export * from './mcp/index.js';
@@ -3,13 +3,13 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
- import { MCP } from "../../types/index.js";
7
6
  import { Implementation } from "@modelcontextprotocol/sdk/types.js";
8
7
  import { ServerOptions } from "@modelcontextprotocol/sdk/server/index.js";
9
8
  import { Agent } from "../a2a/index.js";
9
+ import { MCP } from "../../types/index.js";
10
10
  export interface MCPServiceParams {
11
- serverInfo: Implementation;
12
11
  agent: Agent;
12
+ serverInfo?: Implementation;
13
13
  options?: ServerOptions;
14
14
  agentCardUri?: string;
15
15
  }
@@ -24,3 +24,4 @@ export type MCPService = ReturnType<typeof BaseMCPService.create>;
24
24
  export type MCPAgent = MCPService;
25
25
  export declare const createMCPService: typeof BaseMCPService.create;
26
26
  export declare const createMCPAgent: typeof BaseMCPService.create;
27
+ export declare const mcp: typeof BaseMCPService.create;
@@ -5,6 +5,20 @@
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { A2A } from "../../types/index.js";
7
7
  import { formatJson } from "../../utils/utils.js";
8
+ const toImplementation = (agentCard) => {
9
+ return {
10
+ name: agentCard.name,
11
+ version: agentCard.version,
12
+ websiteUrl: agentCard.url,
13
+ description: agentCard.description,
14
+ title: agentCard.name,
15
+ icons: agentCard.iconUrl ? [
16
+ {
17
+ src: agentCard.iconUrl,
18
+ },
19
+ ] : undefined,
20
+ };
21
+ };
8
22
  export class BaseMCPService extends McpServer {
9
23
  agent;
10
24
  _registerBaseTools(uri = "agent://card") {
@@ -76,7 +90,7 @@ export class BaseMCPService extends McpServer {
76
90
  });
77
91
  }
78
92
  constructor({ serverInfo, agent, options, agentCardUri = "agent://card", }) {
79
- super(serverInfo, options);
93
+ super(serverInfo ?? toImplementation(agent.agentCard), options);
80
94
  this.agent = agent;
81
95
  this._registerBaseTools(agentCardUri);
82
96
  }
@@ -120,3 +134,4 @@ export class BaseMCPService extends McpServer {
120
134
  }
121
135
  export const createMCPService = BaseMCPService.create;
122
136
  export const createMCPAgent = createMCPService;
137
+ export const mcp = createMCPService;
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { Tasks } from "../services/a2a/managers.js";
6
- import { eq, like, or } from "drizzle-orm";
6
+ import { eq, like, or, /*Table, TableConfig*/ } from "drizzle-orm";
7
7
  import { sqliteTable, text } from "drizzle-orm/sqlite-core";
8
8
  import { logger } from "../config/index.js";
9
9
  export const TABLE_NAME = "artinet_tasks";
@@ -16,6 +16,7 @@ const CREATE_TASKS_TABLE_SQL = `CREATE TABLE IF NOT EXISTS ${TABLE_NAME}\
16
16
  export const createTaskTable = async (db) => {
17
17
  await db.run(CREATE_TASKS_TABLE_SQL);
18
18
  };
19
+ /*export type TTable = Table<TableConfig>; //TODO: Unwind Config/Column types */
19
20
  export const TaskTable = sqliteTable(TABLE_NAME, {
20
21
  id: text().primaryKey(),
21
22
  contextId: text().notNull(),
@@ -261,7 +261,7 @@ export type Engine = (context: Context) => AsyncGenerator<Update, void, unknown>
261
261
  export interface BaseContext extends core.Context<Task> {
262
262
  readonly service: Service;
263
263
  /**
264
- * Considering ommit OnStart & OnComplete from Context consumers.
264
+ * Considering omitting OnStart & OnComplete from Context consumers.
265
265
  * That way the user cannot inadvertently trigger a start/completion out of band.
266
266
  */
267
267
  readonly publisher: EventPublisher;
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from "eventemitter3";
1
+ import { EventEmitter } from 'eventemitter3';
2
2
  import { IStore } from "../storage.js";
3
3
  export interface Service<Params extends object = object, Result extends unknown = void> {
4
4
  execute: (params: Params) => Promise<Result>;
@@ -21,6 +21,7 @@ export interface Manager<T = object> extends IStore<T> {
21
21
  delete: (id: string) => Promise<void>;
22
22
  has?: (id: string) => Promise<boolean>;
23
23
  list?: () => Promise<T[]>;
24
+ search?: (query: string, filter?: (item: T) => Promise<boolean>) => Promise<T[]>;
24
25
  }
25
26
  export type Optional<T extends object = object> = Partial<T> & {
26
27
  contextId: string;
@@ -4,3 +4,5 @@
4
4
  */
5
5
  import { A2A } from "../types/index.js";
6
6
  export declare const FINAL_STATES: A2A.TaskState[];
7
+ export declare const PROCESSING_STATES: A2A.TaskState[];
8
+ export declare const isProcessing: (state: A2A.TaskState) => boolean;
@@ -9,3 +9,8 @@ export const FINAL_STATES = [
9
9
  A2A.TaskState.canceled,
10
10
  A2A.TaskState.rejected,
11
11
  ];
12
+ export const PROCESSING_STATES = [
13
+ A2A.TaskState.working,
14
+ A2A.TaskState.submitted,
15
+ ];
16
+ export const isProcessing = (state) => PROCESSING_STATES.includes(state);
package/package.json CHANGED
@@ -1,179 +1,190 @@
1
1
  {
2
- "name": "@artinet/sdk",
3
- "version": "0.6.4",
4
- "description": "A TypeScript SDK for building collaborative AI agents.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "browser": {
12
- "types": "./dist/browser.d.ts",
13
- "import": "./dist/browser/browser.js",
14
- "default": "./dist/browser/browser.js"
15
- },
16
- "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js",
18
- "default": "./dist/index.js"
2
+ "name": "@artinet/sdk",
3
+ "version": "0.6.6",
4
+ "description": "A TypeScript SDK for building collaborative AI agents.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "browser": {
12
+ "types": "./dist/browser.d.ts",
13
+ "import": "./dist/browser/browser.js",
14
+ "default": "./dist/browser/browser.js"
15
+ },
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./mcp": {
21
+ "types": "./dist/services/mcp/index.d.ts",
22
+ "import": "./dist/services/mcp/index.js",
23
+ "default": "./dist/services/mcp/index.js"
24
+ },
25
+ "./serverless": {
26
+ "types": "./dist/server/express/serverless/index.d.ts",
27
+ "import": "./dist/server/express/serverless/index.js",
28
+ "default": "./dist/server/express/serverless/index.js"
29
+ },
30
+ "./sqlite": {
31
+ "types": "./dist/storage/sqlite.d.ts",
32
+ "import": "./dist/storage/sqlite.js",
33
+ "default": "./dist/storage/sqlite.js"
34
+ },
35
+ "./express": {
36
+ "types": "./dist/server/express/server.d.ts",
37
+ "import": "./dist/server/express/server.js",
38
+ "default": "./dist/server/express/server.js"
39
+ },
40
+ "./trpc": {
41
+ "types": "./dist/transport/trpc/index.d.ts",
42
+ "import": "./dist/transport/trpc/index.js",
43
+ "default": "./dist/transport/trpc/index.js"
44
+ },
45
+ "./types": {
46
+ "types": "./dist/types/index.d.ts",
47
+ "import": "./dist/types/index.js",
48
+ "default": "./dist/types/index.js"
49
+ },
50
+ "./pino": {
51
+ "types": "./dist/extensions/pino.d.ts",
52
+ "node": {
53
+ "import": "./dist/extensions/pino.js",
54
+ "default": "./dist/extensions/pino.js"
55
+ }
56
+ },
57
+ "./winston": {
58
+ "types": "./dist/extensions/winston.d.ts",
59
+ "node": {
60
+ "import": "./dist/extensions/winston.js",
61
+ "default": "./dist/extensions/winston.js"
62
+ }
63
+ },
64
+ "./otel": {
65
+ "types": "./dist/extensions/opentelemetry.d.ts",
66
+ "node": {
67
+ "import": "./dist/extensions/opentelemetry.js",
68
+ "default": "./dist/extensions/opentelemetry.js"
69
+ }
70
+ }
19
71
  },
20
- "./sqlite": {
21
- "types": "./dist/storage/sqlite.d.ts",
22
- "import": "./dist/storage/sqlite.js",
23
- "default": "./dist/storage/sqlite.js"
72
+ "rootDir": ".",
73
+ "files": [
74
+ "dist",
75
+ "package.json",
76
+ "README.md",
77
+ "LICENSE"
78
+ ],
79
+ "scripts": {
80
+ "prepare": "ts-patch install -s",
81
+ "build": "tsc --project tsconfig.json",
82
+ "build:browser": "tsc --project tsconfig.browser.json",
83
+ "build:all": "npm run build && npm run build:browser",
84
+ "clean": "rimraf dist",
85
+ "rebuild": "rimraf dist node_modules/ package-lock.json && npm i && npm run build:all",
86
+ "lint": "eslint src --ext .ts",
87
+ "package-test": "npm run build && npm pack && docker build -f ./deployment/test.dockerfile -t sdk-test . && docker run --rm sdk-test && rm artinet-sdk-*.tgz",
88
+ "prepublishOnly": "npm run rebuild && npm run lint && npm test",
89
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest",
90
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
91
+ "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
92
+ "dev:quickstart": "tsx watch quickstart/quick-server.ts"
24
93
  },
25
- "./express": {
26
- "types": "./dist/server/express/server.d.ts",
27
- "import": "./dist/server/express/server.js",
28
- "default": "./dist/server/express/server.js"
94
+ "keywords": [
95
+ "agent2agent",
96
+ "a2a",
97
+ "artinet",
98
+ "ai",
99
+ "agent",
100
+ "artificial intelligence",
101
+ "mcp",
102
+ "modelcontextprotocol"
103
+ ],
104
+ "author": "artinet",
105
+ "license": "Apache-2.0",
106
+ "repository": {
107
+ "type": "git",
108
+ "url": "https://github.com/the-artinet-project/artinet-sdk.git"
29
109
  },
30
- "./trpc": {
31
- "types": "./dist/transport/trpc/index.d.ts",
32
- "import": "./dist/transport/trpc/index.js",
33
- "default": "./dist/transport/trpc/index.js"
110
+ "bugs": {
111
+ "url": "https://github.com/the-artinet-project/artinet/issues"
34
112
  },
35
- "./types": {
36
- "types": "./dist/types/index.d.ts",
37
- "import": "./dist/types/index.js",
38
- "default": "./dist/types/index.js"
113
+ "homepage": "https://github.com/the-artinet-project/artinet-sdk#readme",
114
+ "dependencies": {
115
+ "@artinet/types": "^0.1.4",
116
+ "@opentelemetry/api": "^1.9.0",
117
+ "cors": "^2.8.5",
118
+ "eventemitter3": "^5.0.1",
119
+ "uuid": "^13.0.0",
120
+ "zod": "^3.25"
39
121
  },
40
- "./pino": {
41
- "types": "./dist/extensions/pino.d.ts",
42
- "node": {
43
- "import": "./dist/extensions/pino.js",
44
- "default": "./dist/extensions/pino.js"
45
- }
122
+ "peerDependencies": {
123
+ "@a2a-js/sdk": "^0.3.7",
124
+ "@modelcontextprotocol/sdk": "^1.24.3",
125
+ "@trpc/server": "^11.4.3",
126
+ "drizzle-orm": "^0.45.1",
127
+ "express": "^5.1.0"
46
128
  },
47
- "./winston": {
48
- "types": "./dist/extensions/winston.d.ts",
49
- "node": {
50
- "import": "./dist/extensions/winston.js",
51
- "default": "./dist/extensions/winston.js"
52
- }
129
+ "peerDependenciesMeta": {
130
+ "express": {
131
+ "optional": true
132
+ },
133
+ "@modelcontextprotocol/sdk": {
134
+ "optional": true
135
+ },
136
+ "@a2a-js/sdk": {
137
+ "optional": false
138
+ },
139
+ "@trpc/server": {
140
+ "optional": true
141
+ },
142
+ "pino": {
143
+ "optional": true
144
+ },
145
+ "winston": {
146
+ "optional": true
147
+ },
148
+ "drizzle-orm": {
149
+ "optional": true
150
+ }
53
151
  },
54
- "./otel": {
55
- "types": "./dist/extensions/opentelemetry.d.ts",
56
- "node": {
57
- "import": "./dist/extensions/opentelemetry.js",
58
- "default": "./dist/extensions/opentelemetry.js"
59
- }
60
- }
61
- },
62
- "rootDir": ".",
63
- "files": [
64
- "dist",
65
- "package.json",
66
- "README.md",
67
- "LICENSE"
68
- ],
69
- "scripts": {
70
- "prepare": "ts-patch install -s",
71
- "build": "tsc --project tsconfig.json",
72
- "build:browser": "tsc --project tsconfig.browser.json",
73
- "build:all": "npm run build && npm run build:browser",
74
- "clean": "rimraf dist",
75
- "rebuild": "rimraf dist node_modules/ package-lock.json && npm i && npm run build:all",
76
- "lint": "eslint src --ext .ts",
77
- "package-test": "npm run build && npm pack && docker build -f ./deployment/test.dockerfile -t sdk-test . && docker run --rm sdk-test && rm artinet-sdk-*.tgz",
78
- "prepublishOnly": "npm run package-test && npm run rebuild && npm run lint && npm test",
79
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
80
- "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
81
- "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
82
- "dev:quickstart": "tsx watch quickstart/quick-server.ts"
83
- },
84
- "keywords": [
85
- "agent2agent",
86
- "a2a",
87
- "artinet",
88
- "ai",
89
- "agent",
90
- "artificial intelligence",
91
- "mcp",
92
- "modelcontextprotocol"
93
- ],
94
- "author": "artinet",
95
- "license": "Apache-2.0",
96
- "repository": {
97
- "type": "git",
98
- "url": "https://github.com/the-artinet-project/artinet-sdk.git"
99
- },
100
- "bugs": {
101
- "url": "https://github.com/the-artinet-project/artinet/issues"
102
- },
103
- "homepage": "https://github.com/the-artinet-project/artinet-sdk#readme",
104
- "dependencies": {
105
- "@artinet/types": "^0.0.9",
106
- "@opentelemetry/api": "^1.9.0",
107
- "cors": "^2.8.5",
108
- "eventemitter3": "^5.0.1",
109
- "uuid": "^13.0.0",
110
- "zod": "^3.25"
111
- },
112
- "peerDependencies": {
113
- "express": "^5.1.0",
114
- "@a2a-js/sdk": "^0.3.7",
115
- "@modelcontextprotocol/sdk": "^1.24.3",
116
- "@trpc/server": "^11.4.3",
117
- "drizzle-orm": "^0.45.1"
118
- },
119
- "peerDependenciesMeta": {
120
- "express": {
121
- "optional": false
122
- },
123
- "@modelcontextprotocol/sdk": {
124
- "optional": false
125
- },
126
- "@a2a-js/sdk": {
127
- "optional": false
128
- },
129
- "@trpc/server": {
130
- "optional": true
131
- },
132
- "pino": {
133
- "optional": true
134
- },
135
- "winston": {
136
- "optional": true
152
+ "devDependencies": {
153
+ "@a2a-js/sdk": "^0.3.7",
154
+ "@cfworker/json-schema": "^4.1.1",
155
+ "@eslint/js": "^9.25.1",
156
+ "@modelcontextprotocol/sdk": "^1.24.3",
157
+ "@opentelemetry/api": "^1.9.0",
158
+ "@trpc/server": "^11.4.3",
159
+ "@types/cors": "^2.8.17",
160
+ "@types/escape-html": "^1.0.4",
161
+ "@types/express": "^5.0.1",
162
+ "@types/jest": "^30.0.0",
163
+ "@types/node": "^25.0.3",
164
+ "@types/supertest": "latest",
165
+ "better-sqlite3": "^12.6.2",
166
+ "drizzle-orm": "^0.45.1",
167
+ "eslint": "^9.25.1",
168
+ "globals": "^17.0.0",
169
+ "jest": "^30.2.0",
170
+ "lambda-local": "^2.2.0",
171
+ "msw": "^2.7.5",
172
+ "pino": "^10.1.0",
173
+ "pino-caller": "^4.0.0",
174
+ "pino-pretty": "^13.1.3",
175
+ "rimraf": "^6.1.2",
176
+ "serverless-http": "^4.0.0",
177
+ "supertest": "latest",
178
+ "ts-jest": "^29.4.6",
179
+ "ts-node": "^10.9.2",
180
+ "ts-patch": "^3.3.0",
181
+ "tsx": "^4.21.0",
182
+ "typescript": "^5.9.3",
183
+ "typescript-eslint": "^8.53.0",
184
+ "typescript-transform-paths": "^3.5.6",
185
+ "winston": "^3.19.0"
137
186
  },
138
- "drizzle-orm": {
139
- "optional": true
187
+ "engines": {
188
+ "node": ">=20.0.0"
140
189
  }
141
- },
142
- "devDependencies": {
143
- "better-sqlite3": "^12.5.0",
144
- "drizzle-orm": "^0.45.1",
145
- "@a2a-js/sdk": "^0.3.7",
146
- "@cfworker/json-schema": "^4.1.1",
147
- "@eslint/js": "^9.25.1",
148
- "@modelcontextprotocol/sdk": "^1.24.3",
149
- "@opentelemetry/api": "^1.9.0",
150
- "@trpc/server": "^11.4.3",
151
- "@types/cors": "^2.8.17",
152
- "@types/escape-html": "^1.0.4",
153
- "@types/express": "^5.0.1",
154
- "@types/jest": "^30.0.0",
155
- "@types/node": "^25.0.3",
156
- "@types/supertest": "latest",
157
- "eslint": "^9.25.1",
158
- "globals": "^16.0.0",
159
- "jest": "^30.2.0",
160
- "msw": "^2.7.5",
161
- "pino": "^10.1.0",
162
- "pino-caller": "^4.0.0",
163
- "pino-pretty": "^13.1.3",
164
- "rimraf": "^6.1.2",
165
- "supertest": "latest",
166
- "ts-jest": "^29.3.2",
167
- "ts-node": "^10.9.1",
168
- "ts-patch": "^3.3.0",
169
- "tsx": "^4.20.4",
170
- "typescript": "^5.2.2",
171
- "typescript-eslint": "^8.31.0",
172
- "typescript-transform-paths": "^3.5.5",
173
- "winston": "^3.19.0",
174
- "nock": "^14.0.10"
175
- },
176
- "engines": {
177
- "node": ">=18.9.1"
178
- }
179
190
  }