@artinet/sdk 0.6.5 → 0.6.7

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));
@@ -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,7 +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)}`);
507
- task.status.state = A2A.TaskState.completed;
508
+ task.status.state = isProcessing(task.status.state) ? A2A.TaskState.completed : task.status.state;
508
509
  yield task;
509
510
  };
510
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));
@@ -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,108 @@
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
+ const storedList = (await this.storage.list?.())?.filter((item) => item !== undefined && !listed.includes(item));
76
+ /** Could be an expensive operation */
77
+ listed.push(...(storedList ?? []));
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
+ const items = Array.from(this.cache.values());
92
+ const filterResults = await Promise.all(items.map(async (item) => {
93
+ if (await filter(item)) {
94
+ return item;
95
+ }
96
+ return undefined;
97
+ }));
98
+ results.push(...filterResults.filter((item) => item !== undefined));
99
+ }
100
+ if (this.storage) {
101
+ const storageFilter = async (item) => {
102
+ return ((await filter?.(item)) ?? true) && !results.includes(item);
103
+ };
104
+ /**Spreads are fine for now, but a for of loop and push is safer at scale. */
105
+ results.push(...((await this.storage.search?.(query, storageFilter)) ?? []));
106
+ }
107
+ return results;
46
108
  }
47
109
  }
48
110
  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';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Copyright 2026 The Artinet Project
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { z } from 'zod/v4';
8
+ /**
9
+ * Configuration for mounting an in-memory MCP server.
10
+ */
11
+ declare const InMemoryParamsSchema: z.ZodObject<{
12
+ type: z.ZodEnum<{
13
+ factory: "factory";
14
+ constructor: "constructor";
15
+ }>;
16
+ target: z.ZodString;
17
+ module: z.ZodString;
18
+ args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
19
+ }, z.core.$strip>;
20
+ export type InMemoryParams = z.infer<typeof InMemoryParamsSchema>;
21
+ /**
22
+ * Mounts an MCP server in-memory for direct integration.
23
+ * Creates a linked transport pair for client-server communication without network overhead.
24
+ * @docs https://modelcontextprotocol.io/docs/concepts/transports#in-memory
25
+ *
26
+ * @param params - {@link InMemoryParams} Configuration for the server module
27
+ * @param extract - Optional function to extract the McpServer from the imported module.
28
+ * Use when the module's export structure doesn't match standard factory/constructor patterns.
29
+ * @example
30
+ * ```typescript
31
+ * import { mountMemServer } from "@artinet/sdk/mcp/mem";
32
+ * import { Client } from "@modelcontextprotocol/sdk/client/index.js";
33
+ *
34
+ * // Mount a server using a factory function with custom extraction
35
+ * const { server, clientTransport } = await mountMemServer(
36
+ * {
37
+ * type: "factory",
38
+ * target: "createServer",
39
+ * module: "@modelcontextprotocol/server-everything/dist/everything.js",
40
+ * },
41
+ * (module) => module.createServer().server
42
+ * );
43
+ *
44
+ * // Connect a client to the in-memory server
45
+ * const client = new Client({ name: "my-client", version: "1.0.0" });
46
+ * await client.connect(clientTransport);
47
+ *
48
+ * // Use the client
49
+ * const tools = await client.listTools();
50
+ * ```
51
+ * @returns Promise containing the {@link McpServer} instance and linked transport pair
52
+ */
53
+ export declare function mountMemServer(params: InMemoryParams, extract?: (module: any) => McpServer): Promise<{
54
+ serverTransport: InMemoryTransport;
55
+ clientTransport: InMemoryTransport;
56
+ server: McpServer;
57
+ }>;
58
+ export {};
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Copyright 2026 The Artinet Project
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
6
+ import { logger } from "../../../config/index.js";
7
+ import { z } from 'zod/v4';
8
+ /**
9
+ * Configuration for mounting an in-memory MCP server.
10
+ */
11
+ const InMemoryParamsSchema = z.object({
12
+ /** Whether to invoke the target as a factory function or constructor */
13
+ type: z.enum(['factory', 'constructor']),
14
+ /** The name of the exported factory function or constructor class */
15
+ target: z.string(),
16
+ /** The module path to dynamically import (e.g., '@modelcontextprotocol/server-everything/dist/everything.js') */
17
+ module: z.string(),
18
+ /** Optional arguments to pass to the factory function or constructor */
19
+ args: z.record(z.string(), z.unknown()).optional(),
20
+ });
21
+ /**
22
+ * Mounts an MCP server in-memory for direct integration.
23
+ * Creates a linked transport pair for client-server communication without network overhead.
24
+ * @docs https://modelcontextprotocol.io/docs/concepts/transports#in-memory
25
+ *
26
+ * @param params - {@link InMemoryParams} Configuration for the server module
27
+ * @param extract - Optional function to extract the McpServer from the imported module.
28
+ * Use when the module's export structure doesn't match standard factory/constructor patterns.
29
+ * @example
30
+ * ```typescript
31
+ * import { mountMemServer } from "@artinet/sdk/mcp/mem";
32
+ * import { Client } from "@modelcontextprotocol/sdk/client/index.js";
33
+ *
34
+ * // Mount a server using a factory function with custom extraction
35
+ * const { server, clientTransport } = await mountMemServer(
36
+ * {
37
+ * type: "factory",
38
+ * target: "createServer",
39
+ * module: "@modelcontextprotocol/server-everything/dist/everything.js",
40
+ * },
41
+ * (module) => module.createServer().server
42
+ * );
43
+ *
44
+ * // Connect a client to the in-memory server
45
+ * const client = new Client({ name: "my-client", version: "1.0.0" });
46
+ * await client.connect(clientTransport);
47
+ *
48
+ * // Use the client
49
+ * const tools = await client.listTools();
50
+ * ```
51
+ * @returns Promise containing the {@link McpServer} instance and linked transport pair
52
+ */
53
+ export async function mountMemServer(params, extract) {
54
+ const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
55
+ //IFFE
56
+ const modules = (() => {
57
+ const modules = new Map();
58
+ return async (moduleName) => {
59
+ if (modules.has(moduleName)) {
60
+ return modules.get(moduleName);
61
+ }
62
+ const module = await import(moduleName).catch((error) => {
63
+ logger.error(`Failed to import module ${moduleName}`, error);
64
+ throw error;
65
+ });
66
+ if (module) {
67
+ modules.set(moduleName, module);
68
+ }
69
+ return module;
70
+ };
71
+ })();
72
+ const module = await modules(params.module).catch((error) => {
73
+ logger.error(`Failed to import module ${params.module}`, error);
74
+ throw error;
75
+ });
76
+ if (!module) {
77
+ logger.warn(`Failed to import module ${params.module}`);
78
+ throw new Error(`Failed to import module ${params.module}`);
79
+ }
80
+ let server;
81
+ if (extract) {
82
+ server = extract(module);
83
+ }
84
+ else if (params.type === 'factory') {
85
+ const factory = module[params.target];
86
+ if (!factory) {
87
+ const error = new Error(`Failed to find factory ${params.target} in module ${params.module}`);
88
+ logger.error(error.message, error);
89
+ throw error;
90
+ }
91
+ server = factory(params.args);
92
+ }
93
+ else {
94
+ const constructor = module[params.target];
95
+ if (!constructor) {
96
+ const error = new Error(`Failed to find constructor ${params.target} in module ${params.module}`);
97
+ logger.error(error.message, error);
98
+ throw error;
99
+ }
100
+ server = new constructor(params.args);
101
+ }
102
+ await server.connect(serverTransport).catch((error) => {
103
+ logger.error(`Failed to connect to server ${params.target}`, error);
104
+ throw error;
105
+ });
106
+ return { serverTransport, clientTransport, server };
107
+ }
@@ -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,195 @@
1
1
  {
2
- "name": "@artinet/sdk",
3
- "version": "0.6.5",
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.7",
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
+ "./mcp/mem": {
26
+ "types": "./dist/services/mcp/modules/mem.d.ts",
27
+ "import": "./dist/services/mcp/modules/mem.js",
28
+ "default": "./dist/services/mcp/modules/mem.js"
29
+ },
30
+ "./serverless": {
31
+ "types": "./dist/server/express/serverless/index.d.ts",
32
+ "import": "./dist/server/express/serverless/index.js",
33
+ "default": "./dist/server/express/serverless/index.js"
34
+ },
35
+ "./sqlite": {
36
+ "types": "./dist/storage/sqlite.d.ts",
37
+ "import": "./dist/storage/sqlite.js",
38
+ "default": "./dist/storage/sqlite.js"
39
+ },
40
+ "./express": {
41
+ "types": "./dist/server/express/server.d.ts",
42
+ "import": "./dist/server/express/server.js",
43
+ "default": "./dist/server/express/server.js"
44
+ },
45
+ "./trpc": {
46
+ "types": "./dist/transport/trpc/index.d.ts",
47
+ "import": "./dist/transport/trpc/index.js",
48
+ "default": "./dist/transport/trpc/index.js"
49
+ },
50
+ "./types": {
51
+ "types": "./dist/types/index.d.ts",
52
+ "import": "./dist/types/index.js",
53
+ "default": "./dist/types/index.js"
54
+ },
55
+ "./pino": {
56
+ "types": "./dist/extensions/pino.d.ts",
57
+ "node": {
58
+ "import": "./dist/extensions/pino.js",
59
+ "default": "./dist/extensions/pino.js"
60
+ }
61
+ },
62
+ "./winston": {
63
+ "types": "./dist/extensions/winston.d.ts",
64
+ "node": {
65
+ "import": "./dist/extensions/winston.js",
66
+ "default": "./dist/extensions/winston.js"
67
+ }
68
+ },
69
+ "./otel": {
70
+ "types": "./dist/extensions/opentelemetry.d.ts",
71
+ "node": {
72
+ "import": "./dist/extensions/opentelemetry.js",
73
+ "default": "./dist/extensions/opentelemetry.js"
74
+ }
75
+ }
19
76
  },
20
- "./sqlite": {
21
- "types": "./dist/storage/sqlite.d.ts",
22
- "import": "./dist/storage/sqlite.js",
23
- "default": "./dist/storage/sqlite.js"
77
+ "rootDir": ".",
78
+ "files": [
79
+ "dist",
80
+ "package.json",
81
+ "README.md",
82
+ "LICENSE"
83
+ ],
84
+ "scripts": {
85
+ "prepare": "ts-patch install -s",
86
+ "build": "tsc --project tsconfig.json",
87
+ "build:browser": "tsc --project tsconfig.browser.json",
88
+ "build:all": "npm run build && npm run build:browser",
89
+ "clean": "rimraf dist",
90
+ "rebuild": "rimraf dist node_modules/ package-lock.json && npm i && npm run build:all",
91
+ "lint": "eslint src --ext .ts",
92
+ "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",
93
+ "prepublishOnly": "npm run rebuild && npm run lint && npm test",
94
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest",
95
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
96
+ "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
97
+ "dev:quickstart": "tsx watch quickstart/quick-server.ts"
24
98
  },
25
- "./express": {
26
- "types": "./dist/server/express/server.d.ts",
27
- "import": "./dist/server/express/server.js",
28
- "default": "./dist/server/express/server.js"
99
+ "keywords": [
100
+ "agent2agent",
101
+ "a2a",
102
+ "artinet",
103
+ "ai",
104
+ "agent",
105
+ "artificial intelligence",
106
+ "mcp",
107
+ "modelcontextprotocol"
108
+ ],
109
+ "author": "artinet",
110
+ "license": "Apache-2.0",
111
+ "repository": {
112
+ "type": "git",
113
+ "url": "https://github.com/the-artinet-project/artinet-sdk.git"
29
114
  },
30
- "./trpc": {
31
- "types": "./dist/transport/trpc/index.d.ts",
32
- "import": "./dist/transport/trpc/index.js",
33
- "default": "./dist/transport/trpc/index.js"
115
+ "bugs": {
116
+ "url": "https://github.com/the-artinet-project/artinet/issues"
34
117
  },
35
- "./types": {
36
- "types": "./dist/types/index.d.ts",
37
- "import": "./dist/types/index.js",
38
- "default": "./dist/types/index.js"
118
+ "homepage": "https://github.com/the-artinet-project/artinet-sdk#readme",
119
+ "dependencies": {
120
+ "@artinet/types": "^0.1.4",
121
+ "@opentelemetry/api": "^1.9.0",
122
+ "cors": "^2.8.5",
123
+ "eventemitter3": "^5.0.1",
124
+ "uuid": "^13.0.0",
125
+ "zod": "^3.25"
39
126
  },
40
- "./pino": {
41
- "types": "./dist/extensions/pino.d.ts",
42
- "node": {
43
- "import": "./dist/extensions/pino.js",
44
- "default": "./dist/extensions/pino.js"
45
- }
127
+ "peerDependencies": {
128
+ "@a2a-js/sdk": "^0.3.7",
129
+ "@modelcontextprotocol/sdk": "^1.24.3",
130
+ "@trpc/server": "^11.4.3",
131
+ "drizzle-orm": "^0.45.1",
132
+ "express": "^5.1.0"
46
133
  },
47
- "./winston": {
48
- "types": "./dist/extensions/winston.d.ts",
49
- "node": {
50
- "import": "./dist/extensions/winston.js",
51
- "default": "./dist/extensions/winston.js"
52
- }
134
+ "peerDependenciesMeta": {
135
+ "express": {
136
+ "optional": true
137
+ },
138
+ "@modelcontextprotocol/sdk": {
139
+ "optional": true
140
+ },
141
+ "@a2a-js/sdk": {
142
+ "optional": false
143
+ },
144
+ "@trpc/server": {
145
+ "optional": true
146
+ },
147
+ "pino": {
148
+ "optional": true
149
+ },
150
+ "winston": {
151
+ "optional": true
152
+ },
153
+ "drizzle-orm": {
154
+ "optional": true
155
+ }
53
156
  },
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 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.1.4",
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
- "@a2a-js/sdk": "^0.3.7",
114
- "@modelcontextprotocol/sdk": "^1.24.3",
115
- "@trpc/server": "^11.4.3",
116
- "drizzle-orm": "^0.45.1",
117
- "express": "^5.1.0"
118
- },
119
- "peerDependenciesMeta": {
120
- "express": {
121
- "optional": true
122
- },
123
- "@modelcontextprotocol/sdk": {
124
- "optional": true
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
157
+ "devDependencies": {
158
+ "@a2a-js/sdk": "^0.3.7",
159
+ "@cfworker/json-schema": "^4.1.1",
160
+ "@eslint/js": "^9.25.1",
161
+ "@modelcontextprotocol/sdk": "^1.24.3",
162
+ "@opentelemetry/api": "^1.9.0",
163
+ "@trpc/server": "^11.4.3",
164
+ "@types/cors": "^2.8.17",
165
+ "@types/escape-html": "^1.0.4",
166
+ "@types/express": "^5.0.1",
167
+ "@types/jest": "^30.0.0",
168
+ "@types/node": "^25.0.3",
169
+ "@types/supertest": "latest",
170
+ "better-sqlite3": "^12.6.2",
171
+ "drizzle-orm": "^0.45.1",
172
+ "eslint": "^9.25.1",
173
+ "globals": "^17.0.0",
174
+ "jest": "^30.2.0",
175
+ "lambda-local": "^2.2.0",
176
+ "msw": "^2.7.5",
177
+ "pino": "^10.1.0",
178
+ "pino-caller": "^4.0.0",
179
+ "pino-pretty": "^13.1.3",
180
+ "rimraf": "^6.1.2",
181
+ "serverless-http": "^4.0.0",
182
+ "supertest": "latest",
183
+ "ts-jest": "^29.4.6",
184
+ "ts-node": "^10.9.2",
185
+ "ts-patch": "^3.3.0",
186
+ "tsx": "^4.21.0",
187
+ "typescript": "^5.9.3",
188
+ "typescript-eslint": "^8.53.0",
189
+ "typescript-transform-paths": "^3.5.6",
190
+ "winston": "^3.19.0"
137
191
  },
138
- "drizzle-orm": {
139
- "optional": true
192
+ "engines": {
193
+ "node": ">=20.0.0"
140
194
  }
141
- },
142
- "devDependencies": {
143
- "@a2a-js/sdk": "^0.3.7",
144
- "@cfworker/json-schema": "^4.1.1",
145
- "@eslint/js": "^9.25.1",
146
- "@modelcontextprotocol/sdk": "^1.24.3",
147
- "@opentelemetry/api": "^1.9.0",
148
- "@trpc/server": "^11.4.3",
149
- "@types/cors": "^2.8.17",
150
- "@types/escape-html": "^1.0.4",
151
- "@types/express": "^5.0.1",
152
- "@types/jest": "^30.0.0",
153
- "@types/node": "^25.0.3",
154
- "@types/supertest": "latest",
155
- "better-sqlite3": "^12.6.2",
156
- "drizzle-orm": "^0.45.1",
157
- "eslint": "^9.25.1",
158
- "globals": "^17.0.0",
159
- "jest": "^30.2.0",
160
- "msw": "^2.7.5",
161
- "nock": "^15.0.0",
162
- "pino": "^10.1.0",
163
- "pino-caller": "^4.0.0",
164
- "pino-pretty": "^13.1.3",
165
- "rimraf": "^6.1.2",
166
- "supertest": "latest",
167
- "ts-jest": "^29.4.6",
168
- "ts-node": "^10.9.2",
169
- "ts-patch": "^3.3.0",
170
- "tsx": "^4.21.0",
171
- "typescript": "^5.9.3",
172
- "typescript-eslint": "^8.53.0",
173
- "typescript-transform-paths": "^3.5.6",
174
- "winston": "^3.19.0"
175
- },
176
- "engines": {
177
- "node": ">=20.0.0"
178
- }
179
195
  }