@cuylabs/agent-core 0.1.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 +275 -0
- package/dist/chunk-6VKLWNRE.js +288 -0
- package/dist/index-eud06GDQ.d.ts +446 -0
- package/dist/index.d.ts +4414 -0
- package/dist/index.js +6646 -0
- package/dist/tool/index.d.ts +2 -0
- package/dist/tool/index.js +24 -0
- package/package.json +98 -0
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# @cuylabs/agent-core
|
|
2
|
+
|
|
3
|
+
Embeddable AI agent infrastructure using Vercel AI SDK. Core building blocks for streaming AI agents with session management, resilience, and model capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Agent Framework** - Create AI agents with tool support and streaming responses
|
|
8
|
+
- **Session Management** - Persistent conversation state with branching support
|
|
9
|
+
- **LLM Streaming** - Real-time streaming with proper backpressure handling
|
|
10
|
+
- **Error Resilience** - Automatic retry with exponential backoff
|
|
11
|
+
- **Context Management** - Token counting and automatic context pruning
|
|
12
|
+
- **Tool Framework** - Type-safe tool definitions with Zod schemas
|
|
13
|
+
- **Approval System** - Configurable tool approval workflows
|
|
14
|
+
- **Checkpoint System** - Undo/restore capabilities for file operations
|
|
15
|
+
- **Model Capabilities** - Runtime model capability detection
|
|
16
|
+
- **MCP Support** - Extend agents with Model Context Protocol servers
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @cuylabs/agent-core
|
|
22
|
+
# or
|
|
23
|
+
pnpm add @cuylabs/agent-core
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
You'll also need at least one AI SDK provider:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @ai-sdk/openai
|
|
30
|
+
# or @ai-sdk/anthropic, @ai-sdk/google
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For OpenAI-compatible endpoints (local or hosted), add:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @ai-sdk/openai-compatible
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { createAgent, Tool } from "@cuylabs/agent-core";
|
|
43
|
+
import { openai } from "@ai-sdk/openai";
|
|
44
|
+
import { z } from "zod";
|
|
45
|
+
|
|
46
|
+
// Define tools
|
|
47
|
+
const tools: Tool[] = [
|
|
48
|
+
{
|
|
49
|
+
name: "greet",
|
|
50
|
+
description: "Greet a user by name",
|
|
51
|
+
parameters: z.object({
|
|
52
|
+
name: z.string().describe("Name to greet"),
|
|
53
|
+
}),
|
|
54
|
+
execute: async ({ name }) => `Hello, ${name}!`,
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
// Create agent
|
|
59
|
+
const agent = createAgent({
|
|
60
|
+
model: openai("gpt-4o"),
|
|
61
|
+
cwd: process.cwd(),
|
|
62
|
+
tools,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Stream responses
|
|
66
|
+
for await (const event of agent.chat("session-1", "Hello!")) {
|
|
67
|
+
switch (event.type) {
|
|
68
|
+
case "text-delta":
|
|
69
|
+
process.stdout.write(event.text);
|
|
70
|
+
break;
|
|
71
|
+
case "tool-call":
|
|
72
|
+
console.log(`Calling tool: ${event.toolName}`);
|
|
73
|
+
break;
|
|
74
|
+
case "tool-result":
|
|
75
|
+
console.log(`Tool result: ${event.result}`);
|
|
76
|
+
break;
|
|
77
|
+
case "complete":
|
|
78
|
+
console.log("\nDone!");
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API Reference
|
|
85
|
+
|
|
86
|
+
### Local Models (Ollama Example)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { createAgent, createModelResolver } from "@cuylabs/agent-core";
|
|
90
|
+
|
|
91
|
+
const resolveModel = createModelResolver({
|
|
92
|
+
engines: {
|
|
93
|
+
ollama: {
|
|
94
|
+
adapter: "openai-compatible",
|
|
95
|
+
settings: {
|
|
96
|
+
baseUrl: "http://localhost:11434/v1",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const agent = createAgent({
|
|
103
|
+
model: resolveModel("ollama/llama3.1"),
|
|
104
|
+
cwd: process.cwd(),
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Agent
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { createAgent, Agent } from "@cuylabs/agent-core";
|
|
112
|
+
import { openai } from "@ai-sdk/openai";
|
|
113
|
+
|
|
114
|
+
const agent = createAgent({
|
|
115
|
+
model: openai("gpt-4o"),
|
|
116
|
+
cwd: "/path/to/project",
|
|
117
|
+
tools: myTools,
|
|
118
|
+
systemPrompt: "You are a helpful assistant.",
|
|
119
|
+
temperature: 0.7,
|
|
120
|
+
maxSteps: 10,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Streaming chat
|
|
124
|
+
for await (const event of agent.chat(sessionId, message)) {
|
|
125
|
+
// Handle events
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Session Management
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import {
|
|
133
|
+
SessionManager,
|
|
134
|
+
MemoryStorage,
|
|
135
|
+
FileStorage
|
|
136
|
+
} from "@cuylabs/agent-core";
|
|
137
|
+
|
|
138
|
+
// In-memory storage (default)
|
|
139
|
+
const memoryStorage = new MemoryStorage();
|
|
140
|
+
|
|
141
|
+
// File-based persistent storage
|
|
142
|
+
const fileStorage = new FileStorage({
|
|
143
|
+
dataDir: "/path/to/data",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const sessions = new SessionManager(fileStorage);
|
|
147
|
+
await sessions.createSession({ id: "my-session" });
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Tool Framework
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { defineTool, Tool, ToolRegistry } from "@cuylabs/agent-core";
|
|
154
|
+
import { z } from "zod";
|
|
155
|
+
|
|
156
|
+
const myTool = defineTool({
|
|
157
|
+
name: "calculate",
|
|
158
|
+
description: "Perform a calculation",
|
|
159
|
+
parameters: z.object({
|
|
160
|
+
expression: z.string(),
|
|
161
|
+
}),
|
|
162
|
+
execute: async ({ expression }, ctx) => {
|
|
163
|
+
// ctx provides sessionId, cwd, abort signal, etc.
|
|
164
|
+
return eval(expression); // Don't actually do this!
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Register tools
|
|
169
|
+
const registry = new ToolRegistry();
|
|
170
|
+
registry.register(myTool);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Error Handling & Retry
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import {
|
|
177
|
+
withRetry,
|
|
178
|
+
LLMError,
|
|
179
|
+
isRetryable,
|
|
180
|
+
getRetryDelay
|
|
181
|
+
} from "@cuylabs/agent-core";
|
|
182
|
+
|
|
183
|
+
const result = await withRetry(
|
|
184
|
+
async () => {
|
|
185
|
+
// Your operation
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
maxRetries: 3,
|
|
189
|
+
initialDelay: 1000,
|
|
190
|
+
maxDelay: 30000,
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Context Management
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import {
|
|
199
|
+
ContextManager,
|
|
200
|
+
estimateTokens,
|
|
201
|
+
pruneContext
|
|
202
|
+
} from "@cuylabs/agent-core";
|
|
203
|
+
|
|
204
|
+
const ctx = new ContextManager({
|
|
205
|
+
maxInputTokens: 100000,
|
|
206
|
+
pruneThreshold: 0.9,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const tokens = estimateTokens("Your text here");
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Model Capabilities
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import {
|
|
216
|
+
ModelCapabilityResolver,
|
|
217
|
+
getDefaultResolver
|
|
218
|
+
} from "@cuylabs/agent-core";
|
|
219
|
+
|
|
220
|
+
const resolver = getDefaultResolver();
|
|
221
|
+
const caps = await resolver.resolve("gpt-4o");
|
|
222
|
+
|
|
223
|
+
console.log(caps.supportsImages);
|
|
224
|
+
console.log(caps.supportsToolUse);
|
|
225
|
+
console.log(caps.maxOutputTokens);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### MCP (Model Context Protocol)
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import {
|
|
232
|
+
createAgent,
|
|
233
|
+
createMCPManager,
|
|
234
|
+
stdioServer
|
|
235
|
+
} from "@cuylabs/agent-core";
|
|
236
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
237
|
+
|
|
238
|
+
// Create MCP manager with servers
|
|
239
|
+
const mcp = createMCPManager({
|
|
240
|
+
filesystem: stdioServer("npx", [
|
|
241
|
+
"-y", "@modelcontextprotocol/server-filesystem", "/tmp"
|
|
242
|
+
]),
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Create agent with MCP tools
|
|
246
|
+
const agent = createAgent({
|
|
247
|
+
model: anthropic("claude-sonnet-4-20250514"),
|
|
248
|
+
mcp,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// MCP tools are automatically available
|
|
252
|
+
const result = await agent.send("session", "List files in /tmp");
|
|
253
|
+
|
|
254
|
+
// Clean up
|
|
255
|
+
await agent.close();
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Event Types
|
|
259
|
+
|
|
260
|
+
The `chat()` method yields these event types:
|
|
261
|
+
|
|
262
|
+
| Event Type | Description |
|
|
263
|
+
|------------|-------------|
|
|
264
|
+
| `text-delta` | Streaming text chunk |
|
|
265
|
+
| `tool-call` | Tool invocation started |
|
|
266
|
+
| `tool-result` | Tool execution completed |
|
|
267
|
+
| `reasoning` | Model reasoning (if supported) |
|
|
268
|
+
| `message` | Complete assistant message |
|
|
269
|
+
| `complete` | Stream finished with usage stats |
|
|
270
|
+
| `error` | Error occurred |
|
|
271
|
+
|
|
272
|
+
## Concurrency Note
|
|
273
|
+
|
|
274
|
+
When using `runConcurrent()` to run multiple tasks in parallel, be aware that all tasks share the same `SessionManager` instance. For independent conversations, create separate `Agent` instances or use distinct session IDs.
|
|
275
|
+
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// src/tool/tool.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/tool/truncation.ts
|
|
5
|
+
import * as fs from "fs/promises";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
import * as crypto from "crypto";
|
|
9
|
+
var MAX_LINES = 2e3;
|
|
10
|
+
var MAX_BYTES = 1e5;
|
|
11
|
+
var TRUNCATE_DIR = path.join(os.tmpdir(), "cuylabs-agent-outputs");
|
|
12
|
+
var TRUNCATE_GLOB = path.join(TRUNCATE_DIR, "*");
|
|
13
|
+
function truncateOutput(output, options = {}) {
|
|
14
|
+
const maxLines = options.maxLines ?? MAX_LINES;
|
|
15
|
+
const maxBytes = options.maxBytes ?? MAX_BYTES;
|
|
16
|
+
const lines = output.split("\n");
|
|
17
|
+
const bytes = Buffer.byteLength(output, "utf-8");
|
|
18
|
+
if (lines.length <= maxLines && bytes <= maxBytes) {
|
|
19
|
+
return {
|
|
20
|
+
content: output,
|
|
21
|
+
truncated: false
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const hash = crypto.createHash("sha256").update(output).digest("hex").slice(0, 16);
|
|
25
|
+
const outputPath = path.join(TRUNCATE_DIR, `output-${hash}.txt`);
|
|
26
|
+
fs.mkdir(TRUNCATE_DIR, { recursive: true }).then(() => fs.writeFile(outputPath, output, "utf-8")).catch(() => {
|
|
27
|
+
});
|
|
28
|
+
let truncated;
|
|
29
|
+
if (lines.length > maxLines) {
|
|
30
|
+
const keepLines = Math.floor(maxLines / 2);
|
|
31
|
+
const firstPart = lines.slice(0, keepLines);
|
|
32
|
+
const lastPart = lines.slice(-keepLines);
|
|
33
|
+
const omitted = lines.length - keepLines * 2;
|
|
34
|
+
truncated = [
|
|
35
|
+
...firstPart,
|
|
36
|
+
`
|
|
37
|
+
... (${omitted} lines omitted, full output saved to ${outputPath}) ...
|
|
38
|
+
`,
|
|
39
|
+
...lastPart
|
|
40
|
+
].join("\n");
|
|
41
|
+
} else {
|
|
42
|
+
const keepBytes = Math.floor(maxBytes / 2);
|
|
43
|
+
const start = output.slice(0, keepBytes);
|
|
44
|
+
const end = output.slice(-keepBytes);
|
|
45
|
+
const omittedBytes = bytes - keepBytes * 2;
|
|
46
|
+
truncated = `${start}
|
|
47
|
+
... (${omittedBytes} bytes omitted, full output saved to ${outputPath}) ...
|
|
48
|
+
${end}`;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
content: truncated,
|
|
52
|
+
truncated: true,
|
|
53
|
+
outputPath
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function formatSize(bytes) {
|
|
57
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
58
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
59
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/tool/tool.ts
|
|
63
|
+
var Tool;
|
|
64
|
+
((Tool2) => {
|
|
65
|
+
function define(id, init) {
|
|
66
|
+
return {
|
|
67
|
+
id,
|
|
68
|
+
init: async (initCtx) => {
|
|
69
|
+
const toolInfo = typeof init === "function" ? await init(initCtx) : init;
|
|
70
|
+
const originalExecute = toolInfo.execute;
|
|
71
|
+
toolInfo.execute = async (params, ctx) => {
|
|
72
|
+
try {
|
|
73
|
+
toolInfo.parameters.parse(params);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error instanceof z.ZodError && toolInfo.formatValidationError) {
|
|
76
|
+
throw new Error(toolInfo.formatValidationError(error), { cause: error });
|
|
77
|
+
}
|
|
78
|
+
throw new Error(
|
|
79
|
+
`The ${id} tool was called with invalid arguments: ${error}.
|
|
80
|
+
Please rewrite the input so it satisfies the expected schema.`,
|
|
81
|
+
{ cause: error }
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
const result = await originalExecute(params, ctx);
|
|
85
|
+
if (result.metadata.truncated !== void 0) {
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
const truncated = truncateOutput(result.output);
|
|
89
|
+
return {
|
|
90
|
+
...result,
|
|
91
|
+
output: truncated.content,
|
|
92
|
+
metadata: {
|
|
93
|
+
...result.metadata,
|
|
94
|
+
truncated: truncated.truncated,
|
|
95
|
+
...truncated.truncated && { outputPath: truncated.outputPath }
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
return toolInfo;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
Tool2.define = define;
|
|
104
|
+
function defineSimple(id, config) {
|
|
105
|
+
return define(id, config);
|
|
106
|
+
}
|
|
107
|
+
Tool2.defineSimple = defineSimple;
|
|
108
|
+
})(Tool || (Tool = {}));
|
|
109
|
+
function defineTool(definition) {
|
|
110
|
+
return Tool.define(definition.id, {
|
|
111
|
+
description: definition.description,
|
|
112
|
+
parameters: definition.parameters,
|
|
113
|
+
execute: async (params, ctx) => {
|
|
114
|
+
const result = await definition.execute(params, ctx);
|
|
115
|
+
return {
|
|
116
|
+
title: result.title,
|
|
117
|
+
output: result.output,
|
|
118
|
+
metadata: result.metadata ?? {}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/tool/registry.ts
|
|
125
|
+
var ToolRegistry = class {
|
|
126
|
+
tools = /* @__PURE__ */ new Map();
|
|
127
|
+
groups = /* @__PURE__ */ new Map();
|
|
128
|
+
// --------------------------------------------------------------------------
|
|
129
|
+
// Tool registration
|
|
130
|
+
// --------------------------------------------------------------------------
|
|
131
|
+
/**
|
|
132
|
+
* Register a tool. Throws if a tool with the same ID is already registered.
|
|
133
|
+
* Use `set()` for upsert semantics.
|
|
134
|
+
*/
|
|
135
|
+
register(tool) {
|
|
136
|
+
if (this.tools.has(tool.id)) {
|
|
137
|
+
throw new Error(`Tool '${tool.id}' is already registered`);
|
|
138
|
+
}
|
|
139
|
+
this.tools.set(tool.id, tool);
|
|
140
|
+
}
|
|
141
|
+
/** Register multiple tools (throws on duplicates). */
|
|
142
|
+
registerAll(tools) {
|
|
143
|
+
for (const tool of tools) {
|
|
144
|
+
this.register(tool);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Register or replace a tool (upsert). */
|
|
148
|
+
set(tool) {
|
|
149
|
+
this.tools.set(tool.id, tool);
|
|
150
|
+
}
|
|
151
|
+
/** Unregister a tool by ID. Returns `true` if it existed. */
|
|
152
|
+
unregister(id) {
|
|
153
|
+
return this.tools.delete(id);
|
|
154
|
+
}
|
|
155
|
+
/** Get a tool by ID. */
|
|
156
|
+
get(id) {
|
|
157
|
+
return this.tools.get(id);
|
|
158
|
+
}
|
|
159
|
+
/** Check if a tool is registered. */
|
|
160
|
+
has(id) {
|
|
161
|
+
return this.tools.has(id);
|
|
162
|
+
}
|
|
163
|
+
/** Get all tool IDs. */
|
|
164
|
+
ids() {
|
|
165
|
+
return Array.from(this.tools.keys());
|
|
166
|
+
}
|
|
167
|
+
/** Get all tools. */
|
|
168
|
+
all() {
|
|
169
|
+
return Array.from(this.tools.values());
|
|
170
|
+
}
|
|
171
|
+
/** Clear all tools and groups. */
|
|
172
|
+
clear() {
|
|
173
|
+
this.tools.clear();
|
|
174
|
+
this.groups.clear();
|
|
175
|
+
}
|
|
176
|
+
/** Number of registered tools. */
|
|
177
|
+
get size() {
|
|
178
|
+
return this.tools.size;
|
|
179
|
+
}
|
|
180
|
+
// --------------------------------------------------------------------------
|
|
181
|
+
// Group management
|
|
182
|
+
// --------------------------------------------------------------------------
|
|
183
|
+
/**
|
|
184
|
+
* Register a named group of tool IDs.
|
|
185
|
+
* The group name can be used in `resolve()` specs.
|
|
186
|
+
* Tool IDs don't need to be registered yet — resolution is lazy.
|
|
187
|
+
*/
|
|
188
|
+
registerGroup(name, toolIds) {
|
|
189
|
+
this.groups.set(name, toolIds);
|
|
190
|
+
}
|
|
191
|
+
/** Get tools in a group (only returns registered tools). */
|
|
192
|
+
getGroup(name) {
|
|
193
|
+
const ids = this.groups.get(name);
|
|
194
|
+
if (!ids) return void 0;
|
|
195
|
+
return ids.map((id) => this.tools.get(id)).filter((t) => t !== void 0);
|
|
196
|
+
}
|
|
197
|
+
/** Check if a group is registered. */
|
|
198
|
+
hasGroup(name) {
|
|
199
|
+
return this.groups.has(name);
|
|
200
|
+
}
|
|
201
|
+
/** List all group names. */
|
|
202
|
+
listGroups() {
|
|
203
|
+
return Array.from(this.groups.keys());
|
|
204
|
+
}
|
|
205
|
+
// --------------------------------------------------------------------------
|
|
206
|
+
// Resolution
|
|
207
|
+
// --------------------------------------------------------------------------
|
|
208
|
+
/**
|
|
209
|
+
* Resolve a `ToolSpec` to an array of tools.
|
|
210
|
+
*
|
|
211
|
+
* Supports group names, individual tool IDs, comma-separated strings,
|
|
212
|
+
* exclusions with `-` prefix, booleans, and pass-through arrays.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* registry.resolve("read-only"); // group name
|
|
217
|
+
* registry.resolve("read,grep,glob"); // comma-separated IDs
|
|
218
|
+
* registry.resolve("all,-bash"); // all except bash
|
|
219
|
+
* registry.resolve(["read", "grep"]); // array of IDs
|
|
220
|
+
* registry.resolve(true); // all registered tools
|
|
221
|
+
* registry.resolve(false); // empty array
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
resolve(spec) {
|
|
225
|
+
if (spec === true) return this.all();
|
|
226
|
+
if (spec === false) return [];
|
|
227
|
+
if (Array.isArray(spec) && spec.length > 0 && typeof spec[0] !== "string") {
|
|
228
|
+
return spec;
|
|
229
|
+
}
|
|
230
|
+
const tokens = Array.isArray(spec) ? spec : spec.split(",").map((s) => s.trim()).filter(Boolean);
|
|
231
|
+
const includes = [];
|
|
232
|
+
const excludes = [];
|
|
233
|
+
for (const token of tokens) {
|
|
234
|
+
if (token.startsWith("-")) {
|
|
235
|
+
excludes.push(token.slice(1));
|
|
236
|
+
} else {
|
|
237
|
+
includes.push(token);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
let result = /* @__PURE__ */ new Map();
|
|
241
|
+
if (includes.length === 0 && excludes.length > 0) {
|
|
242
|
+
for (const [id, tool] of this.tools) {
|
|
243
|
+
result.set(id, tool);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
for (const token of includes) {
|
|
247
|
+
if (token === "all") {
|
|
248
|
+
for (const [id, tool] of this.tools) {
|
|
249
|
+
result.set(id, tool);
|
|
250
|
+
}
|
|
251
|
+
} else if (this.groups.has(token)) {
|
|
252
|
+
const ids = this.groups.get(token);
|
|
253
|
+
for (const id of ids) {
|
|
254
|
+
const tool = this.tools.get(id);
|
|
255
|
+
if (tool) result.set(id, tool);
|
|
256
|
+
}
|
|
257
|
+
} else if (this.tools.has(token)) {
|
|
258
|
+
result.set(token, this.tools.get(token));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for (const id of excludes) {
|
|
263
|
+
if (this.groups.has(id)) {
|
|
264
|
+
const ids = this.groups.get(id);
|
|
265
|
+
for (const gid of ids) {
|
|
266
|
+
result.delete(gid);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
result.delete(id);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return Array.from(result.values());
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
var defaultRegistry = new ToolRegistry();
|
|
276
|
+
|
|
277
|
+
export {
|
|
278
|
+
MAX_LINES,
|
|
279
|
+
MAX_BYTES,
|
|
280
|
+
TRUNCATE_DIR,
|
|
281
|
+
TRUNCATE_GLOB,
|
|
282
|
+
truncateOutput,
|
|
283
|
+
formatSize,
|
|
284
|
+
Tool,
|
|
285
|
+
defineTool,
|
|
286
|
+
ToolRegistry,
|
|
287
|
+
defaultRegistry
|
|
288
|
+
};
|