tarsk 0.2.5 → 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.
@@ -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 = {
@@ -81,6 +81,7 @@ export async function callTools(toolCalls, request) {
81
81
  logStart({ type: `tool_call_${toolName}`, args: { toolName, toolArgs } });
82
82
  logWrite({ type: 'tool_call', args: { functionMap, toolArgs } });
83
83
  try {
84
+ logStep(`Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}`);
84
85
  const toolResponse = await functionMap[toolName](...Object.values(toolArgs));
85
86
  newMessages.push({
86
87
  role: 'tool',
@@ -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/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 + '.test');
21
- const functionName = 'test';
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: 'test();' });
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({ type: "api_save_tool", args: { test: testPath, code: srcPath, meta: metaPath } });
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 == '' ? { tile: '', name: '' } : JSON.parse(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('temp.ts', code, ts.ScriptTarget.Latest, true);
185
+ const sourceFile = ts.createSourceFile("temp.ts", code, ts.ScriptTarget.Latest, true);
175
186
  function visit(node) {
176
- if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) && node.name) {
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 = 'object';
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 ? parsed.params[param.name.getText()] : '';
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 == 'array') {
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: 'function',
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: 'object',
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 += ' ' + tag.comment;
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 'any';
278
- if (name.endsWith('[]')) {
279
- return 'array';
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 'any';
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/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.5",
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"