@contractspec/lib.ai-agent 5.0.4 → 6.0.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/README.md +41 -0
- package/dist/agent/agent-factory.d.ts +13 -0
- package/dist/agent/agent-factory.js +290 -63
- package/dist/agent/contract-spec-agent.d.ts +9 -0
- package/dist/agent/contract-spec-agent.js +287 -63
- package/dist/agent/index.js +353 -129
- package/dist/agent/json-runner.js +290 -66
- package/dist/agent/unified-agent.js +350 -126
- package/dist/exporters/claude-agent-exporter.js +12 -1
- package/dist/exporters/index.js +12 -1
- package/dist/exporters/opencode-exporter.js +11 -0
- package/dist/index.js +11 -0
- package/dist/interop/index.js +24 -2
- package/dist/interop/spec-consumer.js +11 -0
- package/dist/interop/tool-consumer.js +13 -2
- package/dist/node/agent/agent-factory.js +290 -63
- package/dist/node/agent/contract-spec-agent.js +287 -63
- package/dist/node/agent/index.js +353 -129
- package/dist/node/agent/json-runner.js +290 -66
- package/dist/node/agent/unified-agent.js +350 -126
- package/dist/node/exporters/claude-agent-exporter.js +12 -1
- package/dist/node/exporters/index.js +12 -1
- package/dist/node/exporters/opencode-exporter.js +11 -0
- package/dist/node/index.js +11 -0
- package/dist/node/interop/index.js +24 -2
- package/dist/node/interop/spec-consumer.js +11 -0
- package/dist/node/interop/tool-consumer.js +13 -2
- package/dist/node/providers/claude-agent-sdk/adapter.js +11 -0
- package/dist/node/providers/claude-agent-sdk/index.js +11 -0
- package/dist/node/providers/index.js +11 -0
- package/dist/node/providers/opencode-sdk/adapter.js +11 -0
- package/dist/node/providers/opencode-sdk/index.js +11 -0
- package/dist/node/spec/index.js +11 -0
- package/dist/node/spec/spec.js +11 -0
- package/dist/node/tools/agent-memory-store.js +24 -0
- package/dist/node/tools/in-memory-agent-memory-store.js +236 -0
- package/dist/node/tools/index.js +463 -42
- package/dist/node/tools/memory-tools.js +45 -0
- package/dist/node/tools/operation-tool-handler.js +35 -0
- package/dist/node/tools/subagent-tool.js +95 -0
- package/dist/node/tools/tool-adapter.js +192 -25
- package/dist/providers/claude-agent-sdk/adapter.js +11 -0
- package/dist/providers/claude-agent-sdk/index.js +11 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/opencode-sdk/adapter.js +11 -0
- package/dist/providers/opencode-sdk/index.js +11 -0
- package/dist/spec/index.js +11 -0
- package/dist/spec/spec.d.ts +69 -1
- package/dist/spec/spec.js +11 -0
- package/dist/tools/agent-memory-store.d.ts +26 -0
- package/dist/tools/agent-memory-store.js +24 -0
- package/dist/tools/agent-memory-store.test.d.ts +1 -0
- package/dist/tools/in-memory-agent-memory-store.d.ts +18 -0
- package/dist/tools/in-memory-agent-memory-store.js +236 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +463 -42
- package/dist/tools/mcp-client.browser.d.ts +6 -6
- package/dist/tools/memory-tools.d.ts +29 -0
- package/dist/tools/memory-tools.js +45 -0
- package/dist/tools/operation-tool-handler.d.ts +24 -0
- package/dist/tools/operation-tool-handler.js +35 -0
- package/dist/tools/subagent-tool.d.ts +66 -0
- package/dist/tools/subagent-tool.js +95 -0
- package/dist/tools/tool-adapter.d.ts +26 -10
- package/dist/tools/tool-adapter.js +192 -25
- package/dist/types.d.ts +9 -3
- package/package.json +67 -7
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
set: (newValue) => all[name] = () => newValue
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
13
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
14
|
+
|
|
15
|
+
// src/tools/operation-tool-handler.ts
|
|
16
|
+
function toolCtxToHandlerCtx(ctx) {
|
|
17
|
+
return {
|
|
18
|
+
traceId: ctx.metadata?.traceId,
|
|
19
|
+
organizationId: ctx.tenantId ?? null,
|
|
20
|
+
userId: ctx.actorId ?? null,
|
|
21
|
+
actor: ctx.actorId ? "user" : "anonymous",
|
|
22
|
+
channel: "agent",
|
|
23
|
+
roles: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function createOperationToolHandler(registry, operationRef) {
|
|
27
|
+
return async (input, context) => {
|
|
28
|
+
const handlerCtx = toolCtxToHandlerCtx(context);
|
|
29
|
+
const result = await registry.execute(operationRef.key, operationRef.version, input ?? {}, handlerCtx);
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
createOperationToolHandler
|
|
35
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
set: (newValue) => all[name] = () => newValue
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
13
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
14
|
+
|
|
15
|
+
// src/tools/subagent-tool.ts
|
|
16
|
+
import { readUIMessageStream, tool } from "ai";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
function toReadableStream(iterable) {
|
|
19
|
+
if (iterable instanceof ReadableStream) {
|
|
20
|
+
return iterable;
|
|
21
|
+
}
|
|
22
|
+
return new ReadableStream({
|
|
23
|
+
async start(controller) {
|
|
24
|
+
try {
|
|
25
|
+
for await (const chunk of iterable) {
|
|
26
|
+
controller.enqueue(chunk);
|
|
27
|
+
}
|
|
28
|
+
} finally {
|
|
29
|
+
controller.close();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function createSubagentTool(options) {
|
|
35
|
+
const {
|
|
36
|
+
subagent,
|
|
37
|
+
description = "Research a topic or question in depth.",
|
|
38
|
+
taskParam = "task",
|
|
39
|
+
toModelSummary = true,
|
|
40
|
+
passConversationHistory = false
|
|
41
|
+
} = options;
|
|
42
|
+
const inputSchema = z.object({
|
|
43
|
+
[taskParam]: z.string().describe("The research task to complete")
|
|
44
|
+
});
|
|
45
|
+
const execute = async function* (input, options2) {
|
|
46
|
+
const task = String(input[taskParam] ?? input.task ?? "");
|
|
47
|
+
const { abortSignal, messages } = options2 ?? {};
|
|
48
|
+
if (passConversationHistory && messages && messages.length > 0 && typeof subagent.generate === "function") {
|
|
49
|
+
const result2 = await subagent.generate({
|
|
50
|
+
messages: [...messages, { role: "user", content: task }],
|
|
51
|
+
abortSignal
|
|
52
|
+
});
|
|
53
|
+
yield { parts: [{ type: "text", text: result2.text }] };
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const result = await subagent.stream({
|
|
57
|
+
prompt: task,
|
|
58
|
+
abortSignal
|
|
59
|
+
});
|
|
60
|
+
const uiStream = result.toUIMessageStream();
|
|
61
|
+
const stream = toReadableStream(uiStream);
|
|
62
|
+
for await (const message of readUIMessageStream({
|
|
63
|
+
stream
|
|
64
|
+
})) {
|
|
65
|
+
yield message;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const toolOptions = {
|
|
69
|
+
description,
|
|
70
|
+
inputSchema,
|
|
71
|
+
execute,
|
|
72
|
+
...toModelSummary && {
|
|
73
|
+
toModelOutput: ({
|
|
74
|
+
output
|
|
75
|
+
}) => {
|
|
76
|
+
const parts = output?.parts;
|
|
77
|
+
if (!Array.isArray(parts)) {
|
|
78
|
+
return { type: "text", value: "Task completed." };
|
|
79
|
+
}
|
|
80
|
+
const lastTextPart = [...parts].reverse().find((p) => p?.type === "text");
|
|
81
|
+
return {
|
|
82
|
+
type: "text",
|
|
83
|
+
value: lastTextPart?.text ?? "Task completed."
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return tool(toolOptions);
|
|
89
|
+
}
|
|
90
|
+
var init_subagent_tool = () => {};
|
|
91
|
+
init_subagent_tool();
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
createSubagentTool
|
|
95
|
+
};
|
|
@@ -2260,15 +2260,124 @@ function jsonSchemaToZodSafe(schema) {
|
|
|
2260
2260
|
}
|
|
2261
2261
|
var init_json_schema_to_zod = () => {};
|
|
2262
2262
|
|
|
2263
|
+
// src/tools/operation-tool-handler.ts
|
|
2264
|
+
function toolCtxToHandlerCtx(ctx) {
|
|
2265
|
+
return {
|
|
2266
|
+
traceId: ctx.metadata?.traceId,
|
|
2267
|
+
organizationId: ctx.tenantId ?? null,
|
|
2268
|
+
userId: ctx.actorId ?? null,
|
|
2269
|
+
actor: ctx.actorId ? "user" : "anonymous",
|
|
2270
|
+
channel: "agent",
|
|
2271
|
+
roles: []
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
function createOperationToolHandler(registry, operationRef) {
|
|
2275
|
+
return async (input, context) => {
|
|
2276
|
+
const handlerCtx = toolCtxToHandlerCtx(context);
|
|
2277
|
+
const result = await registry.execute(operationRef.key, operationRef.version, input ?? {}, handlerCtx);
|
|
2278
|
+
return result;
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
// src/tools/subagent-tool.ts
|
|
2283
|
+
import { readUIMessageStream, tool } from "ai";
|
|
2284
|
+
import { z as z2 } from "zod";
|
|
2285
|
+
function toReadableStream(iterable) {
|
|
2286
|
+
if (iterable instanceof ReadableStream) {
|
|
2287
|
+
return iterable;
|
|
2288
|
+
}
|
|
2289
|
+
return new ReadableStream({
|
|
2290
|
+
async start(controller) {
|
|
2291
|
+
try {
|
|
2292
|
+
for await (const chunk of iterable) {
|
|
2293
|
+
controller.enqueue(chunk);
|
|
2294
|
+
}
|
|
2295
|
+
} finally {
|
|
2296
|
+
controller.close();
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
function createSubagentTool(options) {
|
|
2302
|
+
const {
|
|
2303
|
+
subagent,
|
|
2304
|
+
description = "Research a topic or question in depth.",
|
|
2305
|
+
taskParam = "task",
|
|
2306
|
+
toModelSummary = true,
|
|
2307
|
+
passConversationHistory = false
|
|
2308
|
+
} = options;
|
|
2309
|
+
const inputSchema = z2.object({
|
|
2310
|
+
[taskParam]: z2.string().describe("The research task to complete")
|
|
2311
|
+
});
|
|
2312
|
+
const execute = async function* (input, options2) {
|
|
2313
|
+
const task = String(input[taskParam] ?? input.task ?? "");
|
|
2314
|
+
const { abortSignal, messages } = options2 ?? {};
|
|
2315
|
+
if (passConversationHistory && messages && messages.length > 0 && typeof subagent.generate === "function") {
|
|
2316
|
+
const result2 = await subagent.generate({
|
|
2317
|
+
messages: [...messages, { role: "user", content: task }],
|
|
2318
|
+
abortSignal
|
|
2319
|
+
});
|
|
2320
|
+
yield { parts: [{ type: "text", text: result2.text }] };
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
const result = await subagent.stream({
|
|
2324
|
+
prompt: task,
|
|
2325
|
+
abortSignal
|
|
2326
|
+
});
|
|
2327
|
+
const uiStream = result.toUIMessageStream();
|
|
2328
|
+
const stream = toReadableStream(uiStream);
|
|
2329
|
+
for await (const message of readUIMessageStream({
|
|
2330
|
+
stream
|
|
2331
|
+
})) {
|
|
2332
|
+
yield message;
|
|
2333
|
+
}
|
|
2334
|
+
};
|
|
2335
|
+
const toolOptions = {
|
|
2336
|
+
description,
|
|
2337
|
+
inputSchema,
|
|
2338
|
+
execute,
|
|
2339
|
+
...toModelSummary && {
|
|
2340
|
+
toModelOutput: ({
|
|
2341
|
+
output
|
|
2342
|
+
}) => {
|
|
2343
|
+
const parts = output?.parts;
|
|
2344
|
+
if (!Array.isArray(parts)) {
|
|
2345
|
+
return { type: "text", value: "Task completed." };
|
|
2346
|
+
}
|
|
2347
|
+
const lastTextPart = [...parts].reverse().find((p) => p?.type === "text");
|
|
2348
|
+
return {
|
|
2349
|
+
type: "text",
|
|
2350
|
+
value: lastTextPart?.text ?? "Task completed."
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
return tool(toolOptions);
|
|
2356
|
+
}
|
|
2357
|
+
var init_subagent_tool = () => {};
|
|
2358
|
+
|
|
2263
2359
|
// src/tools/tool-adapter.ts
|
|
2264
|
-
import { tool } from "ai";
|
|
2265
|
-
function
|
|
2360
|
+
import { tool as tool2 } from "ai";
|
|
2361
|
+
function isAsyncGenerator(value) {
|
|
2362
|
+
return typeof value === "object" && value !== null && typeof value.next === "function" && typeof value[Symbol.asyncIterator] === "function";
|
|
2363
|
+
}
|
|
2364
|
+
function specToolToAISDKTool(specTool, handler, context = {}, effectiveInputSchema, operationSpec) {
|
|
2266
2365
|
let lastInvocationAt;
|
|
2267
|
-
|
|
2366
|
+
const inputSchema = effectiveInputSchema ?? jsonSchemaToZodSafe(specTool.schema);
|
|
2367
|
+
const buildContext = (signal) => ({
|
|
2368
|
+
agentId: context.agentId ?? "unknown",
|
|
2369
|
+
sessionId: context.sessionId ?? "unknown",
|
|
2370
|
+
tenantId: context.tenantId,
|
|
2371
|
+
actorId: context.actorId,
|
|
2372
|
+
locale: context.locale,
|
|
2373
|
+
metadata: context.metadata,
|
|
2374
|
+
signal
|
|
2375
|
+
});
|
|
2376
|
+
return tool2({
|
|
2268
2377
|
description: specTool.description ?? specTool.name,
|
|
2269
|
-
inputSchema
|
|
2378
|
+
inputSchema,
|
|
2270
2379
|
needsApproval: specTool.requiresApproval ?? !specTool.automationSafe,
|
|
2271
|
-
execute: async (input)
|
|
2380
|
+
execute: async function* (input, options) {
|
|
2272
2381
|
const now = Date.now();
|
|
2273
2382
|
const cooldownMs = normalizeDuration(specTool.cooldownMs);
|
|
2274
2383
|
if (cooldownMs && lastInvocationAt !== undefined) {
|
|
@@ -2279,19 +2388,20 @@ function specToolToAISDKTool(specTool, handler, context = {}) {
|
|
|
2279
2388
|
}
|
|
2280
2389
|
}
|
|
2281
2390
|
const timeoutMs = normalizeDuration(specTool.timeoutMs);
|
|
2282
|
-
const
|
|
2391
|
+
const signal = options?.abortSignal ?? context.signal;
|
|
2392
|
+
const { signal: timeoutSignal, dispose } = createTimeoutSignal(signal, timeoutMs);
|
|
2283
2393
|
try {
|
|
2284
|
-
const execution = handler(input,
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2394
|
+
const execution = handler(input, buildContext(timeoutSignal));
|
|
2395
|
+
if (isAsyncGenerator(execution)) {
|
|
2396
|
+
for await (const raw of execution) {
|
|
2397
|
+
const wrapped = wrapToolOutputForRendering(specTool, raw, operationSpec);
|
|
2398
|
+
yield typeof wrapped === "string" ? wrapped : wrapped;
|
|
2399
|
+
}
|
|
2400
|
+
} else {
|
|
2401
|
+
const raw = timeoutMs ? await withTimeout(Promise.resolve(execution), timeoutMs, specTool.name) : await Promise.resolve(execution);
|
|
2402
|
+
const wrapped = wrapToolOutputForRendering(specTool, raw, operationSpec);
|
|
2403
|
+
yield typeof wrapped === "string" ? wrapped : wrapped;
|
|
2404
|
+
}
|
|
2295
2405
|
} finally {
|
|
2296
2406
|
dispose();
|
|
2297
2407
|
lastInvocationAt = Date.now();
|
|
@@ -2299,27 +2409,83 @@ function specToolToAISDKTool(specTool, handler, context = {}) {
|
|
|
2299
2409
|
}
|
|
2300
2410
|
});
|
|
2301
2411
|
}
|
|
2302
|
-
function specToolsToAISDKTools(specTools, handlers, context = {}) {
|
|
2412
|
+
function specToolsToAISDKTools(specTools, handlers, context = {}, options) {
|
|
2303
2413
|
const tools = {};
|
|
2304
2414
|
for (const specTool of specTools) {
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
}
|
|
2415
|
+
if (specTool.subagentRef && options?.subagentRegistry) {
|
|
2416
|
+
const subagent = options.subagentRegistry.get(specTool.subagentRef.agentId);
|
|
2417
|
+
if (!subagent) {
|
|
2418
|
+
throw new Error(`Subagent not found: ${specTool.subagentRef.agentId}. Register it in subagentRegistry.`);
|
|
2419
|
+
}
|
|
2420
|
+
if (specTool.requiresApproval === true || specTool.automationSafe === false) {
|
|
2421
|
+
console.warn(`[ContractSpec] Subagent tool "${specTool.name}" cannot use needsApproval. ` + `requiresApproval and automationSafe are ignored for subagent tools (AI SDK limitation). ` + `See https://ai-sdk.dev/docs/agents/subagents#no-tool-approvals-in-subagents`);
|
|
2422
|
+
}
|
|
2423
|
+
tools[specTool.name] = createSubagentTool({
|
|
2424
|
+
subagent,
|
|
2425
|
+
description: specTool.description ?? specTool.name,
|
|
2426
|
+
toModelSummary: specTool.subagentRef.toModelSummary ?? true,
|
|
2427
|
+
passConversationHistory: specTool.subagentRef.passConversationHistory
|
|
2428
|
+
});
|
|
2429
|
+
continue;
|
|
2310
2430
|
}
|
|
2311
|
-
|
|
2431
|
+
let handler;
|
|
2432
|
+
let effectiveInputSchema;
|
|
2433
|
+
let op;
|
|
2434
|
+
if (specTool.operationRef && options?.operationRegistry) {
|
|
2435
|
+
op = options.operationRegistry.get(specTool.operationRef.key, specTool.operationRef.version);
|
|
2436
|
+
if (!op) {
|
|
2437
|
+
throw new Error(`Operation not found: ${specTool.operationRef.key}${specTool.operationRef.version ? `.v${specTool.operationRef.version}` : ""}`);
|
|
2438
|
+
}
|
|
2439
|
+
handler = createOperationToolHandler(options.operationRegistry, specTool.operationRef);
|
|
2440
|
+
effectiveInputSchema = op.io.input?.getZod?.();
|
|
2441
|
+
} else {
|
|
2442
|
+
const manualHandler = handlers.get(specTool.name);
|
|
2443
|
+
if (!manualHandler) {
|
|
2444
|
+
if (specTool.subagentRef) {
|
|
2445
|
+
throw new Error(`Subagent tool "${specTool.name}" requires subagentRegistry. Pass subagentRegistry in ContractSpecAgentConfig.`);
|
|
2446
|
+
}
|
|
2447
|
+
throw new Error(createAgentI18n(context.locale).t("error.missingToolHandler", {
|
|
2448
|
+
name: specTool.name
|
|
2449
|
+
}));
|
|
2450
|
+
}
|
|
2451
|
+
handler = manualHandler;
|
|
2452
|
+
}
|
|
2453
|
+
tools[specTool.name] = specToolToAISDKTool(specTool, handler, context, effectiveInputSchema, op);
|
|
2312
2454
|
}
|
|
2313
2455
|
return tools;
|
|
2314
2456
|
}
|
|
2315
2457
|
function createToolHandler(handler) {
|
|
2316
|
-
return
|
|
2458
|
+
return (input, context) => {
|
|
2317
2459
|
return handler(input, context);
|
|
2318
2460
|
};
|
|
2319
2461
|
}
|
|
2320
2462
|
function buildToolHandlers(handlersObj) {
|
|
2321
2463
|
return new Map(Object.entries(handlersObj));
|
|
2322
2464
|
}
|
|
2465
|
+
function wrapToolOutputForRendering(specTool, result, operationSpec) {
|
|
2466
|
+
const presentation = specTool.outputPresentation ?? operationSpec?.outputPresentation;
|
|
2467
|
+
const form = specTool.outputForm ?? operationSpec?.outputForm;
|
|
2468
|
+
const dataView = specTool.outputDataView ?? operationSpec?.outputDataView;
|
|
2469
|
+
if (presentation) {
|
|
2470
|
+
return {
|
|
2471
|
+
presentationKey: presentation.key,
|
|
2472
|
+
data: result
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
if (form) {
|
|
2476
|
+
return {
|
|
2477
|
+
formKey: form.key,
|
|
2478
|
+
defaultValues: typeof result === "object" && result !== null ? result : {}
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
if (dataView) {
|
|
2482
|
+
return {
|
|
2483
|
+
dataViewKey: dataView.key,
|
|
2484
|
+
items: Array.isArray(result) ? result : result != null ? [result] : []
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
return result;
|
|
2488
|
+
}
|
|
2323
2489
|
function normalizeDuration(value) {
|
|
2324
2490
|
if (value === undefined) {
|
|
2325
2491
|
return;
|
|
@@ -2381,6 +2547,7 @@ function createToolExecutionError(message, code, retryAfterMs) {
|
|
|
2381
2547
|
var init_tool_adapter = __esm(() => {
|
|
2382
2548
|
init_json_schema_to_zod();
|
|
2383
2549
|
init_i18n();
|
|
2550
|
+
init_subagent_tool();
|
|
2384
2551
|
});
|
|
2385
2552
|
init_tool_adapter();
|
|
2386
2553
|
|
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
package/dist/providers/index.js
CHANGED
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
package/dist/spec/index.js
CHANGED
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
package/dist/spec/spec.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OwnerShipMeta } from '@contractspec/lib.contracts-spec/ownership';
|
|
2
|
+
import type { DataViewRef, FormRef, PresentationRef } from '@contractspec/lib.contracts-spec/features';
|
|
2
3
|
import type { KnowledgeCategory } from '@contractspec/lib.contracts-spec/knowledge/spec';
|
|
3
4
|
import type { PolicyRef } from '@contractspec/lib.contracts-spec/policy/spec';
|
|
4
5
|
/**
|
|
@@ -30,15 +31,51 @@ export interface AgentRuntimeConfig {
|
|
|
30
31
|
capabilities?: AgentRuntimeCapabilities;
|
|
31
32
|
ports?: AgentRuntimePorts;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Reference to a ContractSpec operation that backs an agent tool.
|
|
36
|
+
* When set, the tool is a projection of the operation (one contract → REST, GraphQL, MCP, agent).
|
|
37
|
+
*/
|
|
38
|
+
export interface OperationRef {
|
|
39
|
+
/** Operation key (e.g., "knowledge.search") */
|
|
40
|
+
key: string;
|
|
41
|
+
/** Optional specific version; defaults to latest when omitted */
|
|
42
|
+
version?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reference to a subagent that backs an agent tool.
|
|
46
|
+
* When set, the tool delegates to the subagent; mutually exclusive with operationRef and manual handler.
|
|
47
|
+
*/
|
|
48
|
+
export interface SubagentRef {
|
|
49
|
+
/** Subagent identifier (resolved from subagent registry) */
|
|
50
|
+
agentId: string;
|
|
51
|
+
/** Whether to extract summary for toModelOutput (default: true) */
|
|
52
|
+
toModelSummary?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Pass full conversation history to subagent (opt-in).
|
|
55
|
+
* Defeats context isolation; use sparingly. Requires subagent to support generate({ messages }).
|
|
56
|
+
* Streaming is disabled when history is passed.
|
|
57
|
+
*/
|
|
58
|
+
passConversationHistory?: boolean;
|
|
59
|
+
}
|
|
33
60
|
/**
|
|
34
61
|
* Configuration for a tool that an agent can use.
|
|
35
62
|
*/
|
|
36
63
|
export interface AgentToolConfig {
|
|
37
64
|
/** Tool name (unique within the agent) */
|
|
38
65
|
name: string;
|
|
66
|
+
/**
|
|
67
|
+
* Reference to a ContractSpec operation. When set, the tool is backed by the operation:
|
|
68
|
+
* schema and handler are derived from the operation; no manual handler needed.
|
|
69
|
+
*/
|
|
70
|
+
operationRef?: OperationRef;
|
|
71
|
+
/**
|
|
72
|
+
* Reference to a subagent. When set, the tool delegates to the subagent.
|
|
73
|
+
* Mutually exclusive with operationRef; requires subagentRegistry in agent config.
|
|
74
|
+
*/
|
|
75
|
+
subagentRef?: SubagentRef;
|
|
39
76
|
/** Human-readable description for the LLM */
|
|
40
77
|
description?: string;
|
|
41
|
-
/** JSON Schema fragment for tool parameters */
|
|
78
|
+
/** JSON Schema fragment for tool parameters (fallback when no operationRef) */
|
|
42
79
|
schema?: Record<string, unknown>;
|
|
43
80
|
/** Optional cooldown in milliseconds between invocations */
|
|
44
81
|
cooldownMs?: number;
|
|
@@ -50,6 +87,21 @@ export interface AgentToolConfig {
|
|
|
50
87
|
requiresApproval?: boolean;
|
|
51
88
|
/** Optional policy guard that must evaluate to allow the tool call */
|
|
52
89
|
policy?: PolicyRef;
|
|
90
|
+
/**
|
|
91
|
+
* When set, wrap raw output as { presentationKey, data } for ToolResultRenderer.
|
|
92
|
+
* At most one of outputPresentation, outputForm, outputDataView per tool.
|
|
93
|
+
*/
|
|
94
|
+
outputPresentation?: PresentationRef;
|
|
95
|
+
/**
|
|
96
|
+
* When set, wrap raw output as { formKey, defaultValues } for ToolResultRenderer.
|
|
97
|
+
* At most one of outputPresentation, outputForm, outputDataView per tool.
|
|
98
|
+
*/
|
|
99
|
+
outputForm?: FormRef;
|
|
100
|
+
/**
|
|
101
|
+
* When set, wrap raw output as { dataViewKey, items } for ToolResultRenderer.
|
|
102
|
+
* At most one of outputPresentation, outputForm, outputDataView per tool.
|
|
103
|
+
*/
|
|
104
|
+
outputDataView?: DataViewRef;
|
|
53
105
|
}
|
|
54
106
|
/**
|
|
55
107
|
* Reference to a knowledge space that the agent can access.
|
|
@@ -79,6 +131,20 @@ export interface AgentMemoryConfig {
|
|
|
79
131
|
/** Whether to persist to long-term storage */
|
|
80
132
|
persistLongTerm?: boolean;
|
|
81
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Memory tools config — model-accessible CRUD (Anthropic memory, custom).
|
|
136
|
+
* Distinct from AgentMemoryConfig (session summarization).
|
|
137
|
+
*
|
|
138
|
+
* @see https://ai-sdk.dev/docs/agents/memory
|
|
139
|
+
*/
|
|
140
|
+
export interface AgentMemoryToolsConfig {
|
|
141
|
+
/** Provider: anthropic uses memory_20250818; custom uses operationRef. */
|
|
142
|
+
provider: 'anthropic' | 'custom';
|
|
143
|
+
/** Storage adapter key when using knowledge-backed storage (e.g. ephemeral space) */
|
|
144
|
+
storageAdapter?: string;
|
|
145
|
+
/** Ephemeral KnowledgeSpaceSpec key when using knowledge-backed storage */
|
|
146
|
+
spaceKey?: string;
|
|
147
|
+
}
|
|
82
148
|
/**
|
|
83
149
|
* Confidence policy for agent responses.
|
|
84
150
|
*/
|
|
@@ -127,6 +193,8 @@ export interface AgentSpec {
|
|
|
127
193
|
tools: AgentToolConfig[];
|
|
128
194
|
/** Memory/session configuration */
|
|
129
195
|
memory?: AgentMemoryConfig;
|
|
196
|
+
/** Memory tools (model-accessible CRUD) — Anthropic or custom operation-backed */
|
|
197
|
+
memoryTools?: AgentMemoryToolsConfig;
|
|
130
198
|
/** Knowledge spaces the agent can access */
|
|
131
199
|
knowledge?: AgentKnowledgeRef[];
|
|
132
200
|
/** Policy configuration */
|
package/dist/spec/spec.js
CHANGED
|
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
|
|
|
2156
2156
|
}));
|
|
2157
2157
|
}
|
|
2158
2158
|
toolNames.add(tool.name);
|
|
2159
|
+
if (tool.subagentRef && tool.operationRef) {
|
|
2160
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
|
|
2161
|
+
}
|
|
2162
|
+
const outputRefCount = [
|
|
2163
|
+
tool.outputPresentation,
|
|
2164
|
+
tool.outputForm,
|
|
2165
|
+
tool.outputDataView
|
|
2166
|
+
].filter(Boolean).length;
|
|
2167
|
+
if (outputRefCount > 1) {
|
|
2168
|
+
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2169
|
+
}
|
|
2159
2170
|
}
|
|
2160
2171
|
return Object.freeze(spec);
|
|
2161
2172
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage interface for agent memory tools (model-accessible CRUD).
|
|
3
|
+
*
|
|
4
|
+
* Used by Anthropic memory tool and custom memory tools. Distinct from
|
|
5
|
+
* AgentMemoryManager (session summarization). Storage backend can be
|
|
6
|
+
* in-memory, filesystem, or ephemeral knowledge space.
|
|
7
|
+
*
|
|
8
|
+
* @see https://ai-sdk.dev/docs/agents/memory
|
|
9
|
+
* @see https://console.anthropic.com/docs/en/agents-and-tools/tool-use/memory-tool
|
|
10
|
+
*/
|
|
11
|
+
export interface AgentMemoryStore {
|
|
12
|
+
/** View directory contents or file contents. Path must be under /memories. */
|
|
13
|
+
view(path: string, viewRange?: [number, number]): Promise<string>;
|
|
14
|
+
/** Create a new file. Path must be under /memories. */
|
|
15
|
+
create(path: string, fileText: string): Promise<string>;
|
|
16
|
+
/** Replace old_str with new_str in file. */
|
|
17
|
+
strReplace(path: string, oldStr: string, newStr: string): Promise<string>;
|
|
18
|
+
/** Insert text at line. insertLine is 0-indexed (0 = before first line). */
|
|
19
|
+
insert(path: string, insertLine: number, insertText: string): Promise<string>;
|
|
20
|
+
/** Delete file or directory recursively. */
|
|
21
|
+
delete(path: string): Promise<string>;
|
|
22
|
+
/** Rename/move file or directory. */
|
|
23
|
+
rename(oldPath: string, newPath: string): Promise<string>;
|
|
24
|
+
}
|
|
25
|
+
/** Validates path is under /memories and prevents traversal. */
|
|
26
|
+
export declare function validateMemoryPath(path: string): void;
|