@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,24 @@
|
|
|
1
|
+
// @bun
|
|
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 = import.meta.require;
|
|
14
|
+
|
|
15
|
+
// src/tools/agent-memory-store.ts
|
|
16
|
+
function validateMemoryPath(path) {
|
|
17
|
+
const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
18
|
+
if (!normalized.startsWith("/memories") || normalized.includes("..") || normalized === "/memories/.." || normalized.startsWith("/memories/../")) {
|
|
19
|
+
throw new Error(`Invalid memory path: ${path}. Path must be under /memories and cannot contain traversal sequences.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
validateMemoryPath
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type AgentMemoryStore } from './agent-memory-store';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory implementation of AgentMemoryStore for development and testing.
|
|
4
|
+
* Paths are stored as keys; directories are implicit (paths with /).
|
|
5
|
+
*/
|
|
6
|
+
export declare class InMemoryAgentMemoryStore implements AgentMemoryStore {
|
|
7
|
+
private readonly store;
|
|
8
|
+
view(path: string, viewRange?: [number, number]): Promise<string>;
|
|
9
|
+
create(path: string, fileText: string): Promise<string>;
|
|
10
|
+
strReplace(path: string, oldStr: string, newStr: string): Promise<string>;
|
|
11
|
+
insert(path: string, insertLine: number, insertText: string): Promise<string>;
|
|
12
|
+
delete(path: string): Promise<string>;
|
|
13
|
+
rename(oldPath: string, newPath: string): Promise<string>;
|
|
14
|
+
private isDirectory;
|
|
15
|
+
private hasAnyChild;
|
|
16
|
+
private ensureParentDir;
|
|
17
|
+
private listDirectory;
|
|
18
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// @bun
|
|
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 = import.meta.require;
|
|
14
|
+
|
|
15
|
+
// src/tools/agent-memory-store.ts
|
|
16
|
+
function validateMemoryPath(path) {
|
|
17
|
+
const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
18
|
+
if (!normalized.startsWith("/memories") || normalized.includes("..") || normalized === "/memories/.." || normalized.startsWith("/memories/../")) {
|
|
19
|
+
throw new Error(`Invalid memory path: ${path}. Path must be under /memories and cannot contain traversal sequences.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/tools/in-memory-agent-memory-store.ts
|
|
24
|
+
function formatSize(bytes) {
|
|
25
|
+
if (bytes < 1024)
|
|
26
|
+
return `${bytes}B`;
|
|
27
|
+
if (bytes < 1024 * 1024)
|
|
28
|
+
return `${(bytes / 1024).toFixed(1)}K`;
|
|
29
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class InMemoryAgentMemoryStore {
|
|
33
|
+
store = new Map;
|
|
34
|
+
async view(path, viewRange) {
|
|
35
|
+
validateMemoryPath(path);
|
|
36
|
+
const normalized = path.replace(/\/+/g, "/").replace(/\/$/, "") || "/memories";
|
|
37
|
+
if (this.isDirectory(normalized)) {
|
|
38
|
+
return this.listDirectory(normalized);
|
|
39
|
+
}
|
|
40
|
+
const content = this.store.get(normalized);
|
|
41
|
+
if (content === undefined) {
|
|
42
|
+
return `The path ${path} does not exist. Please provide a valid path.`;
|
|
43
|
+
}
|
|
44
|
+
const lines = content.split(`
|
|
45
|
+
`);
|
|
46
|
+
if (lines.length > 999999) {
|
|
47
|
+
return `File ${path} exceeds maximum line limit of 999,999 lines.`;
|
|
48
|
+
}
|
|
49
|
+
const [start, end] = viewRange ?? [1, lines.length];
|
|
50
|
+
const from = Math.max(0, start - 1);
|
|
51
|
+
const to = Math.min(lines.length, end);
|
|
52
|
+
const selected = lines.slice(from, to);
|
|
53
|
+
const numbered = selected.map((line, i) => {
|
|
54
|
+
const num = from + i + 1;
|
|
55
|
+
return `${String(num).padStart(6)} ${line}`;
|
|
56
|
+
}).join(`
|
|
57
|
+
`);
|
|
58
|
+
return `Here's the content of ${path} with line numbers:
|
|
59
|
+
${numbered}`;
|
|
60
|
+
}
|
|
61
|
+
async create(path, fileText) {
|
|
62
|
+
validateMemoryPath(path);
|
|
63
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
64
|
+
if (this.store.has(normalized)) {
|
|
65
|
+
return `Error: File ${path} already exists`;
|
|
66
|
+
}
|
|
67
|
+
this.ensureParentDir(normalized);
|
|
68
|
+
this.store.set(normalized, fileText);
|
|
69
|
+
return `File created successfully at: ${path}`;
|
|
70
|
+
}
|
|
71
|
+
async strReplace(path, oldStr, newStr) {
|
|
72
|
+
validateMemoryPath(path);
|
|
73
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
74
|
+
const content = this.store.get(normalized);
|
|
75
|
+
if (content === undefined) {
|
|
76
|
+
return `Error: The path ${path} does not exist. Please provide a valid path.`;
|
|
77
|
+
}
|
|
78
|
+
const count = (content.match(new RegExp(escapeRegex(oldStr), "g")) ?? []).length;
|
|
79
|
+
if (count > 1) {
|
|
80
|
+
const lines = content.split(`
|
|
81
|
+
`);
|
|
82
|
+
const lineNums = [];
|
|
83
|
+
lines.forEach((line, i) => {
|
|
84
|
+
if (line.includes(oldStr))
|
|
85
|
+
lineNums.push(i + 1);
|
|
86
|
+
});
|
|
87
|
+
return `No replacement was performed. Multiple occurrences of old_str \`${oldStr}\` in lines: ${lineNums.join(", ")}. Please ensure it is unique`;
|
|
88
|
+
}
|
|
89
|
+
if (count === 0) {
|
|
90
|
+
return `No replacement was performed, old_str \`${oldStr}\` did not appear verbatim in ${path}.`;
|
|
91
|
+
}
|
|
92
|
+
const newContent = content.replace(oldStr, newStr);
|
|
93
|
+
this.store.set(normalized, newContent);
|
|
94
|
+
const snippet = newContent.split(`
|
|
95
|
+
`).slice(0, 5);
|
|
96
|
+
const numbered = snippet.map((line, i) => `${String(i + 1).padStart(6)} ${line}`).join(`
|
|
97
|
+
`);
|
|
98
|
+
return `The memory file has been edited.
|
|
99
|
+
${numbered}`;
|
|
100
|
+
}
|
|
101
|
+
async insert(path, insertLine, insertText) {
|
|
102
|
+
validateMemoryPath(path);
|
|
103
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
104
|
+
const content = this.store.get(normalized);
|
|
105
|
+
if (content === undefined) {
|
|
106
|
+
return `Error: The path ${path} does not exist`;
|
|
107
|
+
}
|
|
108
|
+
const lines = content.split(`
|
|
109
|
+
`);
|
|
110
|
+
const n = lines.length;
|
|
111
|
+
if (insertLine < 0 || insertLine > n) {
|
|
112
|
+
return `Error: Invalid \`insert_line\` parameter: ${insertLine}. It should be within the range of lines of the file: [0, ${n}]`;
|
|
113
|
+
}
|
|
114
|
+
lines.splice(insertLine, 0, insertText.replace(/\n$/, ""));
|
|
115
|
+
this.store.set(normalized, lines.join(`
|
|
116
|
+
`));
|
|
117
|
+
return `The file ${path} has been edited.`;
|
|
118
|
+
}
|
|
119
|
+
async delete(path) {
|
|
120
|
+
validateMemoryPath(path);
|
|
121
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
122
|
+
if (this.isDirectory(normalized)) {
|
|
123
|
+
const prefix = normalized === "/memories" ? "/memories/" : `${normalized}/`;
|
|
124
|
+
for (const key of this.store.keys()) {
|
|
125
|
+
if (key.startsWith(prefix) || key === normalized) {
|
|
126
|
+
this.store.delete(key);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
if (!this.store.has(normalized)) {
|
|
131
|
+
return `Error: The path ${path} does not exist`;
|
|
132
|
+
}
|
|
133
|
+
this.store.delete(normalized);
|
|
134
|
+
}
|
|
135
|
+
return `Successfully deleted ${path}`;
|
|
136
|
+
}
|
|
137
|
+
async rename(oldPath, newPath) {
|
|
138
|
+
validateMemoryPath(oldPath);
|
|
139
|
+
validateMemoryPath(newPath);
|
|
140
|
+
const oldNorm = oldPath.replace(/\/+/g, "/");
|
|
141
|
+
const newNorm = newPath.replace(/\/+/g, "/");
|
|
142
|
+
if (this.store.has(newNorm) || this.hasAnyChild(newNorm)) {
|
|
143
|
+
return `Error: The destination ${newPath} already exists`;
|
|
144
|
+
}
|
|
145
|
+
if (this.isDirectory(oldNorm)) {
|
|
146
|
+
const oldPrefix = `${oldNorm}/`;
|
|
147
|
+
const entries = Array.from(this.store.entries()).filter(([k]) => k.startsWith(oldPrefix) || k === oldNorm);
|
|
148
|
+
const newPrefix = `${newNorm}/`;
|
|
149
|
+
for (const [k, v] of entries) {
|
|
150
|
+
this.store.delete(k);
|
|
151
|
+
const newKey = k === oldNorm ? newNorm : newPrefix + k.slice(oldPrefix.length);
|
|
152
|
+
this.store.set(newKey, v);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
const content = this.store.get(oldNorm);
|
|
156
|
+
if (content === undefined) {
|
|
157
|
+
return `Error: The path ${oldPath} does not exist`;
|
|
158
|
+
}
|
|
159
|
+
this.store.delete(oldNorm);
|
|
160
|
+
this.ensureParentDir(newNorm);
|
|
161
|
+
this.store.set(newNorm, content);
|
|
162
|
+
}
|
|
163
|
+
return `Successfully renamed ${oldPath} to ${newPath}`;
|
|
164
|
+
}
|
|
165
|
+
isDirectory(path) {
|
|
166
|
+
if (path === "/memories")
|
|
167
|
+
return true;
|
|
168
|
+
for (const key of this.store.keys()) {
|
|
169
|
+
if (key.startsWith(path + "/"))
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
hasAnyChild(path) {
|
|
175
|
+
const prefix = path.endsWith("/") ? path : `${path}/`;
|
|
176
|
+
for (const key of this.store.keys()) {
|
|
177
|
+
if (key.startsWith(prefix))
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
ensureParentDir(path) {
|
|
183
|
+
const parts = path.split("/").filter(Boolean);
|
|
184
|
+
parts.pop();
|
|
185
|
+
for (let i = 1;i <= parts.length; i++) {
|
|
186
|
+
const p = "/" + parts.slice(0, i).join("/");
|
|
187
|
+
if (!this.store.has(p)) {
|
|
188
|
+
this.store.set(p, "");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
listDirectory(path) {
|
|
193
|
+
const prefix = path === "/memories" ? "/memories/" : `${path}/`;
|
|
194
|
+
const seen = new Set;
|
|
195
|
+
const entries = [];
|
|
196
|
+
if (path === "/memories") {
|
|
197
|
+
entries.push({
|
|
198
|
+
path: "/memories",
|
|
199
|
+
size: Array.from(this.store.keys()).filter((k) => k.startsWith("/memories/")).reduce((acc, k) => acc + (this.store.get(k)?.length ?? 0), 0)
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
for (const key of this.store.keys()) {
|
|
203
|
+
if (!key.startsWith(prefix) && key !== path)
|
|
204
|
+
continue;
|
|
205
|
+
const rel = key.slice(prefix.length);
|
|
206
|
+
const first = rel.split("/")[0];
|
|
207
|
+
if (!first || first.startsWith(".") || first === "node_modules")
|
|
208
|
+
continue;
|
|
209
|
+
const fullPath = path === "/memories" ? `/memories/${first}` : `${path}/${first}`;
|
|
210
|
+
if (seen.has(fullPath))
|
|
211
|
+
continue;
|
|
212
|
+
seen.add(fullPath);
|
|
213
|
+
let size = 0;
|
|
214
|
+
if (this.store.has(key)) {
|
|
215
|
+
size = (this.store.get(key) ?? "").length;
|
|
216
|
+
} else {
|
|
217
|
+
for (const k of this.store.keys()) {
|
|
218
|
+
if (k.startsWith(fullPath + "/") || k === fullPath) {
|
|
219
|
+
size += (this.store.get(k) ?? "").length;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
entries.push({ path: fullPath, size });
|
|
224
|
+
}
|
|
225
|
+
const lines = entries.slice(0, 50).map((e) => `${formatSize(e.size)} ${e.path}`).join(`
|
|
226
|
+
`);
|
|
227
|
+
return `Here're the files and directories up to 2 levels deep in ${path}, excluding hidden items and node_modules:
|
|
228
|
+
${lines}`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function escapeRegex(s) {
|
|
232
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
233
|
+
}
|
|
234
|
+
export {
|
|
235
|
+
InMemoryAgentMemoryStore
|
|
236
|
+
};
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export * from './tool-adapter';
|
|
2
|
+
export * from './operation-tool-handler';
|
|
2
3
|
export * from './knowledge-tool';
|
|
4
|
+
export * from './subagent-tool';
|
|
3
5
|
export * from './mcp-client';
|
|
4
6
|
export * from './mcp-server';
|
|
7
|
+
export * from './agent-memory-store';
|
|
8
|
+
export * from './in-memory-agent-memory-store';
|
|
9
|
+
export * from './memory-tools';
|