tarsk 0.2.4 → 0.2.6
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/dist/agent/agent.js +14 -4
- package/dist/api/models.js +8 -1
- package/dist/api/prompt.js +3 -1
- package/dist/api/settings.js +16 -13
- package/dist/api/tools.js +49 -33
- package/dist/log/log.js +10 -1
- package/dist/prompt.js +4 -6
- package/dist/tools.js +2 -1
- package/package.json +3 -2
package/dist/agent/agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logWrite, logEnd, logError, logStart } from "../log/log.js";
|
|
1
|
+
import { logWrite, logEnd, logError, logStart, logStep } from "../log/log.js";
|
|
2
2
|
export async function completion(request, options) {
|
|
3
3
|
const tools = request.tools.map(tool => JSON.parse(JSON.stringify(tool.definition)) ?? []);
|
|
4
4
|
const req = {
|
|
@@ -14,8 +14,16 @@ export async function completion(request, options) {
|
|
|
14
14
|
repeating = false;
|
|
15
15
|
count++;
|
|
16
16
|
logStart({ type: `completion_request_${count}`, args: request });
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
try {
|
|
18
|
+
response = await call(options, req);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
logWrite({ type: 'completion_error', args: { error } });
|
|
22
|
+
throw new Error(`Error calling completion: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
logEnd(`completion_request_${count}`);
|
|
26
|
+
}
|
|
19
27
|
if (response.error) {
|
|
20
28
|
const message = JSON.stringify(response.error.metadata);
|
|
21
29
|
logError({ type: 'completion_error', message, args: { ...response.error } });
|
|
@@ -73,6 +81,7 @@ export async function callTools(toolCalls, request) {
|
|
|
73
81
|
logStart({ type: `tool_call_${toolName}`, args: { toolName, toolArgs } });
|
|
74
82
|
logWrite({ type: 'tool_call', args: { functionMap, toolArgs } });
|
|
75
83
|
try {
|
|
84
|
+
logStep(`Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}`);
|
|
76
85
|
const toolResponse = await functionMap[toolName](...Object.values(toolArgs));
|
|
77
86
|
newMessages.push({
|
|
78
87
|
role: 'tool',
|
|
@@ -100,7 +109,8 @@ export async function callFunction(_function, args) {
|
|
|
100
109
|
}
|
|
101
110
|
catch (error) {
|
|
102
111
|
var err = new Error();
|
|
103
|
-
logWrite({
|
|
112
|
+
logWrite({
|
|
113
|
+
type: 'test_call_error', args: { functionName: _function.name, error: `${error}` },
|
|
104
114
|
});
|
|
105
115
|
return { error: `Error calling ${_function.name}: ${error}` };
|
|
106
116
|
}
|
package/dist/api/models.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { getSettings } from "./settings.js";
|
|
1
2
|
export async function api_get_models(c) {
|
|
2
|
-
const
|
|
3
|
+
const setttings = await getSettings();
|
|
4
|
+
const res = await fetch("https://api.tarsk.io/api/v1/models", {
|
|
5
|
+
method: "GET",
|
|
6
|
+
headers: {
|
|
7
|
+
Authorization: `Bearer ${setttings.tarskApiKey}`
|
|
8
|
+
}
|
|
9
|
+
});
|
|
3
10
|
const data = await res.json();
|
|
4
11
|
const models = [];
|
|
5
12
|
for (const model of data.data) {
|
package/dist/api/prompt.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { prompt } from "../prompt.js";
|
|
2
|
-
import { logWrite } from "../log/log.js";
|
|
2
|
+
import { logAi, logUser, logWrite } from "../log/log.js";
|
|
3
3
|
export async function api_prompt(c) {
|
|
4
4
|
const body = await c.req.json();
|
|
5
5
|
logWrite({ type: 'prompt', args: body });
|
|
@@ -7,6 +7,8 @@ export async function api_prompt(c) {
|
|
|
7
7
|
if (!question) {
|
|
8
8
|
return c.json({ error: 'Prompt is required' }, 400);
|
|
9
9
|
}
|
|
10
|
+
logUser(question);
|
|
10
11
|
const answer = await prompt(question);
|
|
12
|
+
logAi('Returned answer to user');
|
|
11
13
|
return c.json({ answer });
|
|
12
14
|
}
|
package/dist/api/settings.js
CHANGED
|
@@ -1,40 +1,43 @@
|
|
|
1
1
|
import {} from "../interfaces/settings.js";
|
|
2
2
|
import { getJSON, setJSON } from "../utils/json-file.js";
|
|
3
3
|
import { httpValidationErrror as httpValidationError, isEmpty } from "./utils.js";
|
|
4
|
-
const
|
|
4
|
+
const defaultTarskURL = "https://api.tarsk.io/api/v1";
|
|
5
5
|
export const defaultModel = "meta-llama/llama-3.3-70b-instruct";
|
|
6
6
|
export async function api_get_settings(c) {
|
|
7
7
|
return c.json(getSettings());
|
|
8
8
|
}
|
|
9
9
|
export async function api_save_settings(c) {
|
|
10
10
|
const settings = await c.req.json();
|
|
11
|
-
if (settings.
|
|
12
|
-
httpValidationError("
|
|
11
|
+
if (isEmpty(settings.tarskApiKey)) {
|
|
12
|
+
httpValidationError("tarskApiKey is required");
|
|
13
13
|
}
|
|
14
|
-
if (isEmpty(settings.
|
|
15
|
-
settings.
|
|
14
|
+
if (isEmpty(settings.apiURL)) {
|
|
15
|
+
settings.apiURL = defaultTarskURL;
|
|
16
16
|
}
|
|
17
17
|
if (isEmpty(settings.defaultModel) || settings.defaultModel == 'Select a Model') {
|
|
18
18
|
settings.defaultModel = defaultModel;
|
|
19
19
|
}
|
|
20
|
-
if (settings.
|
|
21
|
-
httpValidationError("
|
|
20
|
+
if (settings.apiURL == undefined) {
|
|
21
|
+
httpValidationError("apiURL is required");
|
|
22
22
|
}
|
|
23
|
-
if (!settings.
|
|
24
|
-
httpValidationError("
|
|
23
|
+
if (!settings.apiURL.startsWith("https://")) {
|
|
24
|
+
httpValidationError("apiURL must start with https://");
|
|
25
25
|
}
|
|
26
|
-
if (settings.
|
|
27
|
-
settings.
|
|
26
|
+
if (settings.apiURL.endsWith("/")) {
|
|
27
|
+
settings.apiURL = settings.apiURL.slice(0, -1);
|
|
28
28
|
}
|
|
29
29
|
setJSON('settings', settings);
|
|
30
30
|
return c.json(getSettings());
|
|
31
31
|
}
|
|
32
32
|
export function getSettings() {
|
|
33
33
|
const defaultSettings = {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
tarskApiKey: "",
|
|
35
|
+
apiURL: defaultTarskURL,
|
|
36
36
|
defaultModel: defaultModel
|
|
37
37
|
};
|
|
38
38
|
const settings = getJSON("settings", defaultSettings);
|
|
39
|
+
if (isEmpty(settings.tarskApiKey)) {
|
|
40
|
+
settings.tarskApiKey = 'aedf201d-bf05-4fa0-912c-15a924f32c65';
|
|
41
|
+
}
|
|
39
42
|
return settings;
|
|
40
43
|
}
|
package/dist/api/tools.js
CHANGED
|
@@ -17,8 +17,8 @@ export async function api_run_tool(c) {
|
|
|
17
17
|
try {
|
|
18
18
|
const toolToRun = await getTool(tool.name);
|
|
19
19
|
const tools = await loadTools(toolJavascriptFilenames(true));
|
|
20
|
-
const d = tools.find((t) => t.name == toolToRun.name +
|
|
21
|
-
const functionName =
|
|
20
|
+
const d = tools.find((t) => t.name == toolToRun.name + ".test");
|
|
21
|
+
const functionName = "test";
|
|
22
22
|
if (!d) {
|
|
23
23
|
throw new Error(`${tool.name} not found`);
|
|
24
24
|
}
|
|
@@ -26,10 +26,10 @@ export async function api_run_tool(c) {
|
|
|
26
26
|
throw new Error(`${tool.name} function "${functionName}" not found (reload?)`);
|
|
27
27
|
}
|
|
28
28
|
const output = await callFunction(d.functionMap[functionName]);
|
|
29
|
-
return c.json({ output, js:
|
|
29
|
+
return c.json({ output, js: "test();" });
|
|
30
30
|
}
|
|
31
31
|
catch (e) {
|
|
32
|
-
return c.json({ output: `${e}`, js:
|
|
32
|
+
return c.json({ output: `${e}`, js: "" });
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
export async function api_save_tool(c) {
|
|
@@ -39,12 +39,13 @@ export async function api_save_tool(c) {
|
|
|
39
39
|
}
|
|
40
40
|
const title = tool.title;
|
|
41
41
|
const code = tool.code;
|
|
42
|
+
const description = tool.description;
|
|
42
43
|
let test = tool.test ?? "";
|
|
43
44
|
const name = tool.name.toLowerCase().replaceAll(" ", "_");
|
|
44
45
|
if (!title || !code || !name) {
|
|
45
46
|
return c.json({ error: "Title and code are required" }, 400);
|
|
46
47
|
}
|
|
47
|
-
const meta = { title, name };
|
|
48
|
+
const meta = { title, name, description };
|
|
48
49
|
const jsCode = tsBlankSpace(tool.code ?? "", (e) => {
|
|
49
50
|
logError({ type: "failed_ts_to_js_code", args: e });
|
|
50
51
|
});
|
|
@@ -64,7 +65,7 @@ export async function api_save_tool(c) {
|
|
|
64
65
|
}
|
|
65
66
|
const missingData = {
|
|
66
67
|
missingParameters: [],
|
|
67
|
-
missingFunctions: []
|
|
68
|
+
missingFunctions: [],
|
|
68
69
|
};
|
|
69
70
|
const definition = await inspectCode(srcPath, missingData);
|
|
70
71
|
logWrite({ type: "api_save_tool_check_test", args: { test } });
|
|
@@ -77,7 +78,10 @@ export async function api_save_tool(c) {
|
|
|
77
78
|
writeFileSync(testPath, test, "utf-8");
|
|
78
79
|
writeFileSync(jsCodePath, jsCode, "utf-8");
|
|
79
80
|
writeFileSync(jsTestPath, testCode, "utf-8");
|
|
80
|
-
logWrite({
|
|
81
|
+
logWrite({
|
|
82
|
+
type: "api_save_tool",
|
|
83
|
+
args: { test: testPath, code: srcPath, meta: metaPath },
|
|
84
|
+
});
|
|
81
85
|
return c.json({
|
|
82
86
|
message: `Tool saved successfully (${jsCodePath})`,
|
|
83
87
|
missingParameters: missingData.missingParameters,
|
|
@@ -147,12 +151,12 @@ export async function getTool(name) {
|
|
|
147
151
|
const test = await readOrEmpty(join(toolsFolder, `${name}.test.ts`));
|
|
148
152
|
const meta = await readOrEmpty(join(toolsFolder, `${name}.json`));
|
|
149
153
|
try {
|
|
150
|
-
const json = meta ==
|
|
151
|
-
return { code, title: json.title, name: json.name, test };
|
|
154
|
+
const json = meta == "" ? { tile: "", name: "" } : JSON.parse(meta);
|
|
155
|
+
return { code, title: json.title, name: json.name, test, description: json.description };
|
|
152
156
|
}
|
|
153
157
|
catch (e) {
|
|
154
158
|
console.error(`Failed to parse ${name}.json`, e);
|
|
155
|
-
return { code, title: "", name, test };
|
|
159
|
+
return { code, title: "", name, test, description: "" };
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
function toolsSrcFolder() {
|
|
@@ -168,36 +172,48 @@ async function readOrEmpty(filename) {
|
|
|
168
172
|
}
|
|
169
173
|
return await promises.readFile(filename, "utf-8");
|
|
170
174
|
}
|
|
175
|
+
function isNodeExported(node) {
|
|
176
|
+
const modifiers = ts.getCombinedModifierFlags(node);
|
|
177
|
+
if ((modifiers & ts.ModifierFlags.Export) == ts.ModifierFlags.Export) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
171
182
|
export async function inspectCode(filename, missingData) {
|
|
172
183
|
const code = await readOrEmpty(filename);
|
|
173
184
|
const tools = [];
|
|
174
|
-
const sourceFile = ts.createSourceFile(
|
|
185
|
+
const sourceFile = ts.createSourceFile("temp.ts", code, ts.ScriptTarget.Latest, true);
|
|
175
186
|
function visit(node) {
|
|
176
|
-
if ((ts.isFunctionDeclaration(node) ||
|
|
187
|
+
if ((ts.isFunctionDeclaration(node) ||
|
|
188
|
+
ts.isFunctionExpression(node) ||
|
|
189
|
+
ts.isArrowFunction(node)) &&
|
|
190
|
+
node.name &&
|
|
191
|
+
isNodeExported(node)) {
|
|
177
192
|
const parsed = parseJSDoc(node);
|
|
178
|
-
console.log("Parsed function", parsed);
|
|
179
193
|
const properties = {};
|
|
180
194
|
const required = [];
|
|
181
|
-
node.parameters.forEach(param => {
|
|
195
|
+
node.parameters.forEach((param) => {
|
|
182
196
|
const isOptional = !!param.questionToken || !!param.initializer;
|
|
183
197
|
if (!isOptional) {
|
|
184
198
|
required.push(param.name.getText());
|
|
185
199
|
}
|
|
186
200
|
let type = typeName(param.type?.getText());
|
|
187
201
|
if (param.type?.kind == SyntaxKind.TypeReference) {
|
|
188
|
-
type =
|
|
202
|
+
type = "object";
|
|
189
203
|
}
|
|
190
204
|
parsed.params;
|
|
191
205
|
const hasDescription = Object.keys(parsed.params).includes(param.name.getText());
|
|
192
|
-
const description = hasDescription
|
|
206
|
+
const description = hasDescription
|
|
207
|
+
? parsed.params[param.name.getText()]
|
|
208
|
+
: "";
|
|
193
209
|
if (!hasDescription) {
|
|
194
210
|
missingData.missingParameters.push(param.name.escapedText);
|
|
195
211
|
}
|
|
196
212
|
properties[param.name.getText()] = {
|
|
197
213
|
type,
|
|
198
|
-
description
|
|
214
|
+
description,
|
|
199
215
|
};
|
|
200
|
-
if (type ==
|
|
216
|
+
if (type == "array") {
|
|
201
217
|
properties[param.name.getText()].items = {
|
|
202
218
|
type: arrayType(param.type?.getText()),
|
|
203
219
|
};
|
|
@@ -208,16 +224,16 @@ export async function inspectCode(filename, missingData) {
|
|
|
208
224
|
missingData.missingFunctions.push(node.name.getText());
|
|
209
225
|
}
|
|
210
226
|
tools.push({
|
|
211
|
-
type:
|
|
227
|
+
type: "function",
|
|
212
228
|
function: {
|
|
213
|
-
name: node.name?.text ??
|
|
229
|
+
name: node.name?.text ?? "",
|
|
214
230
|
description: functionDescription,
|
|
215
231
|
parameters: {
|
|
216
|
-
type:
|
|
232
|
+
type: "object",
|
|
217
233
|
properties,
|
|
218
234
|
required,
|
|
219
|
-
}
|
|
220
|
-
}
|
|
235
|
+
},
|
|
236
|
+
},
|
|
221
237
|
});
|
|
222
238
|
}
|
|
223
239
|
ts.forEachChild(node, visit);
|
|
@@ -233,7 +249,7 @@ function parseJSDoc(node) {
|
|
|
233
249
|
description: "",
|
|
234
250
|
params: {},
|
|
235
251
|
};
|
|
236
|
-
let info =
|
|
252
|
+
let info = "";
|
|
237
253
|
for (const doc of jsDoc) {
|
|
238
254
|
if (ts.isJSDoc(doc)) {
|
|
239
255
|
if (doc.comment) {
|
|
@@ -241,15 +257,15 @@ function parseJSDoc(node) {
|
|
|
241
257
|
}
|
|
242
258
|
if (doc.tags) {
|
|
243
259
|
for (const tag of doc.tags) {
|
|
244
|
-
info +=
|
|
260
|
+
info += " " + tag.comment;
|
|
245
261
|
if (tag.kind == SyntaxKind.JSDocTag && tag.comment) {
|
|
246
262
|
let txt = tag.comment ? tag.comment.toString() : "";
|
|
247
|
-
const lines = txt.split(
|
|
263
|
+
const lines = txt.split(" ");
|
|
248
264
|
const paramName = lines[0];
|
|
249
265
|
if (txt.startsWith(paramName)) {
|
|
250
266
|
txt = txt.substring(paramName.length).trim();
|
|
251
267
|
}
|
|
252
|
-
if (txt.startsWith(
|
|
268
|
+
if (txt.startsWith("-")) {
|
|
253
269
|
txt = txt.substring(1).trim();
|
|
254
270
|
}
|
|
255
271
|
parsed.params[paramName] = txt;
|
|
@@ -261,7 +277,7 @@ function parseJSDoc(node) {
|
|
|
261
277
|
if (txt.startsWith(paramName)) {
|
|
262
278
|
txt = txt.substring(paramName.length).trim();
|
|
263
279
|
}
|
|
264
|
-
if (txt.startsWith(
|
|
280
|
+
if (txt.startsWith("-")) {
|
|
265
281
|
txt = txt.substring(1).trim();
|
|
266
282
|
}
|
|
267
283
|
parsed.params[paramName] = txt;
|
|
@@ -274,14 +290,14 @@ function parseJSDoc(node) {
|
|
|
274
290
|
}
|
|
275
291
|
function typeName(name) {
|
|
276
292
|
if (!name)
|
|
277
|
-
return
|
|
278
|
-
if (name.endsWith(
|
|
279
|
-
return
|
|
293
|
+
return "any";
|
|
294
|
+
if (name.endsWith("[]")) {
|
|
295
|
+
return "array";
|
|
280
296
|
}
|
|
281
297
|
return name;
|
|
282
298
|
}
|
|
283
299
|
function arrayType(name) {
|
|
284
300
|
if (!name)
|
|
285
|
-
return
|
|
286
|
-
return name.replace(
|
|
301
|
+
return "any";
|
|
302
|
+
return name.replace("[]", "");
|
|
287
303
|
}
|
package/dist/log/log.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let logLevel = "debug";
|
|
1
|
+
let logLevel = process.argv.slice(2).includes('debug') ? "debug" : "none";
|
|
2
2
|
export function logWrite(l, additionalMessage) {
|
|
3
3
|
if (logLevel == "none")
|
|
4
4
|
return;
|
|
@@ -28,6 +28,15 @@ export function logError(l) {
|
|
|
28
28
|
return;
|
|
29
29
|
console.error(l);
|
|
30
30
|
}
|
|
31
|
+
export function logUser(message) {
|
|
32
|
+
console.log(`[user] ${message}`);
|
|
33
|
+
}
|
|
34
|
+
export function logStep(message) {
|
|
35
|
+
console.log(` - ${message}`);
|
|
36
|
+
}
|
|
37
|
+
export function logAi(message) {
|
|
38
|
+
console.log(`[ai] ${message}`);
|
|
39
|
+
}
|
|
31
40
|
function id() {
|
|
32
41
|
return Math.random().toString().replace(".", "");
|
|
33
42
|
}
|
package/dist/prompt.js
CHANGED
|
@@ -6,12 +6,10 @@ import { isEmpty } from "./api/utils.js";
|
|
|
6
6
|
import { logWrite, logEnd, logStart } from "./log/log.js";
|
|
7
7
|
export async function prompt(content, promptOptions) {
|
|
8
8
|
const settings = await getSettings();
|
|
9
|
-
|
|
10
|
-
return "You need to set the OpenRouter API key in the settings.";
|
|
11
|
-
}
|
|
9
|
+
let apiKey = settings.tarskApiKey;
|
|
12
10
|
const options = {
|
|
13
|
-
baseUrl: settings.
|
|
14
|
-
apiKey
|
|
11
|
+
baseUrl: isEmpty(settings.apiURL) ? "https://api.tarsk.io/api/v1" : settings.apiURL,
|
|
12
|
+
apiKey,
|
|
15
13
|
};
|
|
16
14
|
const messages = [];
|
|
17
15
|
if (promptOptions?.firstMessage) {
|
|
@@ -45,7 +43,7 @@ function friendlyError(e, settings) {
|
|
|
45
43
|
return `The model "${settings.defaultModel}" does not support tool use. Please select a different model (A good default is ${defaultModel}).`;
|
|
46
44
|
}
|
|
47
45
|
if (e.startsWith("Error: No auth credentials found")) {
|
|
48
|
-
return `The
|
|
46
|
+
return `The API key is invalid. Please check your account and get a new key.`;
|
|
49
47
|
}
|
|
50
48
|
return e;
|
|
51
49
|
}
|
package/dist/tools.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logWrite, logEnd, logError, logStart } from "./log/log.js";
|
|
1
|
+
import { logWrite, logEnd, logError, logStart, logStep } from "./log/log.js";
|
|
2
2
|
import { getPathWithoutExtension, readAsJSONIfExists } from "./utils/files.js";
|
|
3
3
|
export async function loadTools(modulePaths) {
|
|
4
4
|
const tools = [];
|
|
@@ -14,6 +14,7 @@ export async function loadTools(modulePaths) {
|
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
16
|
const tool = await inspectTool(modulePath);
|
|
17
|
+
logStep(`Loaded tool "${tool.name}"`);
|
|
17
18
|
tools.push(tool);
|
|
18
19
|
}
|
|
19
20
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tarsk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"author": "WebNative LLC",
|
|
5
5
|
"description": "Tarsk is a AI tool available at https://tarsk.io",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"restart": "npm unlink tarsk && rm -rf dist && npm run build && npm link && tarsk",
|
|
13
13
|
"test": "vitest",
|
|
14
14
|
"test2": "bun test/test-get-definition.ts",
|
|
15
|
-
"dev": "tsx watch src/index.ts"
|
|
15
|
+
"dev": "tsx watch src/index.ts",
|
|
16
|
+
"dev:debug": "tsx watch src/index.ts debug=true"
|
|
16
17
|
},
|
|
17
18
|
"bin": {
|
|
18
19
|
"tarsk": "dist/index.js"
|