@acontext/acontext 0.0.8 → 0.0.9
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 +126 -39
- package/dist/agent/base.d.ts +36 -0
- package/dist/agent/base.js +68 -0
- package/dist/agent/disk.d.ts +93 -0
- package/dist/agent/disk.js +243 -0
- package/dist/agent/index.d.ts +5 -0
- package/dist/agent/index.js +21 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/resources/spaces.d.ts +1 -31
- package/dist/resources/spaces.js +0 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,9 +136,134 @@ const result = await client.tools.renameToolName({
|
|
|
136
136
|
console.log(result); // { status: 0, errmsg: '' }
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
+
## Agent Tools
|
|
140
|
+
|
|
141
|
+
The SDK provides agent tools that allow LLMs (OpenAI, Anthropic) to interact with Acontext disks through function calling. These tools can be converted to OpenAI or Anthropic tool schemas and executed when the LLM calls them.
|
|
142
|
+
|
|
143
|
+
### Pre-configured Disk Tools
|
|
144
|
+
|
|
145
|
+
The SDK includes a pre-configured `DISK_TOOLS` pool with four disk operation tools:
|
|
146
|
+
|
|
147
|
+
- **`write_file`**: Write text content to a file
|
|
148
|
+
- **`read_file`**: Read a text file with optional line offset and limit
|
|
149
|
+
- **`replace_string`**: Replace strings in a file
|
|
150
|
+
- **`list_artifacts`**: List files and directories in a path
|
|
151
|
+
|
|
152
|
+
### Getting Tool Schemas for LLM APIs
|
|
153
|
+
|
|
154
|
+
Convert tools to the appropriate format for your LLM provider:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { AcontextClient, DISK_TOOLS } from '@acontext/acontext';
|
|
158
|
+
|
|
159
|
+
const client = new AcontextClient({ apiKey: 'sk-ac-your-root-api-bearer-token' });
|
|
160
|
+
|
|
161
|
+
// Get OpenAI-compatible tool schemas
|
|
162
|
+
const openaiTools = DISK_TOOLS.toOpenAIToolSchema();
|
|
163
|
+
|
|
164
|
+
// Get Anthropic-compatible tool schemas
|
|
165
|
+
const anthropicTools = DISK_TOOLS.toAnthropicToolSchema();
|
|
166
|
+
|
|
167
|
+
// Use with OpenAI API
|
|
168
|
+
import OpenAI from 'openai';
|
|
169
|
+
const openai = new OpenAI({ apiKey: 'your-openai-key' });
|
|
170
|
+
const completion = await openai.chat.completions.create({
|
|
171
|
+
model: 'gpt-4',
|
|
172
|
+
messages: [{ role: 'user', content: 'Write a file called hello.txt with "Hello, World!"' }],
|
|
173
|
+
tools: openaiTools,
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Executing Tools
|
|
178
|
+
|
|
179
|
+
When an LLM calls a tool, execute it using the tool pool:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { AcontextClient, DISK_TOOLS } from '@acontext/acontext';
|
|
183
|
+
|
|
184
|
+
const client = new AcontextClient({ apiKey: 'sk-ac-your-root-api-bearer-token' });
|
|
185
|
+
|
|
186
|
+
// Create a disk for the tools to operate on
|
|
187
|
+
const disk = await client.disks.create();
|
|
188
|
+
|
|
189
|
+
// Create a context for the tools
|
|
190
|
+
const ctx = DISK_TOOLS.formatContext(client, disk.id);
|
|
191
|
+
|
|
192
|
+
// Execute a tool (e.g., after LLM returns a tool call)
|
|
193
|
+
const result = await DISK_TOOLS.executeTool(ctx, 'write_file', {
|
|
194
|
+
filename: 'hello.txt',
|
|
195
|
+
file_path: '/notes/',
|
|
196
|
+
content: 'Hello, World!',
|
|
197
|
+
});
|
|
198
|
+
console.log(result); // File 'hello.txt' written successfully to '/notes/hello.txt'
|
|
199
|
+
|
|
200
|
+
// Read the file
|
|
201
|
+
const readResult = await DISK_TOOLS.executeTool(ctx, 'read_file', {
|
|
202
|
+
filename: 'hello.txt',
|
|
203
|
+
file_path: '/notes/',
|
|
204
|
+
});
|
|
205
|
+
console.log(readResult);
|
|
206
|
+
|
|
207
|
+
// List files in a directory
|
|
208
|
+
const listResult = await DISK_TOOLS.executeTool(ctx, 'list_artifacts', {
|
|
209
|
+
file_path: '/notes/',
|
|
210
|
+
});
|
|
211
|
+
console.log(listResult);
|
|
212
|
+
|
|
213
|
+
// Replace a string in a file
|
|
214
|
+
const replaceResult = await DISK_TOOLS.executeTool(ctx, 'replace_string', {
|
|
215
|
+
filename: 'hello.txt',
|
|
216
|
+
file_path: '/notes/',
|
|
217
|
+
old_string: 'Hello',
|
|
218
|
+
new_string: 'Hi',
|
|
219
|
+
});
|
|
220
|
+
console.log(replaceResult);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Creating Custom Tools
|
|
224
|
+
|
|
225
|
+
You can create custom tools by extending `AbstractBaseTool`:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { AbstractBaseTool, BaseContext, BaseToolPool } from '@acontext/acontext';
|
|
229
|
+
|
|
230
|
+
interface MyContext extends BaseContext {
|
|
231
|
+
// Your context properties
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class MyCustomTool extends AbstractBaseTool {
|
|
235
|
+
readonly name = 'my_custom_tool';
|
|
236
|
+
readonly description = 'A custom tool that does something';
|
|
237
|
+
readonly arguments = {
|
|
238
|
+
param1: {
|
|
239
|
+
type: 'string',
|
|
240
|
+
description: 'First parameter',
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
readonly requiredArguments = ['param1'];
|
|
244
|
+
|
|
245
|
+
async execute(ctx: MyContext, llmArguments: Record<string, unknown>): Promise<string> {
|
|
246
|
+
const param1 = llmArguments.param1 as string;
|
|
247
|
+
// Your custom logic here
|
|
248
|
+
return `Result: ${param1}`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Create a custom tool pool
|
|
253
|
+
class MyToolPool extends BaseToolPool {
|
|
254
|
+
formatContext(...args: unknown[]): MyContext {
|
|
255
|
+
// Create and return your context
|
|
256
|
+
return {};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const myPool = new MyToolPool();
|
|
261
|
+
myPool.addTool(new MyCustomTool());
|
|
262
|
+
```
|
|
263
|
+
|
|
139
264
|
## Semantic search within spaces
|
|
140
265
|
|
|
141
|
-
The SDK provides
|
|
266
|
+
The SDK provides a powerful semantic search API for finding content within your spaces:
|
|
142
267
|
|
|
143
268
|
### 1. Experience Search (Advanced AI-powered search)
|
|
144
269
|
|
|
@@ -175,41 +300,3 @@ if (result.final_answer) {
|
|
|
175
300
|
}
|
|
176
301
|
```
|
|
177
302
|
|
|
178
|
-
### 2. Semantic Glob (Search page/folder titles)
|
|
179
|
-
|
|
180
|
-
Search for pages and folders by their titles using semantic similarity (like a semantic version of `glob`):
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
// Find pages about authentication
|
|
184
|
-
const results = await client.spaces.semanticGlobal('space-uuid', {
|
|
185
|
-
query: 'authentication and authorization pages',
|
|
186
|
-
limit: 10,
|
|
187
|
-
threshold: 1.0, // Only show results with distance < 1.0
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
for (const block of results) {
|
|
191
|
-
console.log(`${block.title} - ${block.type}`);
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### 3. Semantic Grep (Search content blocks)
|
|
196
|
-
|
|
197
|
-
Search through actual content blocks using semantic similarity (like a semantic version of `grep`):
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
// Find code examples for JWT validation
|
|
201
|
-
const results = await client.spaces.semanticGrep('space-uuid', {
|
|
202
|
-
query: 'JWT token validation code examples',
|
|
203
|
-
limit: 15,
|
|
204
|
-
threshold: 0.7,
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
for (const block of results) {
|
|
208
|
-
console.log(`${block.title} - distance: ${block.distance}`);
|
|
209
|
-
const content = block.props.text || block.props.content;
|
|
210
|
-
if (content) {
|
|
211
|
-
console.log(`Content: ${String(content).substring(0, 100)}...`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base classes for agent tools.
|
|
3
|
+
*/
|
|
4
|
+
export interface BaseContext {
|
|
5
|
+
}
|
|
6
|
+
export interface BaseConverter {
|
|
7
|
+
toOpenAIToolSchema(): Record<string, unknown>;
|
|
8
|
+
toAnthropicToolSchema(): Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface BaseTool extends BaseConverter {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly description: string;
|
|
13
|
+
readonly arguments: Record<string, unknown>;
|
|
14
|
+
readonly requiredArguments: string[];
|
|
15
|
+
execute(ctx: BaseContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
export declare abstract class AbstractBaseTool implements BaseTool {
|
|
18
|
+
abstract readonly name: string;
|
|
19
|
+
abstract readonly description: string;
|
|
20
|
+
abstract readonly arguments: Record<string, unknown>;
|
|
21
|
+
abstract readonly requiredArguments: string[];
|
|
22
|
+
abstract execute(ctx: BaseContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
23
|
+
toOpenAIToolSchema(): Record<string, unknown>;
|
|
24
|
+
toAnthropicToolSchema(): Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export declare abstract class BaseToolPool {
|
|
27
|
+
protected tools: Map<string, BaseTool>;
|
|
28
|
+
addTool(tool: BaseTool): void;
|
|
29
|
+
removeTool(toolName: string): void;
|
|
30
|
+
extendToolPool(pool: BaseToolPool): void;
|
|
31
|
+
executeTool(ctx: BaseContext, toolName: string, llmArguments: Record<string, unknown>): Promise<string>;
|
|
32
|
+
toolExists(toolName: string): boolean;
|
|
33
|
+
toOpenAIToolSchema(): Record<string, unknown>[];
|
|
34
|
+
toAnthropicToolSchema(): Record<string, unknown>[];
|
|
35
|
+
abstract formatContext(...args: unknown[]): BaseContext;
|
|
36
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base classes for agent tools.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BaseToolPool = exports.AbstractBaseTool = void 0;
|
|
7
|
+
class AbstractBaseTool {
|
|
8
|
+
toOpenAIToolSchema() {
|
|
9
|
+
return {
|
|
10
|
+
type: 'function',
|
|
11
|
+
function: {
|
|
12
|
+
name: this.name,
|
|
13
|
+
description: this.description,
|
|
14
|
+
parameters: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: this.arguments,
|
|
17
|
+
required: this.requiredArguments,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
toAnthropicToolSchema() {
|
|
23
|
+
return {
|
|
24
|
+
name: this.name,
|
|
25
|
+
description: this.description,
|
|
26
|
+
input_schema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: this.arguments,
|
|
29
|
+
required: this.requiredArguments,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.AbstractBaseTool = AbstractBaseTool;
|
|
35
|
+
class BaseToolPool {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.tools = new Map();
|
|
38
|
+
}
|
|
39
|
+
addTool(tool) {
|
|
40
|
+
this.tools.set(tool.name, tool);
|
|
41
|
+
}
|
|
42
|
+
removeTool(toolName) {
|
|
43
|
+
this.tools.delete(toolName);
|
|
44
|
+
}
|
|
45
|
+
extendToolPool(pool) {
|
|
46
|
+
for (const [name, tool] of pool.tools.entries()) {
|
|
47
|
+
this.tools.set(name, tool);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async executeTool(ctx, toolName, llmArguments) {
|
|
51
|
+
const tool = this.tools.get(toolName);
|
|
52
|
+
if (!tool) {
|
|
53
|
+
throw new Error(`Tool '${toolName}' not found`);
|
|
54
|
+
}
|
|
55
|
+
const result = await tool.execute(ctx, llmArguments);
|
|
56
|
+
return result.trim();
|
|
57
|
+
}
|
|
58
|
+
toolExists(toolName) {
|
|
59
|
+
return this.tools.has(toolName);
|
|
60
|
+
}
|
|
61
|
+
toOpenAIToolSchema() {
|
|
62
|
+
return Array.from(this.tools.values()).map((tool) => tool.toOpenAIToolSchema());
|
|
63
|
+
}
|
|
64
|
+
toAnthropicToolSchema() {
|
|
65
|
+
return Array.from(this.tools.values()).map((tool) => tool.toAnthropicToolSchema());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.BaseToolPool = BaseToolPool;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disk tools for agent operations.
|
|
3
|
+
*/
|
|
4
|
+
import { AcontextClient } from '../client';
|
|
5
|
+
import { AbstractBaseTool, BaseContext, BaseToolPool } from './base';
|
|
6
|
+
export interface DiskContext extends BaseContext {
|
|
7
|
+
client: AcontextClient;
|
|
8
|
+
diskId: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class WriteFileTool extends AbstractBaseTool {
|
|
11
|
+
readonly name = "write_file";
|
|
12
|
+
readonly description = "Write text content to a file in the file system. Creates the file if it doesn't exist, overwrites if it does.";
|
|
13
|
+
readonly arguments: {
|
|
14
|
+
file_path: {
|
|
15
|
+
type: string;
|
|
16
|
+
description: string;
|
|
17
|
+
};
|
|
18
|
+
filename: {
|
|
19
|
+
type: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
content: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly requiredArguments: string[];
|
|
28
|
+
execute(ctx: DiskContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
export declare class ReadFileTool extends AbstractBaseTool {
|
|
31
|
+
readonly name = "read_file";
|
|
32
|
+
readonly description = "Read a text file from the file system and return its content.";
|
|
33
|
+
readonly arguments: {
|
|
34
|
+
file_path: {
|
|
35
|
+
type: string;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
filename: {
|
|
39
|
+
type: string;
|
|
40
|
+
description: string;
|
|
41
|
+
};
|
|
42
|
+
line_offset: {
|
|
43
|
+
type: string;
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
46
|
+
line_limit: {
|
|
47
|
+
type: string;
|
|
48
|
+
description: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
readonly requiredArguments: string[];
|
|
52
|
+
execute(ctx: DiskContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
53
|
+
}
|
|
54
|
+
export declare class ReplaceStringTool extends AbstractBaseTool {
|
|
55
|
+
readonly name = "replace_string";
|
|
56
|
+
readonly description = "Replace an old string with a new string in a file. Reads the file, performs the replacement, and writes it back.";
|
|
57
|
+
readonly arguments: {
|
|
58
|
+
file_path: {
|
|
59
|
+
type: string;
|
|
60
|
+
description: string;
|
|
61
|
+
};
|
|
62
|
+
filename: {
|
|
63
|
+
type: string;
|
|
64
|
+
description: string;
|
|
65
|
+
};
|
|
66
|
+
old_string: {
|
|
67
|
+
type: string;
|
|
68
|
+
description: string;
|
|
69
|
+
};
|
|
70
|
+
new_string: {
|
|
71
|
+
type: string;
|
|
72
|
+
description: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
readonly requiredArguments: string[];
|
|
76
|
+
execute(ctx: DiskContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
77
|
+
}
|
|
78
|
+
export declare class ListTool extends AbstractBaseTool {
|
|
79
|
+
readonly name = "list_artifacts";
|
|
80
|
+
readonly description = "List all files and directories in a specified path on the disk.";
|
|
81
|
+
readonly arguments: {
|
|
82
|
+
file_path: {
|
|
83
|
+
type: string;
|
|
84
|
+
description: string;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
readonly requiredArguments: string[];
|
|
88
|
+
execute(ctx: DiskContext, llmArguments: Record<string, unknown>): Promise<string>;
|
|
89
|
+
}
|
|
90
|
+
export declare class DiskToolPool extends BaseToolPool {
|
|
91
|
+
formatContext(client: AcontextClient, diskId: string): DiskContext;
|
|
92
|
+
}
|
|
93
|
+
export declare const DISK_TOOLS: DiskToolPool;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Disk tools for agent operations.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DISK_TOOLS = exports.DiskToolPool = exports.ListTool = exports.ReplaceStringTool = exports.ReadFileTool = exports.WriteFileTool = void 0;
|
|
7
|
+
const uploads_1 = require("../uploads");
|
|
8
|
+
const base_1 = require("./base");
|
|
9
|
+
function normalizePath(path) {
|
|
10
|
+
if (!path) {
|
|
11
|
+
return '/';
|
|
12
|
+
}
|
|
13
|
+
let normalized = path.startsWith('/') ? path : `/${path}`;
|
|
14
|
+
if (!normalized.endsWith('/')) {
|
|
15
|
+
normalized += '/';
|
|
16
|
+
}
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
class WriteFileTool extends base_1.AbstractBaseTool {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments);
|
|
22
|
+
this.name = 'write_file';
|
|
23
|
+
this.description = "Write text content to a file in the file system. Creates the file if it doesn't exist, overwrites if it does.";
|
|
24
|
+
this.arguments = {
|
|
25
|
+
file_path: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: "Optional folder path to organize files, e.g. '/notes/' or '/documents/'. Defaults to root '/' if not specified.",
|
|
28
|
+
},
|
|
29
|
+
filename: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
description: "Filename such as 'report.md' or 'demo.txt'.",
|
|
32
|
+
},
|
|
33
|
+
content: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description: 'Text content to write to the file.',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
this.requiredArguments = ['filename', 'content'];
|
|
39
|
+
}
|
|
40
|
+
async execute(ctx, llmArguments) {
|
|
41
|
+
const filename = llmArguments.filename;
|
|
42
|
+
const content = llmArguments.content;
|
|
43
|
+
const filePath = llmArguments.file_path || null;
|
|
44
|
+
if (!filename) {
|
|
45
|
+
throw new Error('filename is required');
|
|
46
|
+
}
|
|
47
|
+
if (!content) {
|
|
48
|
+
throw new Error('content is required');
|
|
49
|
+
}
|
|
50
|
+
const normalizedPath = normalizePath(filePath);
|
|
51
|
+
const payload = new uploads_1.FileUpload({
|
|
52
|
+
filename,
|
|
53
|
+
content: Buffer.from(content, 'utf-8'),
|
|
54
|
+
contentType: 'text/plain',
|
|
55
|
+
});
|
|
56
|
+
const artifact = await ctx.client.disks.artifacts.upsert(ctx.diskId, {
|
|
57
|
+
file: payload,
|
|
58
|
+
filePath: normalizedPath,
|
|
59
|
+
});
|
|
60
|
+
return `File '${artifact.filename}' written successfully to '${artifact.path}'`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.WriteFileTool = WriteFileTool;
|
|
64
|
+
class ReadFileTool extends base_1.AbstractBaseTool {
|
|
65
|
+
constructor() {
|
|
66
|
+
super(...arguments);
|
|
67
|
+
this.name = 'read_file';
|
|
68
|
+
this.description = 'Read a text file from the file system and return its content.';
|
|
69
|
+
this.arguments = {
|
|
70
|
+
file_path: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: "Optional directory path where the file is located, e.g. '/notes/'. Defaults to root '/' if not specified.",
|
|
73
|
+
},
|
|
74
|
+
filename: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'Filename to read.',
|
|
77
|
+
},
|
|
78
|
+
line_offset: {
|
|
79
|
+
type: 'number',
|
|
80
|
+
description: 'The line number to start reading from. Default to 0',
|
|
81
|
+
},
|
|
82
|
+
line_limit: {
|
|
83
|
+
type: 'number',
|
|
84
|
+
description: 'The maximum number of lines to return. Default to 100',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
this.requiredArguments = ['filename'];
|
|
88
|
+
}
|
|
89
|
+
async execute(ctx, llmArguments) {
|
|
90
|
+
const filename = llmArguments.filename;
|
|
91
|
+
const filePath = llmArguments.file_path || null;
|
|
92
|
+
const lineOffset = llmArguments.line_offset || 0;
|
|
93
|
+
const lineLimit = llmArguments.line_limit || 100;
|
|
94
|
+
if (!filename) {
|
|
95
|
+
throw new Error('filename is required');
|
|
96
|
+
}
|
|
97
|
+
const normalizedPath = normalizePath(filePath);
|
|
98
|
+
const result = await ctx.client.disks.artifacts.get(ctx.diskId, {
|
|
99
|
+
filePath: normalizedPath,
|
|
100
|
+
filename,
|
|
101
|
+
withContent: true,
|
|
102
|
+
});
|
|
103
|
+
if (!result.content) {
|
|
104
|
+
throw new Error('Failed to read file: server did not return content.');
|
|
105
|
+
}
|
|
106
|
+
const contentStr = result.content.raw;
|
|
107
|
+
const lines = contentStr.split('\n');
|
|
108
|
+
const lineStart = Math.min(lineOffset, Math.max(0, lines.length - 1));
|
|
109
|
+
const lineEnd = Math.min(lineStart + lineLimit, lines.length);
|
|
110
|
+
const preview = lines.slice(lineStart, lineEnd).join('\n');
|
|
111
|
+
return `[${normalizedPath}${filename} - showing L${lineStart}-${lineEnd} of ${lines.length} lines]\n${preview}`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.ReadFileTool = ReadFileTool;
|
|
115
|
+
class ReplaceStringTool extends base_1.AbstractBaseTool {
|
|
116
|
+
constructor() {
|
|
117
|
+
super(...arguments);
|
|
118
|
+
this.name = 'replace_string';
|
|
119
|
+
this.description = 'Replace an old string with a new string in a file. Reads the file, performs the replacement, and writes it back.';
|
|
120
|
+
this.arguments = {
|
|
121
|
+
file_path: {
|
|
122
|
+
type: 'string',
|
|
123
|
+
description: "Optional directory path where the file is located, e.g. '/notes/'. Defaults to root '/' if not specified.",
|
|
124
|
+
},
|
|
125
|
+
filename: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Filename to modify.',
|
|
128
|
+
},
|
|
129
|
+
old_string: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'The string to be replaced.',
|
|
132
|
+
},
|
|
133
|
+
new_string: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: 'The string to replace the old_string with.',
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
this.requiredArguments = ['filename', 'old_string', 'new_string'];
|
|
139
|
+
}
|
|
140
|
+
async execute(ctx, llmArguments) {
|
|
141
|
+
const filename = llmArguments.filename;
|
|
142
|
+
const filePath = llmArguments.file_path || null;
|
|
143
|
+
const oldString = llmArguments.old_string;
|
|
144
|
+
const newString = llmArguments.new_string;
|
|
145
|
+
if (!filename) {
|
|
146
|
+
throw new Error('filename is required');
|
|
147
|
+
}
|
|
148
|
+
if (oldString === null || oldString === undefined) {
|
|
149
|
+
throw new Error('old_string is required');
|
|
150
|
+
}
|
|
151
|
+
if (newString === null || newString === undefined) {
|
|
152
|
+
throw new Error('new_string is required');
|
|
153
|
+
}
|
|
154
|
+
const normalizedPath = normalizePath(filePath);
|
|
155
|
+
// Read the file content
|
|
156
|
+
const result = await ctx.client.disks.artifacts.get(ctx.diskId, {
|
|
157
|
+
filePath: normalizedPath,
|
|
158
|
+
filename,
|
|
159
|
+
withContent: true,
|
|
160
|
+
});
|
|
161
|
+
if (!result.content) {
|
|
162
|
+
throw new Error('Failed to read file: server did not return content.');
|
|
163
|
+
}
|
|
164
|
+
const contentStr = result.content.raw;
|
|
165
|
+
// Perform the replacement
|
|
166
|
+
if (!contentStr.includes(oldString)) {
|
|
167
|
+
return `String '${oldString}' not found in file '${filename}'`;
|
|
168
|
+
}
|
|
169
|
+
// Count occurrences before replacement
|
|
170
|
+
let replacementCount = 0;
|
|
171
|
+
let searchIndex = 0;
|
|
172
|
+
while (searchIndex < contentStr.length) {
|
|
173
|
+
const index = contentStr.indexOf(oldString, searchIndex);
|
|
174
|
+
if (index === -1) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
replacementCount++;
|
|
178
|
+
searchIndex = index + oldString.length;
|
|
179
|
+
}
|
|
180
|
+
const updatedContent = contentStr.replace(oldString, newString);
|
|
181
|
+
// Write the updated content back
|
|
182
|
+
const payload = new uploads_1.FileUpload({
|
|
183
|
+
filename,
|
|
184
|
+
content: Buffer.from(updatedContent, 'utf-8'),
|
|
185
|
+
contentType: 'text/plain',
|
|
186
|
+
});
|
|
187
|
+
await ctx.client.disks.artifacts.upsert(ctx.diskId, {
|
|
188
|
+
file: payload,
|
|
189
|
+
filePath: normalizedPath,
|
|
190
|
+
});
|
|
191
|
+
return `Found ${replacementCount} old_string in ${normalizedPath}${filename} and replaced it.`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.ReplaceStringTool = ReplaceStringTool;
|
|
195
|
+
class ListTool extends base_1.AbstractBaseTool {
|
|
196
|
+
constructor() {
|
|
197
|
+
super(...arguments);
|
|
198
|
+
this.name = 'list_artifacts';
|
|
199
|
+
this.description = 'List all files and directories in a specified path on the disk.';
|
|
200
|
+
this.arguments = {
|
|
201
|
+
file_path: {
|
|
202
|
+
type: 'string',
|
|
203
|
+
description: "Optional directory path to list, e.g. '/todo/' or '/notes/'. Root is '/'",
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
this.requiredArguments = ['file_path'];
|
|
207
|
+
}
|
|
208
|
+
async execute(ctx, llmArguments) {
|
|
209
|
+
const filePath = llmArguments.file_path;
|
|
210
|
+
const normalizedPath = normalizePath(filePath);
|
|
211
|
+
const result = await ctx.client.disks.artifacts.list(ctx.diskId, {
|
|
212
|
+
path: normalizedPath,
|
|
213
|
+
});
|
|
214
|
+
const artifactsList = result.artifacts.map((artifact) => artifact.filename);
|
|
215
|
+
if (artifactsList.length === 0 && result.directories.length === 0) {
|
|
216
|
+
return `No files or directories found in '${normalizedPath}'`;
|
|
217
|
+
}
|
|
218
|
+
const outputParts = [];
|
|
219
|
+
if (artifactsList.length > 0) {
|
|
220
|
+
outputParts.push(`Files: ${artifactsList.join(', ')}`);
|
|
221
|
+
}
|
|
222
|
+
if (result.directories.length > 0) {
|
|
223
|
+
outputParts.push(`Directories: ${result.directories.join(', ')}`);
|
|
224
|
+
}
|
|
225
|
+
const lsSect = outputParts.join('\n');
|
|
226
|
+
return `[Listing in ${normalizedPath}]\n${lsSect}`;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
exports.ListTool = ListTool;
|
|
230
|
+
class DiskToolPool extends base_1.BaseToolPool {
|
|
231
|
+
formatContext(client, diskId) {
|
|
232
|
+
return {
|
|
233
|
+
client,
|
|
234
|
+
diskId,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.DiskToolPool = DiskToolPool;
|
|
239
|
+
exports.DISK_TOOLS = new DiskToolPool();
|
|
240
|
+
exports.DISK_TOOLS.addTool(new WriteFileTool());
|
|
241
|
+
exports.DISK_TOOLS.addTool(new ReadFileTool());
|
|
242
|
+
exports.DISK_TOOLS.addTool(new ReplaceStringTool());
|
|
243
|
+
exports.DISK_TOOLS.addTool(new ListTool());
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent tools for Acontext SDK.
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./base"), exports);
|
|
21
|
+
__exportStar(require("./disk"), exports);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,3 +32,4 @@ Object.defineProperty(exports, "TransportError", { enumerable: true, get: functi
|
|
|
32
32
|
Object.defineProperty(exports, "AcontextError", { enumerable: true, get: function () { return errors_1.AcontextError; } });
|
|
33
33
|
__exportStar(require("./types"), exports);
|
|
34
34
|
__exportStar(require("./resources"), exports);
|
|
35
|
+
__exportStar(require("./agent"), exports);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Spaces endpoints.
|
|
3
3
|
*/
|
|
4
4
|
import { RequesterProtocol } from '../client-types';
|
|
5
|
-
import { ExperienceConfirmation, ListExperienceConfirmationsOutput, ListSpacesOutput,
|
|
5
|
+
import { ExperienceConfirmation, ListExperienceConfirmationsOutput, ListSpacesOutput, Space, SpaceSearchResult } from '../types';
|
|
6
6
|
export declare class SpacesAPI {
|
|
7
7
|
private requester;
|
|
8
8
|
constructor(requester: RequesterProtocol);
|
|
@@ -37,36 +37,6 @@ export declare class SpacesAPI {
|
|
|
37
37
|
semanticThreshold?: number | null;
|
|
38
38
|
maxIterations?: number | null;
|
|
39
39
|
}): Promise<SpaceSearchResult>;
|
|
40
|
-
/**
|
|
41
|
-
* Perform semantic glob (glob) search for page/folder titles.
|
|
42
|
-
*
|
|
43
|
-
* Searches specifically for page/folder titles using semantic similarity,
|
|
44
|
-
* similar to a semantic version of the glob command.
|
|
45
|
-
*
|
|
46
|
-
* @param spaceId - The UUID of the space
|
|
47
|
-
* @param options - Search options
|
|
48
|
-
* @returns List of SearchResultBlockItem objects matching the query
|
|
49
|
-
*/
|
|
50
|
-
semanticGlobal(spaceId: string, options: {
|
|
51
|
-
query: string;
|
|
52
|
-
limit?: number | null;
|
|
53
|
-
threshold?: number | null;
|
|
54
|
-
}): Promise<SearchResultBlockItem[]>;
|
|
55
|
-
/**
|
|
56
|
-
* Perform semantic grep search for content blocks.
|
|
57
|
-
*
|
|
58
|
-
* Searches through content blocks (actual text content) using semantic similarity,
|
|
59
|
-
* similar to a semantic version of the grep command.
|
|
60
|
-
*
|
|
61
|
-
* @param spaceId - The UUID of the space
|
|
62
|
-
* @param options - Search options
|
|
63
|
-
* @returns List of SearchResultBlockItem objects matching the query
|
|
64
|
-
*/
|
|
65
|
-
semanticGrep(spaceId: string, options: {
|
|
66
|
-
query: string;
|
|
67
|
-
limit?: number | null;
|
|
68
|
-
threshold?: number | null;
|
|
69
|
-
}): Promise<SearchResultBlockItem[]>;
|
|
70
40
|
/**
|
|
71
41
|
* Get all unconfirmed experiences in a space with cursor-based pagination.
|
|
72
42
|
*
|
package/dist/resources/spaces.js
CHANGED
|
@@ -66,44 +66,6 @@ class SpacesAPI {
|
|
|
66
66
|
const data = await this.requester.request('GET', `/space/${spaceId}/experience_search`, { params: Object.keys(params).length > 0 ? params : undefined });
|
|
67
67
|
return types_1.SpaceSearchResultSchema.parse(data);
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Perform semantic glob (glob) search for page/folder titles.
|
|
71
|
-
*
|
|
72
|
-
* Searches specifically for page/folder titles using semantic similarity,
|
|
73
|
-
* similar to a semantic version of the glob command.
|
|
74
|
-
*
|
|
75
|
-
* @param spaceId - The UUID of the space
|
|
76
|
-
* @param options - Search options
|
|
77
|
-
* @returns List of SearchResultBlockItem objects matching the query
|
|
78
|
-
*/
|
|
79
|
-
async semanticGlobal(spaceId, options) {
|
|
80
|
-
const params = (0, utils_1.buildParams)({
|
|
81
|
-
query: options.query,
|
|
82
|
-
limit: options.limit ?? null,
|
|
83
|
-
threshold: options.threshold ?? null,
|
|
84
|
-
});
|
|
85
|
-
const data = await this.requester.request('GET', `/space/${spaceId}/semantic_glob`, { params: Object.keys(params).length > 0 ? params : undefined });
|
|
86
|
-
return data.map((item) => types_1.SearchResultBlockItemSchema.parse(item));
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Perform semantic grep search for content blocks.
|
|
90
|
-
*
|
|
91
|
-
* Searches through content blocks (actual text content) using semantic similarity,
|
|
92
|
-
* similar to a semantic version of the grep command.
|
|
93
|
-
*
|
|
94
|
-
* @param spaceId - The UUID of the space
|
|
95
|
-
* @param options - Search options
|
|
96
|
-
* @returns List of SearchResultBlockItem objects matching the query
|
|
97
|
-
*/
|
|
98
|
-
async semanticGrep(spaceId, options) {
|
|
99
|
-
const params = (0, utils_1.buildParams)({
|
|
100
|
-
query: options.query,
|
|
101
|
-
limit: options.limit ?? null,
|
|
102
|
-
threshold: options.threshold ?? null,
|
|
103
|
-
});
|
|
104
|
-
const data = await this.requester.request('GET', `/space/${spaceId}/semantic_grep`, { params: Object.keys(params).length > 0 ? params : undefined });
|
|
105
|
-
return data.map((item) => types_1.SearchResultBlockItemSchema.parse(item));
|
|
106
|
-
}
|
|
107
69
|
/**
|
|
108
70
|
* Get all unconfirmed experiences in a space with cursor-based pagination.
|
|
109
71
|
*
|