@mantyx/sdk 0.1.1 → 0.3.0
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/CHANGELOG.md +19 -1
- package/README.md +213 -14
- package/dist/a2a-server.cjs +404 -0
- package/dist/a2a-server.cjs.map +1 -0
- package/dist/a2a-server.d.cts +170 -0
- package/dist/a2a-server.d.ts +170 -0
- package/dist/a2a-server.js +344 -0
- package/dist/a2a-server.js.map +1 -0
- package/dist/chunk-ZJINVTHD.js +1080 -0
- package/dist/chunk-ZJINVTHD.js.map +1 -0
- package/dist/client-Ce02_fV8.d.cts +591 -0
- package/dist/client-Ce02_fV8.d.ts +591 -0
- package/dist/index.cjs +591 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -261
- package/dist/index.d.ts +3 -261
- package/dist/index.js +30 -587
- package/dist/index.js.map +1 -1
- package/docs/agent-runs-protocol.md +370 -18
- package/package.json +24 -3
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -29,8 +39,14 @@ __export(index_exports, {
|
|
|
29
39
|
MantyxRunError: () => MantyxRunError,
|
|
30
40
|
MantyxToolError: () => MantyxToolError,
|
|
31
41
|
SDK_VERSION: () => SDK_VERSION,
|
|
42
|
+
defineLocalA2A: () => defineLocalA2A,
|
|
43
|
+
defineLocalMcp: () => defineLocalMcp,
|
|
32
44
|
defineLocalTool: () => defineLocalTool,
|
|
45
|
+
isLocalA2ATool: () => isLocalA2ATool,
|
|
46
|
+
isLocalMcpServer: () => isLocalMcpServer,
|
|
33
47
|
isLocalTool: () => isLocalTool,
|
|
48
|
+
mantyxA2A: () => mantyxA2A,
|
|
49
|
+
mantyxMcp: () => mantyxMcp,
|
|
34
50
|
mantyxPluginTool: () => mantyxPluginTool,
|
|
35
51
|
mantyxTool: () => mantyxTool,
|
|
36
52
|
readSseStream: () => readSseStream,
|
|
@@ -88,6 +104,350 @@ var MantyxRunError = class extends MantyxError {
|
|
|
88
104
|
}
|
|
89
105
|
};
|
|
90
106
|
|
|
107
|
+
// src/tools.ts
|
|
108
|
+
function defineLocalTool(opts) {
|
|
109
|
+
assertToolName(opts.name);
|
|
110
|
+
return {
|
|
111
|
+
kind: "local",
|
|
112
|
+
name: opts.name,
|
|
113
|
+
description: opts.description ?? "",
|
|
114
|
+
parameters: opts.parameters,
|
|
115
|
+
execute: opts.execute
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function mantyxTool(id) {
|
|
119
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
120
|
+
throw new Error("mantyxTool(id): id must be a non-empty string");
|
|
121
|
+
}
|
|
122
|
+
return { kind: "mantyx", id };
|
|
123
|
+
}
|
|
124
|
+
function mantyxPluginTool(name) {
|
|
125
|
+
if (typeof name !== "string" || !name.startsWith("@") || !name.includes("/")) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
`mantyxPluginTool(name): expected "@plugin-slug/tool-name", got ${JSON.stringify(name)}`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return { kind: "mantyx_plugin", name };
|
|
131
|
+
}
|
|
132
|
+
function mantyxA2A(opts) {
|
|
133
|
+
assertToolName(opts.name);
|
|
134
|
+
if (typeof opts.agentCardUrl !== "string" || opts.agentCardUrl.length === 0) {
|
|
135
|
+
throw new Error("mantyxA2A: agentCardUrl is required");
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
kind: "a2a",
|
|
139
|
+
name: opts.name,
|
|
140
|
+
...opts.description !== void 0 ? { description: opts.description } : {},
|
|
141
|
+
agentCardUrl: opts.agentCardUrl,
|
|
142
|
+
...opts.headers ? { headers: { ...opts.headers } } : {},
|
|
143
|
+
...opts.contextId ? { contextId: opts.contextId } : {}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function defineLocalA2A(opts) {
|
|
147
|
+
assertToolName(opts.name);
|
|
148
|
+
if (typeof opts.agentCardUrl !== "string" || opts.agentCardUrl.length === 0) {
|
|
149
|
+
throw new Error("defineLocalA2A: `agentCardUrl` is required");
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
kind: "a2a_local",
|
|
153
|
+
name: opts.name,
|
|
154
|
+
agentCardUrl: opts.agentCardUrl,
|
|
155
|
+
headers: opts.headers ? { ...opts.headers } : void 0
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function mantyxMcp(opts) {
|
|
159
|
+
assertToolName(opts.name);
|
|
160
|
+
if (typeof opts.url !== "string" || opts.url.length === 0) {
|
|
161
|
+
throw new Error("mantyxMcp: url is required");
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
kind: "mcp",
|
|
165
|
+
name: opts.name,
|
|
166
|
+
url: opts.url,
|
|
167
|
+
...opts.headers ? { headers: { ...opts.headers } } : {},
|
|
168
|
+
...opts.toolFilter ? { toolFilter: [...opts.toolFilter] } : {}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function defineLocalMcp(opts) {
|
|
172
|
+
assertToolName(opts.name);
|
|
173
|
+
const hasHttp = typeof opts.url === "string" && opts.url.length > 0;
|
|
174
|
+
const hasStdio = typeof opts.command === "string" && opts.command.length > 0;
|
|
175
|
+
if (hasHttp && hasStdio) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
"defineLocalMcp: pass either `url` (Streamable HTTP) or `command` (stdio), not both"
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
if (!hasHttp && !hasStdio) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"defineLocalMcp: one of `url` (Streamable HTTP) or `command` (stdio) is required"
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (hasHttp) {
|
|
186
|
+
const url = opts.url;
|
|
187
|
+
return {
|
|
188
|
+
kind: "mcp_local",
|
|
189
|
+
name: opts.name,
|
|
190
|
+
http: {
|
|
191
|
+
url,
|
|
192
|
+
...opts.headers ? { headers: { ...opts.headers } } : {}
|
|
193
|
+
},
|
|
194
|
+
stdio: void 0
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const command = opts.command;
|
|
198
|
+
return {
|
|
199
|
+
kind: "mcp_local",
|
|
200
|
+
name: opts.name,
|
|
201
|
+
http: void 0,
|
|
202
|
+
stdio: {
|
|
203
|
+
command,
|
|
204
|
+
...opts.args ? { args: [...opts.args] } : {},
|
|
205
|
+
...opts.env ? { env: { ...opts.env } } : {},
|
|
206
|
+
...opts.cwd ? { cwd: opts.cwd } : {}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function isLocalTool(t) {
|
|
211
|
+
return t.kind === "local";
|
|
212
|
+
}
|
|
213
|
+
function isLocalA2ATool(t) {
|
|
214
|
+
return t.kind === "a2a_local";
|
|
215
|
+
}
|
|
216
|
+
function isLocalMcpServer(t) {
|
|
217
|
+
return t.kind === "mcp_local";
|
|
218
|
+
}
|
|
219
|
+
var TOOL_NAME_RE = /^[a-zA-Z0-9_]{1,64}$/;
|
|
220
|
+
function assertToolName(name) {
|
|
221
|
+
if (!TOOL_NAME_RE.test(name)) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Invalid tool name ${JSON.stringify(name)}: must match /^[a-zA-Z0-9_]{1,64}$/`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function prefixedMcpToolName(serverName, toolName) {
|
|
228
|
+
const prefix = `${serverName}_`;
|
|
229
|
+
return toolName.startsWith(prefix) ? toolName : `${prefix}${toolName}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/local-resolver.ts
|
|
233
|
+
async function resolveLocalRefs(tools, opts = { fetch: globalThis.fetch }) {
|
|
234
|
+
if (!tools || tools.length === 0) return { newlyOpenedMcp: [] };
|
|
235
|
+
const newlyOpenedMcp = [];
|
|
236
|
+
const work = [];
|
|
237
|
+
for (const t of tools) {
|
|
238
|
+
if (isLocalA2ATool(t)) {
|
|
239
|
+
if (t._resolvedCard) continue;
|
|
240
|
+
work.push(resolveA2A(t, opts.fetch));
|
|
241
|
+
} else if (isLocalMcpServer(t)) {
|
|
242
|
+
if (t._resolved) continue;
|
|
243
|
+
work.push(
|
|
244
|
+
resolveMcp(t).then((resolved) => {
|
|
245
|
+
if (resolved) newlyOpenedMcp.push(t);
|
|
246
|
+
})
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
await Promise.all(work);
|
|
251
|
+
return { newlyOpenedMcp };
|
|
252
|
+
}
|
|
253
|
+
async function resolveA2A(t, fetchImpl) {
|
|
254
|
+
const headers = { Accept: "application/json", ...t.headers ?? {} };
|
|
255
|
+
const res = await fetchImpl(t.agentCardUrl, { method: "GET", headers });
|
|
256
|
+
if (!res.ok) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`defineLocalA2A(${JSON.stringify(t.name)}): GET ${t.agentCardUrl} returned ${res.status} ${res.statusText}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const card = await res.json();
|
|
262
|
+
if (!card || typeof card !== "object" || typeof card.name !== "string" || !card.name) {
|
|
263
|
+
throw new Error(
|
|
264
|
+
`defineLocalA2A(${JSON.stringify(t.name)}): ${t.agentCardUrl} did not return a valid Agent Card (missing required \`name\` field)`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
t._resolvedCard = card;
|
|
268
|
+
}
|
|
269
|
+
async function resolveMcp(t) {
|
|
270
|
+
const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
|
|
271
|
+
let transport;
|
|
272
|
+
let connect;
|
|
273
|
+
if (t.http) {
|
|
274
|
+
const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
275
|
+
const httpTransport = new StreamableHTTPClientTransport(new URL(t.http.url), {
|
|
276
|
+
requestInit: t.http.headers ? { headers: t.http.headers } : {}
|
|
277
|
+
});
|
|
278
|
+
transport = httpTransport;
|
|
279
|
+
connect = (c) => c.connect(httpTransport);
|
|
280
|
+
} else if (t.stdio) {
|
|
281
|
+
const { StdioClientTransport } = await import("@modelcontextprotocol/sdk/client/stdio.js");
|
|
282
|
+
const stdioTransport = new StdioClientTransport({
|
|
283
|
+
command: t.stdio.command,
|
|
284
|
+
...t.stdio.args ? { args: t.stdio.args } : {},
|
|
285
|
+
...t.stdio.env ? { env: t.stdio.env } : {},
|
|
286
|
+
...t.stdio.cwd ? { cwd: t.stdio.cwd } : {}
|
|
287
|
+
});
|
|
288
|
+
transport = stdioTransport;
|
|
289
|
+
connect = (c) => c.connect(stdioTransport);
|
|
290
|
+
} else {
|
|
291
|
+
throw new Error(
|
|
292
|
+
`defineLocalMcp(${JSON.stringify(t.name)}): missing transport (no \`url\` or \`command\` was provided)`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const client = new Client({ name: "@mantyx/sdk", version: "0.3.0" }, { capabilities: {} });
|
|
296
|
+
try {
|
|
297
|
+
await connect(client);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`defineLocalMcp(${JSON.stringify(t.name)}): failed to connect \u2014 ${err.message}`,
|
|
301
|
+
{ cause: err }
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const serverInfo = client.getServerVersion() ?? { name: t.name };
|
|
305
|
+
const listed = await client.listTools();
|
|
306
|
+
const tools = listed.tools.map((tool) => {
|
|
307
|
+
const out = {
|
|
308
|
+
name: tool.name,
|
|
309
|
+
inputSchema: tool.inputSchema
|
|
310
|
+
};
|
|
311
|
+
if (typeof tool.description === "string") out.description = tool.description;
|
|
312
|
+
if (tool.annotations) out.annotations = tool.annotations;
|
|
313
|
+
return out;
|
|
314
|
+
});
|
|
315
|
+
const close = async () => {
|
|
316
|
+
try {
|
|
317
|
+
await client.close();
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const t2 = transport;
|
|
322
|
+
if (t2.close) await t2.close();
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
t._resolved = {
|
|
327
|
+
serverInfo,
|
|
328
|
+
tools,
|
|
329
|
+
client,
|
|
330
|
+
close
|
|
331
|
+
};
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
async function closeMcpRefs(tools) {
|
|
335
|
+
if (!tools || tools.length === 0) return;
|
|
336
|
+
const closes = [];
|
|
337
|
+
for (const t of tools) {
|
|
338
|
+
if (!isLocalMcpServer(t)) continue;
|
|
339
|
+
const resolved = t._resolved;
|
|
340
|
+
if (!resolved) continue;
|
|
341
|
+
t._resolved = void 0;
|
|
342
|
+
closes.push(resolved.close());
|
|
343
|
+
}
|
|
344
|
+
await Promise.all(closes);
|
|
345
|
+
}
|
|
346
|
+
async function callA2A(t, args, opts = { fetch: globalThis.fetch }) {
|
|
347
|
+
const card = t._resolvedCard;
|
|
348
|
+
if (!card) {
|
|
349
|
+
throw new Error(
|
|
350
|
+
`defineLocalA2A(${JSON.stringify(t.name)}): agent card has not been resolved yet`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
const url = typeof card.url === "string" && card.url.length > 0 ? card.url : t.agentCardUrl;
|
|
354
|
+
const body = {
|
|
355
|
+
jsonrpc: "2.0",
|
|
356
|
+
id: cryptoRandomId(),
|
|
357
|
+
method: "message/send",
|
|
358
|
+
params: {
|
|
359
|
+
message: {
|
|
360
|
+
kind: "message",
|
|
361
|
+
role: "user",
|
|
362
|
+
messageId: cryptoRandomId(),
|
|
363
|
+
parts: [{ kind: "text", text: args.message }]
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
const res = await opts.fetch(url, {
|
|
368
|
+
method: "POST",
|
|
369
|
+
headers: {
|
|
370
|
+
"Content-Type": "application/json",
|
|
371
|
+
Accept: "application/json",
|
|
372
|
+
...t.headers ?? {}
|
|
373
|
+
},
|
|
374
|
+
body: JSON.stringify(body)
|
|
375
|
+
});
|
|
376
|
+
if (!res.ok) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`A2A message/send to ${url} returned ${res.status} ${res.statusText}`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
const json = await res.json();
|
|
382
|
+
if (json.error) {
|
|
383
|
+
throw new Error(`A2A peer reported error ${json.error.code}: ${json.error.message}`);
|
|
384
|
+
}
|
|
385
|
+
return extractA2AReplyText(json.result);
|
|
386
|
+
}
|
|
387
|
+
function extractA2AReplyText(result) {
|
|
388
|
+
if (result == null) return "";
|
|
389
|
+
if (typeof result === "string") return result;
|
|
390
|
+
if (typeof result !== "object") return JSON.stringify(result);
|
|
391
|
+
const obj = result;
|
|
392
|
+
if (Array.isArray(obj.parts)) {
|
|
393
|
+
const text = textFromParts(obj.parts);
|
|
394
|
+
if (text) return text;
|
|
395
|
+
}
|
|
396
|
+
const status = obj.status;
|
|
397
|
+
const statusMessage = status?.message;
|
|
398
|
+
if (Array.isArray(statusMessage?.parts)) {
|
|
399
|
+
const text = textFromParts(statusMessage.parts);
|
|
400
|
+
if (text) return text;
|
|
401
|
+
}
|
|
402
|
+
const artifacts = obj.artifacts;
|
|
403
|
+
if (Array.isArray(artifacts) && artifacts.length > 0) {
|
|
404
|
+
const last = artifacts[artifacts.length - 1];
|
|
405
|
+
if (Array.isArray(last.parts)) {
|
|
406
|
+
const text = textFromParts(last.parts);
|
|
407
|
+
if (text) return text;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return JSON.stringify(result);
|
|
411
|
+
}
|
|
412
|
+
function textFromParts(parts) {
|
|
413
|
+
const out = [];
|
|
414
|
+
for (const part of parts) {
|
|
415
|
+
if (!part || typeof part !== "object") continue;
|
|
416
|
+
const p = part;
|
|
417
|
+
if ((p.kind === "text" || p.type === "text") && typeof p.text === "string") {
|
|
418
|
+
out.push(p.text);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return out.join("\n");
|
|
422
|
+
}
|
|
423
|
+
async function callMcpTool(server, toolName, args) {
|
|
424
|
+
const resolved = server._resolved;
|
|
425
|
+
if (!resolved) {
|
|
426
|
+
throw new Error(
|
|
427
|
+
`defineLocalMcp(${JSON.stringify(server.name)}): MCP server has not been initialised`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
const result = await resolved.client.callTool({ name: toolName, arguments: args });
|
|
431
|
+
if (result.isError) {
|
|
432
|
+
const text = textFromMcpContent(result.content) || "MCP tool reported an error";
|
|
433
|
+
throw new Error(text);
|
|
434
|
+
}
|
|
435
|
+
return textFromMcpContent(result.content);
|
|
436
|
+
}
|
|
437
|
+
function textFromMcpContent(content) {
|
|
438
|
+
if (!content || content.length === 0) return "";
|
|
439
|
+
const out = [];
|
|
440
|
+
for (const block of content) {
|
|
441
|
+
if (block.type === "text" && typeof block.text === "string") out.push(block.text);
|
|
442
|
+
}
|
|
443
|
+
return out.join("\n");
|
|
444
|
+
}
|
|
445
|
+
function cryptoRandomId() {
|
|
446
|
+
const c = globalThis.crypto;
|
|
447
|
+
if (c?.randomUUID) return c.randomUUID();
|
|
448
|
+
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
449
|
+
}
|
|
450
|
+
|
|
91
451
|
// src/sse.ts
|
|
92
452
|
async function* readSseStream(body, opts = {}) {
|
|
93
453
|
if (!body) return;
|
|
@@ -163,39 +523,6 @@ function parseEventBlock(block) {
|
|
|
163
523
|
};
|
|
164
524
|
}
|
|
165
525
|
|
|
166
|
-
// src/tools.ts
|
|
167
|
-
function defineLocalTool(opts) {
|
|
168
|
-
if (!/^[a-zA-Z0-9_]{1,64}$/.test(opts.name)) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
`Invalid local tool name ${JSON.stringify(opts.name)}: must match /^[a-zA-Z0-9_]{1,64}$/`
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
return {
|
|
174
|
-
kind: "local",
|
|
175
|
-
name: opts.name,
|
|
176
|
-
description: opts.description ?? "",
|
|
177
|
-
parameters: opts.parameters,
|
|
178
|
-
execute: opts.execute
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function mantyxTool(id) {
|
|
182
|
-
if (typeof id !== "string" || id.length === 0) {
|
|
183
|
-
throw new Error("mantyxTool(id): id must be a non-empty string");
|
|
184
|
-
}
|
|
185
|
-
return { kind: "mantyx", id };
|
|
186
|
-
}
|
|
187
|
-
function mantyxPluginTool(name) {
|
|
188
|
-
if (typeof name !== "string" || !name.startsWith("@") || !name.includes("/")) {
|
|
189
|
-
throw new Error(
|
|
190
|
-
`mantyxPluginTool(name): expected "@plugin-slug/tool-name", got ${JSON.stringify(name)}`
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
return { kind: "mantyx_plugin", name };
|
|
194
|
-
}
|
|
195
|
-
function isLocalTool(t) {
|
|
196
|
-
return t.kind === "local";
|
|
197
|
-
}
|
|
198
|
-
|
|
199
526
|
// src/zod-to-json-schema.ts
|
|
200
527
|
var import_zod = require("zod");
|
|
201
528
|
function zodToJsonSchema(schema) {
|
|
@@ -277,7 +604,7 @@ function toToolParametersWire(parameters) {
|
|
|
277
604
|
}
|
|
278
605
|
|
|
279
606
|
// src/client.ts
|
|
280
|
-
var DEFAULT_BASE_URL = "https://
|
|
607
|
+
var DEFAULT_BASE_URL = "https://app.mantyx.io";
|
|
281
608
|
var MantyxClient = class {
|
|
282
609
|
options;
|
|
283
610
|
constructor(opts) {
|
|
@@ -310,47 +637,79 @@ var MantyxClient = class {
|
|
|
310
637
|
}
|
|
311
638
|
// ------------------------------------------------------------- One-shot
|
|
312
639
|
async runAgent(spec) {
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
640
|
+
const tools = spec.tools ?? [];
|
|
641
|
+
await resolveLocalRefs(tools, { fetch: this.options.fetch });
|
|
642
|
+
const handlers = collectLocalHandlers(tools);
|
|
643
|
+
try {
|
|
644
|
+
const created = await this.request({
|
|
645
|
+
method: "POST",
|
|
646
|
+
path: "/agent-runs",
|
|
647
|
+
body: serializeAgentSpec(spec, {
|
|
648
|
+
prompt: spec.prompt,
|
|
649
|
+
messages: spec.messages
|
|
650
|
+
})
|
|
651
|
+
});
|
|
652
|
+
return await this.driveRun(created.runId, handlers, {
|
|
653
|
+
...spec.onAssistantDelta ? { onAssistantDelta: spec.onAssistantDelta } : {},
|
|
654
|
+
...spec.onEvent ? { onEvent: spec.onEvent } : {},
|
|
655
|
+
...spec.signal ? { signal: spec.signal } : {}
|
|
656
|
+
});
|
|
657
|
+
} finally {
|
|
658
|
+
await closeMcpRefs(tools);
|
|
659
|
+
}
|
|
327
660
|
}
|
|
328
661
|
async *streamAgent(spec) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
662
|
+
const tools = spec.tools ?? [];
|
|
663
|
+
await resolveLocalRefs(tools, { fetch: this.options.fetch });
|
|
664
|
+
const handlers = collectLocalHandlers(tools);
|
|
665
|
+
try {
|
|
666
|
+
const created = await this.request({
|
|
667
|
+
method: "POST",
|
|
668
|
+
path: "/agent-runs",
|
|
669
|
+
body: serializeAgentSpec(spec, {
|
|
670
|
+
prompt: spec.prompt,
|
|
671
|
+
messages: spec.messages
|
|
672
|
+
})
|
|
673
|
+
});
|
|
674
|
+
yield* this.streamRunEvents(created.runId, handlers, spec.signal);
|
|
675
|
+
} finally {
|
|
676
|
+
await closeMcpRefs(tools);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Internal registry of client-resolved tool handlers. Exposed for callers
|
|
681
|
+
* who drive the run loop manually via `driveRun` / `streamRunEvents`.
|
|
682
|
+
*/
|
|
683
|
+
collectHandlers(tools) {
|
|
684
|
+
return collectLocalHandlers(tools);
|
|
339
685
|
}
|
|
340
686
|
// ------------------------------------------------------------- Sessions
|
|
341
687
|
async createSession(spec) {
|
|
342
|
-
const
|
|
688
|
+
const tools = spec.tools ?? [];
|
|
689
|
+
await resolveLocalRefs(tools, { fetch: this.options.fetch });
|
|
690
|
+
const handlers = collectLocalHandlers(tools);
|
|
343
691
|
const created = await this.request({
|
|
344
692
|
method: "POST",
|
|
345
693
|
path: "/agent-sessions",
|
|
346
694
|
body: serializeAgentSpec(spec)
|
|
347
695
|
});
|
|
348
|
-
return new AgentSession(this, created.sessionId, handlers);
|
|
696
|
+
return new AgentSession(this, created.sessionId, handlers, tools);
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Re-emit a `local_tool_call` event into the right local handler. Useful
|
|
700
|
+
* for tests and for users who consume events via `streamAgent` themselves.
|
|
701
|
+
*/
|
|
702
|
+
async dispatchLocalToolFromEvent(runId, ev, handlers) {
|
|
703
|
+
return this.dispatchLocalTool(runId, ev, handlers);
|
|
349
704
|
}
|
|
350
705
|
async resumeSession(sessionId, opts = {}) {
|
|
351
706
|
await this.getSessionInfo(sessionId);
|
|
352
|
-
const
|
|
353
|
-
|
|
707
|
+
const tools = opts.tools ?? [];
|
|
708
|
+
if (tools.length > 0) {
|
|
709
|
+
await resolveLocalRefs(tools, { fetch: this.options.fetch });
|
|
710
|
+
}
|
|
711
|
+
const handlers = collectLocalHandlers(tools);
|
|
712
|
+
return new AgentSession(this, sessionId, handlers, tools);
|
|
354
713
|
}
|
|
355
714
|
async endSession(sessionId) {
|
|
356
715
|
await this.request({
|
|
@@ -448,22 +807,49 @@ var MantyxClient = class {
|
|
|
448
807
|
}
|
|
449
808
|
}
|
|
450
809
|
async dispatchLocalTool(runId, ev, handlers) {
|
|
451
|
-
const
|
|
452
|
-
if (!handler) {
|
|
453
|
-
await this.postToolResult(runId, ev.toolUseId, {
|
|
454
|
-
error: `No local handler registered for tool ${JSON.stringify(ev.name)}`
|
|
455
|
-
});
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
810
|
+
const kind = ev.kind ?? "local";
|
|
458
811
|
try {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
812
|
+
let out;
|
|
813
|
+
if (kind === "a2a_local") {
|
|
814
|
+
const tool = handlers.a2aTools.get(ev.name);
|
|
815
|
+
if (!tool) {
|
|
816
|
+
await this.postToolResult(runId, ev.toolUseId, {
|
|
817
|
+
error: `No local A2A handler registered for tool ${JSON.stringify(ev.name)}`
|
|
818
|
+
});
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const message = typeof ev.args?.message === "string" ? ev.args.message : "";
|
|
822
|
+
out = await callA2A(tool, { message }, { fetch: this.options.fetch });
|
|
823
|
+
} else if (kind === "mcp_local") {
|
|
824
|
+
const serverName = ev.mcpServer ?? "";
|
|
825
|
+
const mcpToolName = ev.mcpToolName ?? "";
|
|
826
|
+
const server = handlers.mcpServers.get(serverName);
|
|
827
|
+
if (!server) {
|
|
828
|
+
await this.postToolResult(runId, ev.toolUseId, {
|
|
829
|
+
error: `No local MCP server registered as ${JSON.stringify(serverName)}`
|
|
830
|
+
});
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const upstreamName = mcpToolName.startsWith(`${serverName}_`) ? mcpToolName.slice(serverName.length + 1) : mcpToolName;
|
|
834
|
+
out = await callMcpTool(server, upstreamName, ev.args ?? {});
|
|
835
|
+
} else {
|
|
836
|
+
const handler = handlers.localTools.get(ev.name);
|
|
837
|
+
if (!handler) {
|
|
838
|
+
await this.postToolResult(runId, ev.toolUseId, {
|
|
839
|
+
error: `No local handler registered for tool ${JSON.stringify(ev.name)}`
|
|
840
|
+
});
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const args = handler.parameters ? handler.parameters.parse?.(ev.args) ?? ev.args : ev.args;
|
|
844
|
+
const result = await handler.execute(args);
|
|
845
|
+
out = typeof result === "string" ? result : JSON.stringify(result);
|
|
846
|
+
}
|
|
847
|
+
await this.postToolResult(runId, ev.toolUseId, { result: out });
|
|
463
848
|
} catch (err) {
|
|
464
849
|
const message = err instanceof Error ? err.message : String(err);
|
|
850
|
+
const handlerName = describeHandlerName(ev);
|
|
465
851
|
await this.postToolResult(runId, ev.toolUseId, {
|
|
466
|
-
error: new MantyxToolError(
|
|
852
|
+
error: new MantyxToolError(handlerName, message).message
|
|
467
853
|
});
|
|
468
854
|
}
|
|
469
855
|
}
|
|
@@ -541,22 +927,18 @@ var AgentSession = class {
|
|
|
541
927
|
id;
|
|
542
928
|
client;
|
|
543
929
|
handlers;
|
|
544
|
-
|
|
545
|
-
constructor(client, id, handlers,
|
|
930
|
+
tools;
|
|
931
|
+
constructor(client, id, handlers, tools) {
|
|
546
932
|
this.client = client;
|
|
547
933
|
this.id = id;
|
|
548
934
|
this.handlers = handlers;
|
|
549
|
-
this.
|
|
935
|
+
this.tools = tools ?? [];
|
|
550
936
|
}
|
|
551
937
|
async send(prompt, opts = {}) {
|
|
552
938
|
const created = await this.client.request({
|
|
553
939
|
method: "POST",
|
|
554
940
|
path: `/agent-sessions/${encodeURIComponent(this.id)}/messages`,
|
|
555
|
-
body:
|
|
556
|
-
prompt,
|
|
557
|
-
...this.toolsForResume ? { tools: serializeToolRefs(this.toolsForResume) } : {},
|
|
558
|
-
...opts.metadata && Object.keys(opts.metadata).length > 0 ? { metadata: opts.metadata } : {}
|
|
559
|
-
}
|
|
941
|
+
body: this.buildSessionMessageBody(prompt, opts)
|
|
560
942
|
});
|
|
561
943
|
return this.client.driveRun(created.runId, this.handlers, {
|
|
562
944
|
...opts.onAssistantDelta ? { onAssistantDelta: opts.onAssistantDelta } : {},
|
|
@@ -567,14 +949,19 @@ var AgentSession = class {
|
|
|
567
949
|
const created = await this.client.request({
|
|
568
950
|
method: "POST",
|
|
569
951
|
path: `/agent-sessions/${encodeURIComponent(this.id)}/messages`,
|
|
570
|
-
body:
|
|
571
|
-
prompt,
|
|
572
|
-
...this.toolsForResume ? { tools: serializeToolRefs(this.toolsForResume) } : {},
|
|
573
|
-
...opts.metadata && Object.keys(opts.metadata).length > 0 ? { metadata: opts.metadata } : {}
|
|
574
|
-
}
|
|
952
|
+
body: this.buildSessionMessageBody(prompt, opts)
|
|
575
953
|
});
|
|
576
954
|
yield* this.client.streamRunEvents(created.runId, this.handlers, opts.signal);
|
|
577
955
|
}
|
|
956
|
+
buildSessionMessageBody(prompt, opts) {
|
|
957
|
+
const body = { prompt };
|
|
958
|
+
if (this.tools.length > 0) body.tools = serializeToolRefs(this.tools);
|
|
959
|
+
if (opts.metadata && Object.keys(opts.metadata).length > 0) body.metadata = opts.metadata;
|
|
960
|
+
if (opts.reasoningLevel !== void 0) {
|
|
961
|
+
body.reasoningLevel = normalizeReasoningLevel(opts.reasoningLevel);
|
|
962
|
+
}
|
|
963
|
+
return body;
|
|
964
|
+
}
|
|
578
965
|
async history() {
|
|
579
966
|
const info = await this.client.getSessionInfo(this.id);
|
|
580
967
|
return info.messages;
|
|
@@ -583,7 +970,11 @@ var AgentSession = class {
|
|
|
583
970
|
return this.client.getSessionInfo(this.id);
|
|
584
971
|
}
|
|
585
972
|
async end() {
|
|
586
|
-
|
|
973
|
+
try {
|
|
974
|
+
await this.client.endSession(this.id);
|
|
975
|
+
} finally {
|
|
976
|
+
await closeMcpRefs(this.tools);
|
|
977
|
+
}
|
|
587
978
|
}
|
|
588
979
|
};
|
|
589
980
|
function serializeAgentSpec(spec, extra = {}) {
|
|
@@ -597,6 +988,9 @@ function serializeAgentSpec(spec, extra = {}) {
|
|
|
597
988
|
if (spec.agentId) body.agentId = spec.agentId;
|
|
598
989
|
if (spec.name) body.name = spec.name;
|
|
599
990
|
if (spec.modelId) body.modelId = spec.modelId;
|
|
991
|
+
if (spec.reasoningLevel !== void 0) {
|
|
992
|
+
body.reasoningLevel = normalizeReasoningLevel(spec.reasoningLevel);
|
|
993
|
+
}
|
|
600
994
|
if (spec.budgets) body.budgets = spec.budgets;
|
|
601
995
|
if (spec.metadata && Object.keys(spec.metadata).length > 0) body.metadata = spec.metadata;
|
|
602
996
|
if (extra.prompt !== void 0) body.prompt = extra.prompt;
|
|
@@ -605,29 +999,120 @@ function serializeAgentSpec(spec, extra = {}) {
|
|
|
605
999
|
}
|
|
606
1000
|
function serializeToolRefs(tools) {
|
|
607
1001
|
return tools.map((t) => {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
1002
|
+
switch (t.kind) {
|
|
1003
|
+
case "mantyx":
|
|
1004
|
+
return { kind: "mantyx", id: t.id };
|
|
1005
|
+
case "mantyx_plugin":
|
|
1006
|
+
return { kind: "mantyx_plugin", name: t.name };
|
|
1007
|
+
case "local":
|
|
1008
|
+
return {
|
|
1009
|
+
kind: "local",
|
|
1010
|
+
name: t.name,
|
|
1011
|
+
description: t.description,
|
|
1012
|
+
parameters: toToolParametersWire(t.parameters)
|
|
1013
|
+
};
|
|
1014
|
+
case "a2a":
|
|
1015
|
+
return {
|
|
1016
|
+
kind: "a2a",
|
|
1017
|
+
name: t.name,
|
|
1018
|
+
...t.description !== void 0 ? { description: t.description } : {},
|
|
1019
|
+
agentCardUrl: t.agentCardUrl,
|
|
1020
|
+
...t.headers ? { headers: { ...t.headers } } : {},
|
|
1021
|
+
...t.contextId ? { contextId: t.contextId } : {}
|
|
1022
|
+
};
|
|
1023
|
+
case "a2a_local": {
|
|
1024
|
+
const card = t._resolvedCard;
|
|
1025
|
+
if (!card) {
|
|
1026
|
+
throw new MantyxError(
|
|
1027
|
+
`defineLocalA2A(${JSON.stringify(t.name)}): agent card has not been resolved yet (was \`runAgent\` / \`createSession\` skipped?)`
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
kind: "a2a_local",
|
|
1032
|
+
name: t.name,
|
|
1033
|
+
// The wire ships the resolved A2A Agent Card. Shallow-clone so
|
|
1034
|
+
// consumers can mutate the input later without affecting the
|
|
1035
|
+
// wire payload.
|
|
1036
|
+
agentCard: { ...card }
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
case "mcp":
|
|
1040
|
+
return {
|
|
1041
|
+
kind: "mcp",
|
|
1042
|
+
name: t.name,
|
|
1043
|
+
url: t.url,
|
|
1044
|
+
...t.headers ? { headers: { ...t.headers } } : {},
|
|
1045
|
+
...t.toolFilter ? { toolFilter: [...t.toolFilter] } : {}
|
|
1046
|
+
};
|
|
1047
|
+
case "mcp_local": {
|
|
1048
|
+
const resolved = t._resolved;
|
|
1049
|
+
if (!resolved) {
|
|
1050
|
+
throw new MantyxError(
|
|
1051
|
+
`defineLocalMcp(${JSON.stringify(t.name)}): MCP server has not been initialised yet`
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
const tools2 = resolved.tools.map((tool) => {
|
|
1055
|
+
const wire = {
|
|
1056
|
+
name: prefixedMcpToolName(t.name, tool.name),
|
|
1057
|
+
inputSchema: tool.inputSchema
|
|
1058
|
+
};
|
|
1059
|
+
if (typeof tool.description === "string") wire.description = tool.description;
|
|
1060
|
+
if (tool.annotations) wire.annotations = tool.annotations;
|
|
1061
|
+
return wire;
|
|
1062
|
+
});
|
|
1063
|
+
return {
|
|
1064
|
+
kind: "mcp_local",
|
|
1065
|
+
name: t.name,
|
|
1066
|
+
serverInfo: { ...resolved.serverInfo },
|
|
1067
|
+
tools: tools2
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
616
1071
|
});
|
|
617
1072
|
}
|
|
618
1073
|
function collectLocalHandlers(tools) {
|
|
619
|
-
const
|
|
1074
|
+
const localTools = /* @__PURE__ */ new Map();
|
|
1075
|
+
const a2aTools = /* @__PURE__ */ new Map();
|
|
1076
|
+
const mcpServers = /* @__PURE__ */ new Map();
|
|
620
1077
|
for (const t of tools) {
|
|
621
|
-
if (isLocalTool(t))
|
|
1078
|
+
if (isLocalTool(t)) {
|
|
1079
|
+
localTools.set(t.name, t);
|
|
1080
|
+
} else if (isLocalA2ATool(t)) {
|
|
1081
|
+
a2aTools.set(t.name, t);
|
|
1082
|
+
} else if (isLocalMcpServer(t)) {
|
|
1083
|
+
mcpServers.set(t.name, t);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return { localTools, a2aTools, mcpServers };
|
|
1087
|
+
}
|
|
1088
|
+
function describeHandlerName(ev) {
|
|
1089
|
+
if (ev.kind === "mcp_local" && ev.mcpServer && ev.mcpToolName) {
|
|
1090
|
+
return `${ev.mcpServer}/${ev.mcpToolName}`;
|
|
1091
|
+
}
|
|
1092
|
+
return ev.name;
|
|
1093
|
+
}
|
|
1094
|
+
function normalizeReasoningLevel(level) {
|
|
1095
|
+
if (typeof level === "number") {
|
|
1096
|
+
if (!Number.isFinite(level) || level < 0 || level > 100) {
|
|
1097
|
+
throw new MantyxError(
|
|
1098
|
+
`reasoningLevel must be a string anchor or an integer in 0..100, got ${level}`
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
return Math.trunc(level);
|
|
1102
|
+
}
|
|
1103
|
+
if (level === "off" || level === "low" || level === "medium" || level === "high") {
|
|
1104
|
+
return level;
|
|
622
1105
|
}
|
|
623
|
-
|
|
1106
|
+
throw new MantyxError(
|
|
1107
|
+
`reasoningLevel must be one of "off" | "low" | "medium" | "high" or a number 0..100, got ${JSON.stringify(level)}`
|
|
1108
|
+
);
|
|
624
1109
|
}
|
|
625
1110
|
function sleep(ms) {
|
|
626
1111
|
return new Promise((r) => setTimeout(r, ms));
|
|
627
1112
|
}
|
|
628
1113
|
|
|
629
1114
|
// src/version.ts
|
|
630
|
-
var SDK_VERSION = "0.
|
|
1115
|
+
var SDK_VERSION = "0.3.0";
|
|
631
1116
|
// Annotate the CommonJS export names for ESM import in node:
|
|
632
1117
|
0 && (module.exports = {
|
|
633
1118
|
AgentSession,
|
|
@@ -639,8 +1124,14 @@ var SDK_VERSION = "0.1.1";
|
|
|
639
1124
|
MantyxRunError,
|
|
640
1125
|
MantyxToolError,
|
|
641
1126
|
SDK_VERSION,
|
|
1127
|
+
defineLocalA2A,
|
|
1128
|
+
defineLocalMcp,
|
|
642
1129
|
defineLocalTool,
|
|
1130
|
+
isLocalA2ATool,
|
|
1131
|
+
isLocalMcpServer,
|
|
643
1132
|
isLocalTool,
|
|
1133
|
+
mantyxA2A,
|
|
1134
|
+
mantyxMcp,
|
|
644
1135
|
mantyxPluginTool,
|
|
645
1136
|
mantyxTool,
|
|
646
1137
|
readSseStream,
|