@artinet/sdk 0.6.0-preview.1 → 0.6.0-preview.3
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 +8 -17
- package/dist/browser/client/a2a-client.js +4 -4
- package/dist/browser/config/index.d.ts +1 -1
- package/dist/browser/config/index.js +1 -1
- package/dist/browser/create/agentcard-builder.d.ts +47 -0
- package/dist/browser/create/agentcard-builder.js +65 -0
- package/dist/browser/create/base.d.ts +4 -0
- package/dist/browser/create/base.js +1 -0
- package/dist/browser/create/describe.d.ts +8 -0
- package/dist/browser/create/describe.js +8 -0
- package/dist/browser/create/message-builder.d.ts +78 -0
- package/dist/browser/create/message-builder.js +108 -0
- package/dist/browser/create/part-builder.d.ts +60 -0
- package/dist/browser/create/part-builder.js +81 -0
- package/dist/browser/create/task-builder.d.ts +251 -0
- package/dist/browser/create/task-builder.js +379 -0
- package/dist/browser/transport/rpc/parser.d.ts +1 -1
- package/dist/browser/transport/rpc/parser.js +2 -1
- package/dist/browser/types/a2a/a2a.d.ts +7 -3
- package/dist/browser/types/a2a/index.d.ts +3 -1
- package/dist/browser/types/a2a/index.js +0 -1
- package/dist/browser/utils/common/constants.d.ts +0 -5
- package/dist/browser/utils/common/constants.js +0 -27
- package/dist/browser/utils/common/errors.d.ts +57 -1
- package/dist/browser/utils/common/errors.js +68 -15
- package/dist/client/a2a-client.js +4 -4
- package/dist/config/default.d.ts +1 -1
- package/dist/config/default.js +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +1 -1
- package/dist/create/agent-builder.d.ts +77 -0
- package/dist/create/agent-builder.js +20 -0
- package/dist/create/agentcard-builder.d.ts +47 -0
- package/dist/create/agentcard-builder.js +66 -0
- package/dist/create/base.d.ts +4 -0
- package/dist/create/base.js +1 -0
- package/dist/create/create.d.ts +762 -0
- package/dist/create/create.js +556 -0
- package/dist/create/describe.d.ts +8 -0
- package/dist/create/describe.js +8 -0
- package/dist/create/index.d.ts +4 -0
- package/dist/create/index.js +4 -0
- package/dist/create/message-builder.d.ts +78 -0
- package/dist/create/message-builder.js +110 -0
- package/dist/create/part-builder.d.ts +60 -0
- package/dist/create/part-builder.js +84 -0
- package/dist/create/status-builder.d.ts +30 -0
- package/dist/create/status-builder.js +46 -0
- package/dist/create/task-builder.d.ts +251 -0
- package/dist/create/task-builder.js +384 -0
- package/dist/create/transform.d.ts +16 -0
- package/dist/create/transform.js +106 -0
- package/dist/extensions/otel.d.ts +3 -0
- package/dist/extensions/otel.js +3 -0
- package/dist/extensions/pino.d.ts +3 -0
- package/dist/extensions/pino.js +3 -0
- package/dist/extensions/winston.d.ts +3 -0
- package/dist/extensions/winston.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/server/express/errors.js +4 -8
- package/dist/server/express/middeware.js +17 -38
- package/dist/server/express/server.d.ts +20 -1
- package/dist/server/express/server.js +44 -12
- package/dist/services/a2a/execute.d.ts +5 -0
- package/dist/services/a2a/execute.js +7 -0
- package/dist/services/a2a/factory/context.d.ts +1 -1
- package/dist/services/a2a/factory/context.js +2 -3
- package/dist/services/a2a/factory/handler.js +3 -3
- package/dist/services/a2a/factory/index.d.ts +0 -1
- package/dist/services/a2a/factory/index.js +0 -1
- package/dist/services/a2a/factory/service.d.ts +2 -2
- package/dist/services/a2a/factory/service.js +2 -2
- package/dist/services/a2a/factory/state-machine.d.ts +1 -1
- package/dist/services/a2a/factory/state-machine.js +30 -8
- package/dist/services/a2a/handlers/artifact.d.ts +2 -5
- package/dist/services/a2a/handlers/artifact.js +21 -32
- package/dist/services/a2a/handlers/cancel-task.js +7 -5
- package/dist/services/a2a/handlers/resubscribe-task.d.ts +10 -2
- package/dist/services/a2a/handlers/resubscribe-task.js +21 -18
- package/dist/services/a2a/handlers/send-message.js +6 -10
- package/dist/services/a2a/handlers/stream-message.d.ts +10 -2
- package/dist/services/a2a/handlers/stream-message.js +5 -1
- package/dist/services/a2a/handlers/update.js +15 -12
- package/dist/services/a2a/helpers/content.d.ts +5 -1
- package/dist/services/a2a/helpers/content.js +5 -1
- package/dist/services/a2a/helpers/index.d.ts +2 -2
- package/dist/services/a2a/helpers/index.js +2 -2
- package/dist/services/a2a/index.d.ts +1 -1
- package/dist/services/a2a/index.js +1 -1
- package/dist/services/a2a/managers.js +7 -1
- package/dist/services/a2a/service.d.ts +6 -2
- package/dist/services/a2a/service.js +54 -61
- package/dist/services/a2a/state-machine.d.ts +3 -3
- package/dist/services/a2a/state-machine.js +2 -0
- package/dist/transport/rpc/parser.d.ts +1 -1
- package/dist/transport/rpc/parser.js +2 -1
- package/dist/transport/trpc/a2a/routes/message/route.js +2 -1
- package/dist/transport/trpc/a2a/routes/tasks/route.js +2 -1
- package/dist/types/a2a/a2a.d.ts +7 -3
- package/dist/types/a2a/index.d.ts +3 -1
- package/dist/types/a2a/index.js +0 -1
- package/dist/utils/common/constants.d.ts +0 -5
- package/dist/utils/common/constants.js +0 -27
- package/dist/utils/common/errors.d.ts +57 -1
- package/dist/utils/common/errors.js +68 -15
- package/dist/utils/common/parse.d.ts +1 -1
- package/dist/utils/common/schema-validation.d.ts +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/package.json +8 -5
- package/dist/browser/services/a2a/helpers/message-builder.d.ts +0 -17
- package/dist/browser/services/a2a/helpers/message-builder.js +0 -66
- package/dist/browser/types/a2a/builder.d.ts +0 -43
- package/dist/browser/types/a2a/builder.js +0 -5
- package/dist/services/a2a/factory/builder.d.ts +0 -292
- package/dist/services/a2a/factory/builder.js +0 -370
- package/dist/services/a2a/helpers/agentcard-builder.d.ts +0 -11
- package/dist/services/a2a/helpers/agentcard-builder.js +0 -27
- package/dist/services/a2a/helpers/message-builder.d.ts +0 -17
- package/dist/services/a2a/helpers/message-builder.js +0 -66
- package/dist/types/a2a/builder.d.ts +0 -43
- package/dist/types/a2a/builder.js +0 -5
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { A2A } from "../../types/index.js";
|
|
6
|
-
import { PUSH_NOTIFICATION_NOT_SUPPORTED, INVALID_REQUEST, INVALID_PARAMS, METHOD_NOT_FOUND, AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED, } from "../../utils/index.js";
|
|
7
5
|
import { logger } from "../../config/index.js";
|
|
6
|
+
import { formatJson } from "../../utils/common/utils.js";
|
|
7
|
+
import { A2AError } from "@a2a-js/sdk/server";
|
|
8
8
|
const isValidMethod = (method) => {
|
|
9
9
|
return (method &&
|
|
10
10
|
method !== "" &&
|
|
@@ -14,41 +14,35 @@ const isValidMethod = (method) => {
|
|
|
14
14
|
};
|
|
15
15
|
const checkParams = (params, method) => {
|
|
16
16
|
if (!params || (typeof params !== "object" && !Array.isArray(params))) {
|
|
17
|
-
throw
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
method,
|
|
21
|
-
},
|
|
17
|
+
throw A2AError.invalidParams("Invalid Parameters", {
|
|
18
|
+
params,
|
|
19
|
+
method,
|
|
22
20
|
});
|
|
23
21
|
}
|
|
24
22
|
else if (typeof params === "object" && Object.keys(params).length === 0) {
|
|
25
|
-
throw
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
method,
|
|
29
|
-
},
|
|
23
|
+
throw A2AError.invalidParams("Params Required", {
|
|
24
|
+
params,
|
|
25
|
+
method,
|
|
30
26
|
});
|
|
31
27
|
}
|
|
32
28
|
};
|
|
33
29
|
export async function jsonRPCMiddleware(service, req, res, next, extendedAgentCard) {
|
|
34
30
|
const { method, params, id, jsonrpc } = req.body;
|
|
35
31
|
if (jsonrpc !== "2.0" ||
|
|
36
|
-
(
|
|
32
|
+
(typeof id !== "string" &&
|
|
33
|
+
typeof id === "number" &&
|
|
34
|
+
!Number.isInteger(id) &&
|
|
35
|
+
id !== null)) {
|
|
37
36
|
res.json({
|
|
38
37
|
jsonrpc: "2.0",
|
|
39
38
|
id: id || null,
|
|
40
|
-
error:
|
|
39
|
+
error: A2AError.invalidRequest(`Invalid JSONRPC info: ${formatJson({ method, params, id, jsonrpc })}`).toJSONRPCError(),
|
|
41
40
|
});
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
43
|
try {
|
|
45
44
|
if (!isValidMethod(method)) {
|
|
46
|
-
throw
|
|
47
|
-
data: {
|
|
48
|
-
message: "No method provided",
|
|
49
|
-
method,
|
|
50
|
-
},
|
|
51
|
-
});
|
|
45
|
+
throw A2AError.invalidRequest("No method provided");
|
|
52
46
|
}
|
|
53
47
|
let result;
|
|
54
48
|
switch (method) {
|
|
@@ -101,34 +95,19 @@ export async function jsonRPCMiddleware(service, req, res, next, extendedAgentCa
|
|
|
101
95
|
case "tasks/pushNotificationConfig/get":
|
|
102
96
|
case "tasks/pushNotificationConfig/delete":
|
|
103
97
|
case "task/pushNotificationConfig/list": {
|
|
104
|
-
throw
|
|
105
|
-
data: {
|
|
106
|
-
message: "Push notifications not supported",
|
|
107
|
-
method,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
98
|
+
throw A2AError.pushNotificationNotSupported();
|
|
110
99
|
}
|
|
111
100
|
case "agent/getAuthenticatedExtendedCard": {
|
|
112
101
|
if (!extendedAgentCard ||
|
|
113
102
|
(await service.getAgentCard()).supportsAuthenticatedExtendedCard !==
|
|
114
103
|
true) {
|
|
115
|
-
throw
|
|
116
|
-
data: {
|
|
117
|
-
message: "Authenticated Extended Card is not configured",
|
|
118
|
-
method,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
104
|
+
throw A2AError.authenticatedExtendedCardNotConfigured();
|
|
121
105
|
}
|
|
122
106
|
result = extendedAgentCard;
|
|
123
107
|
break;
|
|
124
108
|
}
|
|
125
109
|
default:
|
|
126
|
-
throw
|
|
127
|
-
data: {
|
|
128
|
-
message: "Method not found",
|
|
129
|
-
method,
|
|
130
|
-
},
|
|
131
|
-
});
|
|
110
|
+
throw A2AError.methodNotFound(method);
|
|
132
111
|
}
|
|
133
112
|
res.json({ jsonrpc: "2.0", id, result });
|
|
134
113
|
}
|
|
@@ -11,14 +11,33 @@ export interface ServerParams {
|
|
|
11
11
|
app?: express.Express;
|
|
12
12
|
corsOptions?: CorsOptions;
|
|
13
13
|
basePath?: string;
|
|
14
|
+
port?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Your agentCard must have supportsAuthenticatedExtendedCard set to true
|
|
17
|
+
*/
|
|
14
18
|
extendedAgentCard?: A2A.AgentCard;
|
|
15
19
|
agent: Agent | CreateAgentParams;
|
|
16
20
|
agentCardPath?: string;
|
|
17
21
|
register?: boolean;
|
|
18
22
|
}
|
|
19
23
|
export declare function rpcParser(req: express.Request, res: express.Response, next: express.NextFunction): void;
|
|
20
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @note Best used with the `cr8` builder.
|
|
26
|
+
* @param {ServerParams} params - The server parameters
|
|
27
|
+
* @returns {ExpressAgentServer} - The express agent server
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const { app, agent, start } = createAgentServer({
|
|
31
|
+
* agent: cr8("MyAgent")
|
|
32
|
+
* .text("Hello, world!")
|
|
33
|
+
* .agent,
|
|
34
|
+
* basePath: "/a2a",
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function createAgentServer({ app, basePath, agentCardPath, agent, corsOptions, extendedAgentCard, register, port, }: ServerParams): {
|
|
21
39
|
app: express.Express;
|
|
22
40
|
agent: Agent;
|
|
41
|
+
start: (_port?: number) => import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
|
|
23
42
|
};
|
|
24
43
|
export type ExpressAgentServer = ReturnType<typeof createAgentServer>;
|
|
@@ -3,26 +3,24 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import express from "express";
|
|
6
|
-
import { INVALID_REQUEST, PARSE_ERROR } from "../../utils/index.js";
|
|
7
6
|
import { createAgent, Service, } from "../../services/index.js";
|
|
8
7
|
import cors from "cors";
|
|
9
8
|
import { jsonRPCMiddleware } from "./middeware.js";
|
|
10
9
|
import { errorHandler } from "./errors.js";
|
|
10
|
+
import { logger } from "../../config/index.js";
|
|
11
|
+
import { A2AError } from "@a2a-js/sdk/server";
|
|
12
|
+
import { formatJson } from "../../utils/common/utils.js";
|
|
11
13
|
export function rpcParser(req, res, next) {
|
|
12
14
|
express.json()(req, res, (err) => {
|
|
13
15
|
if (!req.body || typeof req.body !== "object") {
|
|
14
|
-
return next(
|
|
15
|
-
data: { message: "Invalid request body" },
|
|
16
|
-
}));
|
|
16
|
+
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
17
17
|
}
|
|
18
18
|
if (err) {
|
|
19
19
|
if (err instanceof SyntaxError &&
|
|
20
20
|
"status" in err &&
|
|
21
21
|
err.status === 400 &&
|
|
22
22
|
"body" in err) {
|
|
23
|
-
return next(
|
|
24
|
-
data: err.message,
|
|
25
|
-
}));
|
|
23
|
+
return next(A2AError.parseError(`Invalid request body: ${formatJson(req.body)}`));
|
|
26
24
|
}
|
|
27
25
|
return next(err);
|
|
28
26
|
}
|
|
@@ -46,7 +44,25 @@ const ensureAgent = (agentOrParams) => {
|
|
|
46
44
|
}
|
|
47
45
|
throw new Error("invalid agent or params");
|
|
48
46
|
};
|
|
49
|
-
|
|
47
|
+
const registerAgent = async (agentCard) => {
|
|
48
|
+
logger.debug("registerAgent: not implemented", { agentCard });
|
|
49
|
+
return Promise.resolve(agentCard);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* @note Best used with the `cr8` builder.
|
|
53
|
+
* @param {ServerParams} params - The server parameters
|
|
54
|
+
* @returns {ExpressAgentServer} - The express agent server
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const { app, agent, start } = createAgentServer({
|
|
58
|
+
* agent: cr8("MyAgent")
|
|
59
|
+
* .text("Hello, world!")
|
|
60
|
+
* .agent,
|
|
61
|
+
* basePath: "/a2a",
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function createAgentServer({ app = express(), basePath = "/", agentCardPath = "/.well-known/agent-card.json", agent, corsOptions, extendedAgentCard, register = false, port, }) {
|
|
50
66
|
const agentInstance = ensureAgent(agent);
|
|
51
67
|
app.use(cors(corsOptions));
|
|
52
68
|
if (agentCardPath !== "/.well-known/agent-card.json") {
|
|
@@ -72,10 +88,10 @@ export function createAgentServer({ app = express(), basePath = "/", agentCardPa
|
|
|
72
88
|
//a standard express middleware to handle json-rpc requests
|
|
73
89
|
app.post(basePath, rpcParser, async (req, res, next) => {
|
|
74
90
|
const { jsonrpc } = req.body;
|
|
75
|
-
if (jsonrpc
|
|
76
|
-
return
|
|
91
|
+
if (jsonrpc !== "2.0") {
|
|
92
|
+
return next(A2AError.invalidRequest("Invalid JSON-RPC request"));
|
|
77
93
|
}
|
|
78
|
-
|
|
94
|
+
return await jsonRPCMiddleware(agentInstance, req, res, next, extendedAgentCard);
|
|
79
95
|
});
|
|
80
96
|
app.use(errorHandler);
|
|
81
97
|
/** this is an example of using trpc as express middleware
|
|
@@ -94,5 +110,21 @@ export function createAgentServer({ app = express(), basePath = "/", agentCardPa
|
|
|
94
110
|
);
|
|
95
111
|
* we could also use trpc directly or any other transport layer
|
|
96
112
|
*/
|
|
97
|
-
|
|
113
|
+
const start = (_port) => {
|
|
114
|
+
try {
|
|
115
|
+
const listenPort = _port ?? port;
|
|
116
|
+
const server = app.listen(listenPort, () => {
|
|
117
|
+
logger.info(`Agent server started on port ${listenPort}`);
|
|
118
|
+
});
|
|
119
|
+
if (register) {
|
|
120
|
+
registerAgent(agentInstance.agentCard);
|
|
121
|
+
}
|
|
122
|
+
return server;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
logger.error(`Failed to start agent server`, error);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
return { app, agent: agentInstance, start };
|
|
98
130
|
}
|
|
@@ -3,4 +3,9 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { A2A } from "../../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Our universal executor for {@link A2A.Engine}.
|
|
8
|
+
* @param engine - {@link A2A.Engine} to execute.
|
|
9
|
+
* @param context - {@link A2A.Context} provided to the engine.
|
|
10
|
+
*/
|
|
6
11
|
export declare const execute: (engine: A2A.Engine, context: A2A.Context) => Promise<void>;
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* Our universal executor for {@link A2A.Engine}.
|
|
7
|
+
* @param engine - {@link A2A.Engine} to execute.
|
|
8
|
+
* @param context - {@link A2A.Context} provided to the engine.
|
|
9
|
+
*/
|
|
5
10
|
export const execute = async (engine, context) => {
|
|
6
11
|
try {
|
|
7
12
|
if (context.publisher.onStart) {
|
|
@@ -16,7 +21,9 @@ export const execute = async (engine, context) => {
|
|
|
16
21
|
}
|
|
17
22
|
}
|
|
18
23
|
catch (error) {
|
|
24
|
+
/* onError triggers completion internally */
|
|
19
25
|
await context.publisher.onError(error);
|
|
26
|
+
/* rethrow the error to be handled by the caller */
|
|
20
27
|
throw error;
|
|
21
28
|
}
|
|
22
29
|
finally {
|
|
@@ -6,7 +6,7 @@ import { A2A } from "../../../types/index.js";
|
|
|
6
6
|
export declare function createBaseContext({ contextId, service, task, overrides, abortSignal, }: {
|
|
7
7
|
contextId: string;
|
|
8
8
|
service: A2A.Service;
|
|
9
|
-
task
|
|
9
|
+
task: A2A.Task;
|
|
10
10
|
overrides?: Partial<Omit<A2A.EventConsumer, "contextId">>;
|
|
11
11
|
abortSignal?: AbortSignal;
|
|
12
12
|
}): A2A.BaseContext;
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
import { createStateMachine } from "./state-machine.js";
|
|
18
18
|
import { v4 as uuidv4 } from "uuid";
|
|
19
19
|
export function createBaseContext({ contextId = uuidv4(), service, task, overrides, abortSignal = new AbortController().signal, }) {
|
|
20
|
-
const isCancelled = async () => (await service.cancellations.has(task
|
|
21
|
-
abortSignal.aborted;
|
|
20
|
+
const isCancelled = async () => (await service.cancellations.has(task.id)) || abortSignal.aborted;
|
|
22
21
|
const getState = async (args) => args ? await service.tasks.get(args) : task;
|
|
23
22
|
const context = {
|
|
24
23
|
contextId: contextId,
|
|
@@ -34,7 +33,7 @@ export function createContext({ baseContext, taskId, messenger, extensions, refe
|
|
|
34
33
|
const getTask = async () => baseContext.publisher.currentTask;
|
|
35
34
|
const context = {
|
|
36
35
|
...baseContext,
|
|
37
|
-
taskId
|
|
36
|
+
taskId,
|
|
38
37
|
userMessage: messenger.message,
|
|
39
38
|
messages: messenger,
|
|
40
39
|
getTask,
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { getTask, cancelTask, sendMessage,
|
|
5
|
+
import { getTask, cancelTask, sendMessage, sendMessageStream, subscribeToTask, } from "../handlers/index.js";
|
|
6
6
|
export function createHandler(methods) {
|
|
7
7
|
return {
|
|
8
8
|
getTask: methods?.getTask ?? getTask,
|
|
9
9
|
cancelTask: methods?.cancelTask ?? cancelTask,
|
|
10
10
|
sendMessage: methods?.sendMessage ?? sendMessage,
|
|
11
|
-
streamMessage: methods?.streamMessage ??
|
|
12
|
-
resubscribe: methods?.resubscribe ??
|
|
11
|
+
streamMessage: methods?.streamMessage ?? sendMessageStream,
|
|
12
|
+
resubscribe: methods?.resubscribe ?? subscribeToTask,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import * as describe from "../../../create/agentcard-builder.js";
|
|
1
2
|
import { A2A } from "../../../types/index.js";
|
|
2
3
|
import { Service } from "../service.js";
|
|
3
|
-
export type AgentCardParams = (Partial<A2A.AgentCard> & Required<Pick<A2A.AgentCard, "name">>) | string;
|
|
4
4
|
export interface ServiceParams {
|
|
5
|
-
agentCard: AgentCardParams;
|
|
5
|
+
agentCard: describe.AgentCardParams;
|
|
6
6
|
engine: A2A.Engine;
|
|
7
7
|
contexts?: A2A.Contexts;
|
|
8
8
|
streams?: A2A.Streams;
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { createHandler } from "./handler.js";
|
|
6
|
-
import
|
|
6
|
+
import * as describe from "../../../create/agentcard-builder.js";
|
|
7
7
|
import { Service } from "../service.js";
|
|
8
8
|
import { Contexts, Streams, Connections, Cancellations, Tasks, } from "../managers.js";
|
|
9
9
|
export function createService(params) {
|
|
10
|
-
return new Service(
|
|
10
|
+
return new Service(describe.card(params.agentCard), params.engine, params.connections ?? new Connections(), params.cancellations ?? new Cancellations(), params.tasks ?? new Tasks(), params.contexts ?? new Contexts(), params.streams ?? new Streams(), createHandler(params.methods), params.overrides);
|
|
11
11
|
}
|
|
12
12
|
export const createAgent = createService;
|
|
@@ -6,6 +6,6 @@ import { A2A } from "../../../types/index.js";
|
|
|
6
6
|
export declare function createStateMachine({ contextId, service, task: currentTask, overrides, }: {
|
|
7
7
|
contextId: string;
|
|
8
8
|
service: A2A.Service;
|
|
9
|
-
task
|
|
9
|
+
task: A2A.Task;
|
|
10
10
|
overrides?: Partial<Omit<A2A.EventConsumer, "contextId">>;
|
|
11
11
|
}): A2A.EventPublisher;
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { StateMachine } from "../state-machine.js";
|
|
6
6
|
import { logger } from "../../../config/index.js";
|
|
7
|
-
import
|
|
7
|
+
import * as describe from "../../../create/describe.js";
|
|
8
|
+
import { TASK_NOT_FOUND } from "../../../utils/index.js";
|
|
8
9
|
import assert from "assert";
|
|
9
10
|
export function createStateMachine({ contextId, service, task: currentTask, overrides, }) {
|
|
10
11
|
const handler = {
|
|
@@ -25,7 +26,11 @@ export function createStateMachine({ contextId, service, task: currentTask, over
|
|
|
25
26
|
logger.info(`onCancel[ctx:${contextId}]:`, "cancellation triggered");
|
|
26
27
|
logger.debug(`onCancel[ctx:${contextId}]:`, "arguments", update, task);
|
|
27
28
|
await service.cancellations.set(task.id);
|
|
28
|
-
const cancellation =
|
|
29
|
+
const cancellation = describe.update.canceled({
|
|
30
|
+
taskId: task.id,
|
|
31
|
+
contextId: task.contextId,
|
|
32
|
+
message: update.status?.message,
|
|
33
|
+
});
|
|
29
34
|
await service.tasks.update((await service.contexts.get(contextId)), cancellation);
|
|
30
35
|
},
|
|
31
36
|
onUpdate: async (update, task) => {
|
|
@@ -43,17 +48,34 @@ export function createStateMachine({ contextId, service, task: currentTask, over
|
|
|
43
48
|
logger.error(`onError[ctx:${contextId}]:`, new Error("task not found"));
|
|
44
49
|
return;
|
|
45
50
|
}
|
|
46
|
-
const errorUpdate =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.
|
|
51
|
+
const errorUpdate = describe.update.failed({
|
|
52
|
+
taskId: task.id,
|
|
53
|
+
contextId,
|
|
54
|
+
message: describe.message({
|
|
55
|
+
messageId: "failed-update",
|
|
56
|
+
parts: [
|
|
57
|
+
{
|
|
58
|
+
kind: "text",
|
|
59
|
+
text: error instanceof Error ? error.message : String(error),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
const context = await service.contexts.get(contextId);
|
|
65
|
+
if (!context) {
|
|
66
|
+
logger.error(`onError[ctx:${contextId}]:`, new Error("context not found"));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await service.tasks.update(context, errorUpdate).catch((error) => {
|
|
50
70
|
//we capture errors thrown during error handling to ensure we trigger completion gracefully
|
|
51
|
-
logger.error(`onError[ctx:${contextId}]:`, error);
|
|
71
|
+
logger.error(`onError: task update error[ctx:${contextId}]:`, error);
|
|
52
72
|
});
|
|
73
|
+
// we trigger completion here to ensure the context is cleaned up
|
|
74
|
+
await context.publisher.onComplete();
|
|
53
75
|
},
|
|
54
76
|
onComplete: async (task) => {
|
|
55
77
|
assert(task.contextId === contextId, "context mismatch");
|
|
56
|
-
logger.info(`onComplete[ctx:${contextId}]
|
|
78
|
+
logger.info(`onComplete[ctx:${contextId}]: `, { taskId: task.id });
|
|
57
79
|
await service.cancellations.delete(task.id);
|
|
58
80
|
await service.connections.delete(task.contextId);
|
|
59
81
|
await service.contexts.delete(task.contextId);
|
|
@@ -3,8 +3,5 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { A2A } from "../../../types/index.js";
|
|
6
|
-
export declare function
|
|
7
|
-
|
|
8
|
-
replaced: boolean;
|
|
9
|
-
};
|
|
10
|
-
export declare function processArtifactUpdate(append: boolean, artifacts: A2A.Artifact[], artifactUpdate: A2A.Artifact): A2A.Artifact[];
|
|
6
|
+
export declare function updateArtifact(_artifact: A2A.Artifact, update: A2A.TaskArtifactUpdateEvent): A2A.Artifact;
|
|
7
|
+
export declare function upsertArtifact(artifacts: A2A.Artifact[], update: A2A.TaskArtifactUpdateEvent): A2A.Artifact[];
|
|
@@ -2,38 +2,27 @@
|
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
export function
|
|
6
|
-
if (append)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (artifactUpdate.name) {
|
|
19
|
-
existingArtifact.name = artifactUpdate.name;
|
|
20
|
-
}
|
|
21
|
-
artifacts[index] = existingArtifact;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
artifacts[index] = { ...artifactUpdate };
|
|
25
|
-
}
|
|
26
|
-
return { artifacts, replaced: true };
|
|
5
|
+
export function updateArtifact(_artifact, update) {
|
|
6
|
+
if (!update.append)
|
|
7
|
+
return update.artifact;
|
|
8
|
+
const artifactUpdate = update.artifact;
|
|
9
|
+
const artifact = _artifact;
|
|
10
|
+
artifact.metadata = {
|
|
11
|
+
...(artifact.metadata || {}),
|
|
12
|
+
...artifactUpdate.metadata,
|
|
13
|
+
};
|
|
14
|
+
artifact.description = artifactUpdate.description;
|
|
15
|
+
artifact.name = artifactUpdate.name;
|
|
16
|
+
artifact.parts.push(...artifactUpdate.parts);
|
|
17
|
+
return artifact;
|
|
27
18
|
}
|
|
28
|
-
export function
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
if (!replaced) {
|
|
36
|
-
newArtifacts.push({ ...artifactUpdate });
|
|
19
|
+
export function upsertArtifact(artifacts, update) {
|
|
20
|
+
const updateId = update.artifact.artifactId;
|
|
21
|
+
const index = artifacts.findIndex((a) => a.artifactId === updateId);
|
|
22
|
+
if (index === -1) {
|
|
23
|
+
artifacts.push({ ...update.artifact });
|
|
24
|
+
return artifacts;
|
|
37
25
|
}
|
|
38
|
-
|
|
26
|
+
artifacts[index] = updateArtifact(artifacts[index], update);
|
|
27
|
+
return artifacts;
|
|
39
28
|
}
|
|
@@ -16,7 +16,13 @@ export const cancelTask = async ({ id: taskId }, context) => {
|
|
|
16
16
|
if (FINAL_STATES.includes(task.status.state)) {
|
|
17
17
|
throw TASK_NOT_CANCELABLE("Task is in a final state: " + task.status.state);
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* By triggering onCancel, we're guaranteed that:
|
|
21
|
+
* - No further updates will be processed other than errors
|
|
22
|
+
* - The task will be cancelled
|
|
23
|
+
* - The task will be completed
|
|
24
|
+
* - The cancellations will be cleaned up
|
|
25
|
+
*/
|
|
20
26
|
const cancelledTask = {
|
|
21
27
|
...task,
|
|
22
28
|
status: {
|
|
@@ -24,10 +30,6 @@ export const cancelTask = async ({ id: taskId }, context) => {
|
|
|
24
30
|
state: A2A.TaskState.canceled,
|
|
25
31
|
},
|
|
26
32
|
};
|
|
27
|
-
context.publisher?.on("complete", async () => {
|
|
28
|
-
await service.cancellations.delete(taskId);
|
|
29
|
-
await service.contexts.delete(context.contextId);
|
|
30
|
-
});
|
|
31
33
|
await context.publisher.onCancel(cancelledTask);
|
|
32
34
|
return cancelledTask;
|
|
33
35
|
};
|
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { A2A } from "../../../types/index.js";
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const subscribeToTask: A2A.RequestHandler["resubscribe"];
|
|
7
|
+
export type SubscribeToTaskHandler = typeof subscribeToTask;
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Use SubscribeToTaskHandler instead
|
|
10
|
+
*/
|
|
11
|
+
export declare const resubscribe: (input: A2A.TaskIdParams, context?: A2A.Context, options?: A2A.ServiceOptions) => AsyncGenerator<A2A.Update>;
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use SubscribeToTaskHandler instead
|
|
14
|
+
*/
|
|
7
15
|
export type TaskResubscribeHandler = typeof resubscribe;
|
|
8
16
|
/**
|
|
9
|
-
* @deprecated Use
|
|
17
|
+
* @deprecated Use SubscribeToTaskHandler instead
|
|
10
18
|
*/
|
|
11
19
|
export type ResubscribeTaskMethod = TaskResubscribeHandler;
|
|
@@ -5,22 +5,22 @@
|
|
|
5
5
|
import { A2A } from "../../../types/index.js";
|
|
6
6
|
import { FINAL_STATES, INTERNAL_ERROR, TASK_NOT_FOUND } from "../../../utils/index.js";
|
|
7
7
|
const flush = (task, stream) => {
|
|
8
|
-
if (task.artifacts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
if (!task.artifacts || task.artifacts.length === 0)
|
|
9
|
+
return;
|
|
10
|
+
for (const artifact of task.artifacts) {
|
|
11
|
+
const artifactUpdate = {
|
|
12
|
+
kind: A2A.Kind["artifact-update"],
|
|
13
|
+
taskId: task.id,
|
|
14
|
+
contextId: task.contextId,
|
|
15
|
+
artifact,
|
|
16
|
+
lastChunk: task.artifacts.length === 1,
|
|
17
|
+
metadata: task.metadata,
|
|
18
|
+
};
|
|
19
|
+
stream.updates.push(artifactUpdate);
|
|
20
|
+
task.artifacts.shift();
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
-
export const
|
|
23
|
+
export const subscribeToTask = async function* ({ id: taskId }, context) {
|
|
24
24
|
if (!context) {
|
|
25
25
|
throw INTERNAL_ERROR({ error: { message: "Context is required" } });
|
|
26
26
|
}
|
|
@@ -33,9 +33,7 @@ export const resubscribe = async function* ({ id: taskId }, context) {
|
|
|
33
33
|
contextId: context.contextId,
|
|
34
34
|
context,
|
|
35
35
|
}));
|
|
36
|
-
//
|
|
37
|
-
// then we dont care about the upsert in onStart
|
|
38
|
-
// so we can just push the update and continue
|
|
36
|
+
// onStart no longer inserts a new task, so we can safely push the update and continue
|
|
39
37
|
context.publisher.on("start", async (_, task) => {
|
|
40
38
|
stream.updates.push({
|
|
41
39
|
kind: "status-update",
|
|
@@ -46,7 +44,8 @@ export const resubscribe = async function* ({ id: taskId }, context) {
|
|
|
46
44
|
metadata: task.metadata,
|
|
47
45
|
});
|
|
48
46
|
if (FINAL_STATES.includes(task.status.state)) {
|
|
49
|
-
|
|
47
|
+
/* We create a new task object to avoid mutating the original task */
|
|
48
|
+
flush({ ...task }, stream);
|
|
50
49
|
await stream.kill();
|
|
51
50
|
}
|
|
52
51
|
});
|
|
@@ -54,3 +53,7 @@ export const resubscribe = async function* ({ id: taskId }, context) {
|
|
|
54
53
|
service: service,
|
|
55
54
|
});
|
|
56
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated Use SubscribeToTaskHandler instead
|
|
58
|
+
*/
|
|
59
|
+
export const resubscribe = subscribeToTask;
|
|
@@ -8,15 +8,10 @@ export const sendMessage = async ({ configuration }, context) => {
|
|
|
8
8
|
if (!context) {
|
|
9
9
|
throw INTERNAL_ERROR({ error: { message: "Context is required" } });
|
|
10
10
|
}
|
|
11
|
-
context.publisher.on("complete", () => {
|
|
12
|
-
context.service.contexts.delete(context.contextId);
|
|
13
|
-
});
|
|
14
|
-
context.publisher.on("error", () => {
|
|
15
|
-
context.publisher.onComplete();
|
|
16
|
-
});
|
|
17
11
|
const service = context.service;
|
|
12
|
+
let task;
|
|
18
13
|
if (configuration?.blocking === false) {
|
|
19
|
-
|
|
14
|
+
task = await Promise.race([
|
|
20
15
|
service.execute({ engine: service.engine, context }).then(async () => {
|
|
21
16
|
return await context.getTask();
|
|
22
17
|
}),
|
|
@@ -26,10 +21,11 @@ export const sendMessage = async ({ configuration }, context) => {
|
|
|
26
21
|
});
|
|
27
22
|
}),
|
|
28
23
|
]);
|
|
29
|
-
return result;
|
|
30
24
|
}
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
else {
|
|
26
|
+
await service.execute({ engine: service.engine, context });
|
|
27
|
+
task = await context.getTask();
|
|
28
|
+
}
|
|
33
29
|
task.history = getLatestHistory(task, configuration?.historyLength);
|
|
34
30
|
return task;
|
|
35
31
|
};
|