tarsk 0.0.9 → 0.0.11
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/.vscode/launch.json +17 -0
- package/dist/.tarsk/.tools/books.js +5 -44
- package/dist/.tarsk/.tools/books.js.definition.json +24 -0
- package/dist/.tarsk/.tools/books.test.js +1 -1
- package/dist/.tarsk/.tools/dust.js +5 -29
- package/dist/.tarsk/.tools/dust.js.definition.json +24 -0
- package/dist/.tarsk/.tools/dust.test.js +1 -1
- package/dist/.tarsk/tools/books.test.ts +1 -1
- package/dist/.tarsk/tools/books.ts +5 -44
- package/dist/.tarsk/tools/dust.test.ts +1 -1
- package/dist/.tarsk/tools/dust.ts +5 -29
- package/dist/api/tools.js +121 -2
- package/dist/tools.js +6 -23
- package/package.json +5 -2
- package/test/test-fn-expected-result.ts +25 -0
- package/test/test-fn.ts +30 -0
- package/test/test-fn2.ts +55 -0
- package/test/test-get-definition.spec.ts +33 -0
- package/test/test-get-definition.ts +9 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"configurations": [
|
|
5
|
+
{
|
|
6
|
+
"type": "node",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"name": "Debug Tests",
|
|
9
|
+
"autoAttachChildProcesses": true,
|
|
10
|
+
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
|
11
|
+
"program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
|
|
12
|
+
"args": ["run", "${relativeFile}"],
|
|
13
|
+
"smartStep": true,
|
|
14
|
+
"console": "integratedTerminal"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Searches for books in the Project Gutenberg library based on provided search terms
|
|
3
|
+
* @param @array @required searchTerms - List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)
|
|
4
|
+
* @returns {Promise<Book[]>} A promise that resolves to an array of books matching the search terms
|
|
5
|
+
*/
|
|
3
6
|
export async function searchGutenbergBooks(searchTerms ) {
|
|
4
7
|
const searchQuery = searchTerms.join(' ');
|
|
5
8
|
const url = 'https://gutendex.com/books';
|
|
@@ -11,45 +14,3 @@ export async function searchGutenbergBooks(searchTerms )
|
|
|
11
14
|
authors: book.authors,
|
|
12
15
|
}));
|
|
13
16
|
}
|
|
14
|
-
|
|
15
|
-
export default function tools() {
|
|
16
|
-
return booksTools;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Automate via TS Morph?
|
|
20
|
-
const booksTools = [
|
|
21
|
-
{
|
|
22
|
-
type: 'function',
|
|
23
|
-
function: {
|
|
24
|
-
name: 'searchGutenbergBooks',
|
|
25
|
-
description:
|
|
26
|
-
'Search for books in the Project Gutenberg library based on specified search terms',
|
|
27
|
-
parameters: {
|
|
28
|
-
type: 'object',
|
|
29
|
-
properties: {
|
|
30
|
-
searchTerms: { // Must match argument name in function
|
|
31
|
-
type: 'array',
|
|
32
|
-
items: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
},
|
|
35
|
-
description:
|
|
36
|
-
"List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
required: ['searchTerms'],
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"function": {
|
|
5
|
+
"name": "searchGutenbergBooks",
|
|
6
|
+
"description": "Searches for books in the Project Gutenberg library based on provided search terms",
|
|
7
|
+
"parameters": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"searchTerms": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"description": "List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)",
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": [
|
|
19
|
+
"searchTerms"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
]
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Searches for burns based on provided search terms.
|
|
3
|
+
* @param {string[]} searchTerms - List of search terms to find burns.
|
|
4
|
+
* @returns {Promise<Burn[]>} A promise that resolves with an array of Burn objects.
|
|
5
|
+
*/
|
|
1
6
|
export async function searchBurns(searchTerms ) {
|
|
2
7
|
const searchQuery = searchTerms.join(' ');
|
|
3
8
|
const url = 'https://api.dust.events/data/festivals.json';
|
|
@@ -18,35 +23,6 @@ export async function searchBurns(searchTerms ) {
|
|
|
18
23
|
}));
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
export default function tools() {
|
|
22
|
-
return burnTools;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const burnTools = [
|
|
26
|
-
{
|
|
27
|
-
type: 'function',
|
|
28
|
-
function: {
|
|
29
|
-
name: 'searchBurns',
|
|
30
|
-
description:
|
|
31
|
-
"Search for regional burning man events based on specified search terms",
|
|
32
|
-
parameters: {
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties: {
|
|
35
|
-
searchTerms: { // Must match argument name in function
|
|
36
|
-
type: 'array',
|
|
37
|
-
items: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
},
|
|
40
|
-
description:
|
|
41
|
-
"List of search terms (e.g. ['snrg', 'soak'] to search for regional burns with 'snrg' or 'soak' in the title",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
required: ['searchTerms'],
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
|
|
50
26
|
;
|
|
51
27
|
|
|
52
28
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"function": {
|
|
5
|
+
"name": "searchBurns",
|
|
6
|
+
"description": "Searches for burns based on provided search terms.",
|
|
7
|
+
"parameters": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"searchTerms": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"description": "",
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": [
|
|
19
|
+
"searchTerms"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
]
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Searches for books in the Project Gutenberg library based on provided search terms
|
|
3
|
+
* @param @array @required searchTerms - List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)
|
|
4
|
+
* @returns {Promise<Book[]>} A promise that resolves to an array of books matching the search terms
|
|
5
|
+
*/
|
|
3
6
|
export async function searchGutenbergBooks(searchTerms: string[]): Promise<Book[]> {
|
|
4
7
|
const searchQuery = searchTerms.join(' ');
|
|
5
8
|
const url = 'https://gutendex.com/books';
|
|
@@ -11,45 +14,3 @@ export async function searchGutenbergBooks(searchTerms: string[]): Promise<Book[
|
|
|
11
14
|
authors: book.authors,
|
|
12
15
|
}));
|
|
13
16
|
}
|
|
14
|
-
|
|
15
|
-
export default function tools() {
|
|
16
|
-
return booksTools;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Automate via TS Morph?
|
|
20
|
-
const booksTools = [
|
|
21
|
-
{
|
|
22
|
-
type: 'function',
|
|
23
|
-
function: {
|
|
24
|
-
name: 'searchGutenbergBooks',
|
|
25
|
-
description:
|
|
26
|
-
'Search for books in the Project Gutenberg library based on specified search terms',
|
|
27
|
-
parameters: {
|
|
28
|
-
type: 'object',
|
|
29
|
-
properties: {
|
|
30
|
-
searchTerms: { // Must match argument name in function
|
|
31
|
-
type: 'array',
|
|
32
|
-
items: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
},
|
|
35
|
-
description:
|
|
36
|
-
"List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
required: ['searchTerms'],
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
interface Book {
|
|
46
|
-
id: string;
|
|
47
|
-
title: string;
|
|
48
|
-
authors: Person[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface Person {
|
|
52
|
-
birth_year?: number;
|
|
53
|
-
death_year?: number;
|
|
54
|
-
name: string;
|
|
55
|
-
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Searches for burns based on provided search terms.
|
|
3
|
+
* @param {string[]} searchTerms - List of search terms to find burns.
|
|
4
|
+
* @returns {Promise<Burn[]>} A promise that resolves with an array of Burn objects.
|
|
5
|
+
*/
|
|
1
6
|
export async function searchBurns(searchTerms: string[]): Promise<Burn[]> {
|
|
2
7
|
const searchQuery = searchTerms.join(' ');
|
|
3
8
|
const url = 'https://api.dust.events/data/festivals.json';
|
|
@@ -18,35 +23,6 @@ export async function searchBurns(searchTerms: string[]): Promise<Burn[]> {
|
|
|
18
23
|
}));
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
export default function tools() {
|
|
22
|
-
return burnTools;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const burnTools = [
|
|
26
|
-
{
|
|
27
|
-
type: 'function',
|
|
28
|
-
function: {
|
|
29
|
-
name: 'searchBurns',
|
|
30
|
-
description:
|
|
31
|
-
"Search for regional burning man events based on specified search terms",
|
|
32
|
-
parameters: {
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties: {
|
|
35
|
-
searchTerms: { // Must match argument name in function
|
|
36
|
-
type: 'array',
|
|
37
|
-
items: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
},
|
|
40
|
-
description:
|
|
41
|
-
"List of search terms (e.g. ['snrg', 'soak'] to search for regional burns with 'snrg' or 'soak' in the title",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
required: ['searchTerms'],
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
|
|
50
26
|
export interface Burn {
|
|
51
27
|
name: string
|
|
52
28
|
title: string
|
package/dist/api/tools.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, promises, readdirSync, writeFileSync, } from "fs";
|
|
2
2
|
import { extname, join } from "path";
|
|
3
|
-
import { extensionLess, tarskFolder } from "./utils.js";
|
|
3
|
+
import { extensionLess, isEmpty, tarskFolder } from "./utils.js";
|
|
4
4
|
import { logError, logWrite } from "../log/log.js";
|
|
5
5
|
import tsBlankSpace from "ts-blank-space";
|
|
6
6
|
import { loadTools } from "../tools.js";
|
|
7
7
|
import { callFunction } from "../agent/agent.js";
|
|
8
8
|
import { readAsJSONIfExists } from "../utils/files.js";
|
|
9
|
+
import ts, { SyntaxKind } from "typescript";
|
|
9
10
|
export async function api_run_tool(c) {
|
|
10
11
|
const tool = await c.req.json();
|
|
11
12
|
logWrite({ type: "api_run_tool", args: { toolName: tool.name } });
|
|
@@ -56,6 +57,7 @@ export async function api_save_tool(c) {
|
|
|
56
57
|
const filename = name.replace(/\s+/g, "_").toLowerCase();
|
|
57
58
|
const srcPath = join(toolsSrcFolder(), `${filename}.ts`);
|
|
58
59
|
const jsCodePath = join(toolsJSFolder(), `${filename}.js`);
|
|
60
|
+
const defPath = join(toolsJSFolder(), `${filename}.js.definition.json`);
|
|
59
61
|
const testPath = join(toolsSrcFolder(), `${filename}.test.ts`);
|
|
60
62
|
const jsTestPath = join(toolsJSFolder(), `${filename}.test.js`);
|
|
61
63
|
const metaPath = join(toolsSrcFolder(), `${filename}.json`);
|
|
@@ -63,9 +65,16 @@ export async function api_save_tool(c) {
|
|
|
63
65
|
if (currentMeta) {
|
|
64
66
|
meta.revision = (meta.revision ?? 1) + 1;
|
|
65
67
|
}
|
|
68
|
+
const missingData = {
|
|
69
|
+
missingParameters: [],
|
|
70
|
+
missingFunctions: []
|
|
71
|
+
};
|
|
72
|
+
const definition = await inspectCode(srcPath, missingData);
|
|
66
73
|
// Save the Typescript
|
|
67
74
|
writeFileSync(srcPath, code, "utf-8");
|
|
68
75
|
writeFileSync(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
76
|
+
// Write the function definition
|
|
77
|
+
writeFileSync(defPath, JSON.stringify(definition, null, 2), "utf-8");
|
|
69
78
|
// Save the Test
|
|
70
79
|
writeFileSync(testPath, test, "utf-8");
|
|
71
80
|
// Save the Javascript Code
|
|
@@ -73,7 +82,10 @@ export async function api_save_tool(c) {
|
|
|
73
82
|
// Save the Javascript Test
|
|
74
83
|
writeFileSync(jsTestPath, testCode, "utf-8");
|
|
75
84
|
logWrite({ type: "api_save_tool", args: { test: testPath, code: srcPath, meta: metaPath } });
|
|
76
|
-
return c.json({ message: `Tool saved successfully (${jsCodePath})
|
|
85
|
+
return c.json({ message: `Tool saved successfully (${jsCodePath})`,
|
|
86
|
+
missingParameters: missingData.missingParameters,
|
|
87
|
+
missingFunctions: missingData.missingFunctions,
|
|
88
|
+
});
|
|
77
89
|
}
|
|
78
90
|
// Get the tool with code
|
|
79
91
|
export async function api_get_tool(c) {
|
|
@@ -166,3 +178,110 @@ async function readOrEmpty(filename) {
|
|
|
166
178
|
}
|
|
167
179
|
return await promises.readFile(filename, "utf-8");
|
|
168
180
|
}
|
|
181
|
+
export async function inspectCode(filename, missingData) {
|
|
182
|
+
const code = await readOrEmpty(filename);
|
|
183
|
+
const tools = [];
|
|
184
|
+
const sourceFile = ts.createSourceFile('temp.ts', code, ts.ScriptTarget.Latest, true);
|
|
185
|
+
function visit(node) {
|
|
186
|
+
if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) && node.name) {
|
|
187
|
+
const parsed = parseJSDoc(node);
|
|
188
|
+
console.log("Parsed function", parsed);
|
|
189
|
+
const properties = {};
|
|
190
|
+
const required = [];
|
|
191
|
+
node.parameters.forEach(param => {
|
|
192
|
+
const isOptional = !!param.questionToken || !!param.initializer;
|
|
193
|
+
if (!isOptional) {
|
|
194
|
+
required.push(param.name.getText());
|
|
195
|
+
}
|
|
196
|
+
let type = typeName(param.type?.getText());
|
|
197
|
+
if (param.type?.kind == SyntaxKind.TypeReference) {
|
|
198
|
+
type = 'object';
|
|
199
|
+
}
|
|
200
|
+
parsed.params;
|
|
201
|
+
const hasDescription = Object.keys(parsed.params).includes(param.name.getText());
|
|
202
|
+
const description = hasDescription ? parsed.params[param.name.getText()] : '';
|
|
203
|
+
if (!hasDescription) {
|
|
204
|
+
missingData.missingParameters.push(param.name.escapedText);
|
|
205
|
+
}
|
|
206
|
+
properties[param.name.getText()] = {
|
|
207
|
+
type,
|
|
208
|
+
description
|
|
209
|
+
};
|
|
210
|
+
if (type == 'array') {
|
|
211
|
+
properties[param.name.getText()].items = {
|
|
212
|
+
type: arrayType(param.type?.getText()),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const functionDescription = parsed.description;
|
|
217
|
+
if (isEmpty(functionDescription)) {
|
|
218
|
+
missingData.missingFunctions.push(node.name.getText());
|
|
219
|
+
}
|
|
220
|
+
tools.push({
|
|
221
|
+
type: 'function',
|
|
222
|
+
function: {
|
|
223
|
+
name: node.name?.text ?? '',
|
|
224
|
+
description: functionDescription,
|
|
225
|
+
parameters: {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties,
|
|
228
|
+
required,
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
ts.forEachChild(node, visit);
|
|
234
|
+
}
|
|
235
|
+
visit(sourceFile);
|
|
236
|
+
return tools;
|
|
237
|
+
}
|
|
238
|
+
function parseJSDoc(node) {
|
|
239
|
+
const functionName = node.name?.getText();
|
|
240
|
+
const jsDoc = ts.getJSDocCommentsAndTags(node);
|
|
241
|
+
const parsed = {
|
|
242
|
+
functionName,
|
|
243
|
+
description: "",
|
|
244
|
+
params: {},
|
|
245
|
+
};
|
|
246
|
+
let info = '';
|
|
247
|
+
for (const doc of jsDoc) {
|
|
248
|
+
if (ts.isJSDoc(doc)) {
|
|
249
|
+
if (doc.comment) {
|
|
250
|
+
parsed.description = doc.comment.toString();
|
|
251
|
+
}
|
|
252
|
+
if (doc.tags) {
|
|
253
|
+
for (const tag of doc.tags) {
|
|
254
|
+
info += ' ' + tag.comment;
|
|
255
|
+
// if (ts.isJSDocPropertyTag(tag)) {
|
|
256
|
+
if (tag.kind == 327) {
|
|
257
|
+
let txt = tag.comment ? tag.comment.toString() : "";
|
|
258
|
+
const lines = txt.split(' ');
|
|
259
|
+
const paramName = lines[0];
|
|
260
|
+
if (txt.startsWith(paramName)) {
|
|
261
|
+
txt = txt.substring(paramName.length).trim();
|
|
262
|
+
if (txt.startsWith('-')) {
|
|
263
|
+
txt = txt.substring(1).trim();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//parsed.params[paramName] = paramDesc;
|
|
267
|
+
parsed.params[paramName] = txt;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return parsed;
|
|
274
|
+
}
|
|
275
|
+
function typeName(name) {
|
|
276
|
+
if (!name)
|
|
277
|
+
return 'any';
|
|
278
|
+
if (name.endsWith('[]')) {
|
|
279
|
+
return 'array';
|
|
280
|
+
}
|
|
281
|
+
return name;
|
|
282
|
+
}
|
|
283
|
+
function arrayType(name) {
|
|
284
|
+
if (!name)
|
|
285
|
+
return 'any';
|
|
286
|
+
return name.replace('[]', '');
|
|
287
|
+
}
|
package/dist/tools.js
CHANGED
|
@@ -19,24 +19,6 @@ export async function loadTools(modulePaths) {
|
|
|
19
19
|
}
|
|
20
20
|
return tools;
|
|
21
21
|
}
|
|
22
|
-
// async function importFromMemory(moduleCode: string) {
|
|
23
|
-
// const module = new Function(
|
|
24
|
-
// "exports",
|
|
25
|
-
// "module",
|
|
26
|
-
// "require",
|
|
27
|
-
// "__filename",
|
|
28
|
-
// "__dirname",
|
|
29
|
-
// moduleCode
|
|
30
|
-
// );
|
|
31
|
-
// const exports = {};
|
|
32
|
-
// const moduleObj = { exports: exports };
|
|
33
|
-
// module(exports, moduleObj, require, null, null);
|
|
34
|
-
// return moduleObj.exports;
|
|
35
|
-
// }
|
|
36
|
-
// async function importModule(code: string) {
|
|
37
|
-
// const myModule = await importFromMemory(code);
|
|
38
|
-
// //console.log(myModule.hello()); // Output: Hello from memory!
|
|
39
|
-
// }
|
|
40
22
|
function findMetaData(modulePath) {
|
|
41
23
|
// Load the meta data: its in the toolsfolder not the .tools folder
|
|
42
24
|
let metaPath = (getPathWithoutExtension(modulePath) + ".json").replace('.tools', 'tools');
|
|
@@ -61,9 +43,6 @@ async function inspectTool(modulePath) {
|
|
|
61
43
|
path: modulePath,
|
|
62
44
|
revision: undefined
|
|
63
45
|
};
|
|
64
|
-
// When 'key' is no longer referenced and garbage collected,
|
|
65
|
-
// the module './myModule.js' associated with it in 'weakModules'
|
|
66
|
-
// will also be eligible for garbage collection.
|
|
67
46
|
logStart({ type: "load_tool", args: { modulePath } }, `The modulePath is "${modulePath}"`);
|
|
68
47
|
try {
|
|
69
48
|
const meta = findMetaData(modulePath);
|
|
@@ -89,7 +68,7 @@ async function inspectTool(modulePath) {
|
|
|
89
68
|
try {
|
|
90
69
|
// This is the definition needed for the tool for the agent (TODO: Generate this)
|
|
91
70
|
if (!isTest) {
|
|
92
|
-
result.definition =
|
|
71
|
+
result.definition = getDefinition(modulePath);
|
|
93
72
|
}
|
|
94
73
|
}
|
|
95
74
|
catch (e) {
|
|
@@ -99,10 +78,14 @@ async function inspectTool(modulePath) {
|
|
|
99
78
|
}
|
|
100
79
|
catch (e) {
|
|
101
80
|
logError({ type: "load_tool_error", args: e });
|
|
81
|
+
throw new Error(`load_tool_error ${modulePath}: ${e}`);
|
|
102
82
|
}
|
|
103
83
|
finally {
|
|
104
84
|
logEnd("load_tool");
|
|
105
85
|
logWrite({ type: 'load_tool', args: { result } });
|
|
106
86
|
}
|
|
107
|
-
|
|
87
|
+
}
|
|
88
|
+
function getDefinition(modulePath) {
|
|
89
|
+
const filename = modulePath + '.definition.json';
|
|
90
|
+
return readAsJSONIfExists(filename);
|
|
108
91
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tarsk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"author": "WebNative LLC",
|
|
5
5
|
"description": "Tarsk is a AI tool available at https://tarsk.io",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"start": "npm run build && npm link && tarsk",
|
|
11
11
|
"restart": "npm unlink tarsk && rm -rf dist && npm run build && npm link && tarsk",
|
|
12
12
|
"publish": "npm run build && npm publish",
|
|
13
|
+
"test": "vitest",
|
|
14
|
+
"test2": "bun test/test-get-definition.ts",
|
|
13
15
|
"dev": "tsx watch src/index.ts"
|
|
14
16
|
},
|
|
15
17
|
"bin": {
|
|
@@ -23,6 +25,7 @@
|
|
|
23
25
|
},
|
|
24
26
|
"devDependencies": {
|
|
25
27
|
"@types/node": "^20.11.17",
|
|
26
|
-
"tsx": "^4.7.1"
|
|
28
|
+
"tsx": "^4.7.1",
|
|
29
|
+
"vitest": "^3.1.2"
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Automate via TS Morph?
|
|
2
|
+
const booksTools = [
|
|
3
|
+
{
|
|
4
|
+
type: 'function',
|
|
5
|
+
function: {
|
|
6
|
+
name: 'searchGutenbergBooks',
|
|
7
|
+
description:
|
|
8
|
+
'Search for books in the Project Gutenberg library based on specified search terms',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
searchTerms: { // Must match argument name in function
|
|
13
|
+
type: 'array',
|
|
14
|
+
items: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
},
|
|
17
|
+
description:
|
|
18
|
+
"List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ['searchTerms'],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
package/test/test-fn.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Searches for books in the Project Gutenberg library based on provided search terms
|
|
3
|
+
* @param @array @required searchTerms - List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)
|
|
4
|
+
* @param @object @required book - The book object to search for
|
|
5
|
+
* @returns {Promise<Book[]>} A promise that resolves to an array of books matching the search terms
|
|
6
|
+
*/
|
|
7
|
+
export async function searchGutenbergBooks(searchTerms: string[], count: number, book: Book): Promise<Book[]> {
|
|
8
|
+
const searchQuery = searchTerms ? searchTerms.join(' ') : '';
|
|
9
|
+
const url = 'https://gutendex.com/books';
|
|
10
|
+
const response = await fetch(`${url}?search=${searchQuery}`);
|
|
11
|
+
const data = await response.json();
|
|
12
|
+
return data.results.map((book: any) => ({
|
|
13
|
+
id: book.id,
|
|
14
|
+
title: book.title,
|
|
15
|
+
authors: book.authors,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Book {
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
authors: Person[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface Person {
|
|
26
|
+
birth_year?: number;
|
|
27
|
+
death_year?: number;
|
|
28
|
+
name: string;
|
|
29
|
+
}
|
|
30
|
+
|
package/test/test-fn2.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Searches for burns based on provided search terms.
|
|
3
|
+
* @param {string[]} searchTerms - List of search terms to find burns.
|
|
4
|
+
* @returns {Promise<Burn[]>} A promise that resolves with an array of Burn objects.
|
|
5
|
+
*/
|
|
6
|
+
export async function searchBurns(searchTerms: string[]): Promise<Burn[]> {
|
|
7
|
+
const searchQuery = searchTerms.join(' ');
|
|
8
|
+
const url = 'https://api.dust.events/data/festivals.json';
|
|
9
|
+
const response = await fetch(`${url}`);
|
|
10
|
+
let data = await response.json();
|
|
11
|
+
data = data.filter((b) => b.active);
|
|
12
|
+
return data.map((burn: any) => ({
|
|
13
|
+
name: burn.name,
|
|
14
|
+
title: burn.title,
|
|
15
|
+
year: burn.year,
|
|
16
|
+
startDate: burn.start,
|
|
17
|
+
endDate: burn.end,
|
|
18
|
+
lat: burn.lat,
|
|
19
|
+
long: burn.long,
|
|
20
|
+
timeZone: burn.timeZone,
|
|
21
|
+
region: burn.region,
|
|
22
|
+
website: burn.website
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Burn {
|
|
27
|
+
name: string
|
|
28
|
+
title: string
|
|
29
|
+
year: string
|
|
30
|
+
active: boolean
|
|
31
|
+
id: string
|
|
32
|
+
uid: number
|
|
33
|
+
start: string
|
|
34
|
+
end: string
|
|
35
|
+
lat: any
|
|
36
|
+
long: any
|
|
37
|
+
imageUrl?: string
|
|
38
|
+
timeZone: string
|
|
39
|
+
mapDirection: number
|
|
40
|
+
mastodonHandle: string
|
|
41
|
+
rssFeed: string
|
|
42
|
+
inboxEmail: string
|
|
43
|
+
region: string
|
|
44
|
+
website: string
|
|
45
|
+
unknownDates: boolean
|
|
46
|
+
volunteeripateSubdomain: string
|
|
47
|
+
volunteeripateIdentifier: string
|
|
48
|
+
pin_size_multiplier: number
|
|
49
|
+
camp_registration: boolean
|
|
50
|
+
event_registration: boolean
|
|
51
|
+
pin: string
|
|
52
|
+
directions?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { expect, test } from 'vitest'
|
|
2
|
+
import { inspectCode, MissingData } from "../src/api/tools.js";
|
|
3
|
+
import { Tool } from '../src/agent/interfaces.js';
|
|
4
|
+
|
|
5
|
+
test('function definition generation works', async () => {
|
|
6
|
+
const missingData: MissingData = {
|
|
7
|
+
missingFunctions: [],
|
|
8
|
+
missingParameters: [],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const tools: Tool[] = await inspectCode('./test/test-fn.ts', missingData);
|
|
12
|
+
|
|
13
|
+
// One comment is missing
|
|
14
|
+
expect(missingData.missingParameters.length).toBe(1);
|
|
15
|
+
// One comment is missing
|
|
16
|
+
expect(missingData.missingParameters[0]).toBe('count');
|
|
17
|
+
expect(tools[0].function.description).toBe('Searches for books in the Project Gutenberg library based on provided search terms');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('function definition generation works style 2', async () => {
|
|
21
|
+
const missingData: MissingData = {
|
|
22
|
+
missingFunctions: [],
|
|
23
|
+
missingParameters: [],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const tools: Tool[] = await inspectCode('./test/test-fn2.ts', missingData);
|
|
27
|
+
|
|
28
|
+
// One comment is missing
|
|
29
|
+
expect(missingData.missingParameters.length).toBe(1);
|
|
30
|
+
// One comment is missing
|
|
31
|
+
expect(missingData.missingParameters[0]).toBe('count');
|
|
32
|
+
expect(tools[0].function.description).toBe('');
|
|
33
|
+
});
|