tune-basic-toolset 0.1.16 → 0.1.18

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 CHANGED
@@ -20,7 +20,8 @@ Basic toolset for [Tune](https://github.com/iovdin/tune).
20
20
  - [list](#list) keep list of tasks todo (loops for LLM)
21
21
  - [sqlite](#sqlite) execute sqlite queries
22
22
  - [py](#py) run python code
23
- - [js](#js) run javascript code
23
+ - [js_node](#js_node) run javascript code in node process
24
+ - [js_ctx](#js_ctx) run javascript code that shares context with LLM
24
25
  - [turn](#turn) handoff based agent (shared context)
25
26
  - [message](#message) talk to another chat/agent (separate context)
26
27
  - [Processors](#processors)
@@ -350,10 +351,10 @@ tool_result:
350
351
  5545
351
352
  ```
352
353
 
353
- ### `js`
354
- execute javascript code
354
+ ### `js_node`
355
+ execute javascript code in nodejs
355
356
  ```chat
356
- user: @js
357
+ user: @js_node
357
358
  1234 + 4311
358
359
 
359
360
  tool_call: js {"inputType":"commonjs"}
@@ -364,6 +365,90 @@ tool_result:
364
365
 
365
366
  ```
366
367
 
368
+ ### `js_ctx`
369
+ execute javascript code but also call tools available to llm or trigger LLM response from code
370
+ It is useful when you need to trigger loops and ifs or chain few tool calls together
371
+ ```chat
372
+ user:
373
+ @js_ctx @sh
374
+
375
+ what is in my current directory?
376
+
377
+ tool_call: sh
378
+ ls
379
+ tool_result:
380
+ __pycache__
381
+ append.schema.json
382
+ append.tool.js
383
+ ... file list
384
+
385
+ user:
386
+ can you do the same using js_ctx tool?
387
+
388
+ assistant:
389
+
390
+ tool_call: js_ctx
391
+
392
+ const result = await ctx.exec("sh", { text: "ls" });
393
+ return result;
394
+
395
+ tool_result:
396
+ __pycache__
397
+ append.schema.json
398
+ append.tool.js
399
+ ....
400
+ ```
401
+
402
+
403
+ Now we can loop trough all the files and summarize its content
404
+ ```
405
+ user:
406
+ can you loop throught the .js files and summarize its content using llm?
407
+ assistant:
408
+
409
+ tool_call: js_ctx
410
+
411
+ // Get all .js files (excluding .proc.js and .schema.json files)
412
+ const files = await ctx.exec("sh", { text: "ls *.js | grep -v '.proc.js'" });
413
+ const jsFiles = files.trim().split('\n').filter(f => f.endsWith('.js'));
414
+
415
+ const summaries = [];
416
+
417
+ // Loop through each .js file
418
+ for (const file of jsFiles) {
419
+ // Read the file content
420
+ const content = await ctx.exec("sh", { text: `cat ${file}` });
421
+
422
+ // Use LLM to summarize
423
+ const summary = await ctx.file2run({
424
+ system: "@mistral-tiny You are a code analyst. Provide a brief 1-2 sentence summary of what this JavaScript file does.",
425
+ user: "Summarize this code:\n\n@code"
426
+ }, {
427
+ code: content
428
+ });
429
+
430
+ summaries.push({
431
+ file: file,
432
+ summary: summary.trim()
433
+ });
434
+ }
435
+
436
+ // Format and return results
437
+ return summaries.map(s => `**${s.file}**\n${s.summary}\n`).join('\n');
438
+
439
+ tool_result:
440
+ **append.tool.js**
441
+ This JavaScript file exports an asynchronous function that appends the given text to the end of a specified file, and returns "done" once the operation is completed.
442
+
443
+ **cmd.tool.js**
444
+ This JavaScript file exports an asynchronous function `cmd` that executes a system command (Windows-specific, using 'cmd.exe' as the shell) passed as a string, and returns the command's output or an error message containing both stderr and stdout.
445
+
446
+ **grep.tool.js**
447
+ This JavaScript module exports an asynchronous function named `grep` that reads a file (if provided) or a provided text and searches for lines matching a given regular expression. It returns the lines that match, separated by newlines. If the file is not found or the content is empty, it returns appropriate error messages.
448
+ ....
449
+
450
+ ```
451
+
367
452
  ### `turn`
368
453
  A way to switch roles when building multistep agents [read more](https://iovdin.github.io/tune/examples/multi-agent)
369
454
  ```chat
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tune-basic-toolset",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Basic toolset for tune",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -0,0 +1,13 @@
1
+ {
2
+ "description": "run js code",
3
+ "parameters": {
4
+ "type": "object",
5
+ "properties": {
6
+ "text": {
7
+ "type": "string",
8
+ "description": "js code to execute. You can use 'ctx' inside code to call tools available, e.g. await ctx.exec(\"tool_name\", { param: value }), it is also possible to call LLM from code: await ctx.file2run({ system: \"You are helpful assistant\" user: \"user request: @data \" }, { data: \"value of template variable\") to proper escape user input file2run template engine instead of javascripts ${}"
9
+ }
10
+ },
11
+ "required": ["text"]
12
+ }
13
+ }
@@ -0,0 +1,48 @@
1
+ const { parseScript } = require('esprima');
2
+ const { generate } = require('escodegen');
3
+ const vm = require('node:vm');
4
+ module.exports = async function js({ text }, ctx) {
5
+
6
+ let code = `(async () =>{\n${text}\n})()`
7
+ const ast = parseScript(code, { range: true });
8
+
9
+ const bodyAst = ast.body[ast.body.length - 1].expression.callee.body;
10
+ const lastNode = bodyAst.body[bodyAst.body.length - 1];
11
+
12
+ if (lastNode.type === 'ExpressionStatement') {
13
+ bodyAst.body[bodyAst.body.length - 1] = {
14
+ type: 'ReturnStatement',
15
+ argument: lastNode.expression
16
+ }
17
+ code = generate(ast);
18
+ }
19
+ if (bodyAst.length === 0) {
20
+ return null;
21
+ }
22
+
23
+ let logs = [];
24
+
25
+ try {
26
+ let result = vm.runInContext(code, vm.createContext({
27
+ ctx,
28
+ console: {
29
+ log: (...args) => logs.push(args),
30
+ error: (...args) => logs.push(args),
31
+ warn: (...args) => logs.push(args),
32
+ debug: (...args) => logs.push(args),
33
+ }
34
+ }))
35
+ result = await result
36
+ return result
37
+ if (typeof(result) === "object") {
38
+ result = JSON.stringify(result, null, " ")
39
+ } else {
40
+ result = String(result)
41
+ }
42
+ logs = logs.map(log => log.join(" ")).join("\n")
43
+ result = logs.trim() + "\n" + (result || "").trim()
44
+ return result.trim()
45
+ } catch (e) {
46
+ return e.stack
47
+ }
48
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Execute a given JavaScript code snippet and return the result",
2
+ "description": "Execute a given JavaScript code snippet and return the result using new node process",
3
3
  "parameters": {
4
4
  "type": "object",
5
5
  "properties": {
@@ -12,6 +12,6 @@
12
12
  "description": "save the role name to filename that keeps the current role"
13
13
  }
14
14
  },
15
- "required": ["name", "filename"]
15
+ "required": ["role", "filename"]
16
16
  }
17
17
  }
package/src/wf.tool.js CHANGED
@@ -3,5 +3,8 @@ const path = require('path');
3
3
 
4
4
  module.exports = async function writeFile({ filename, text }, ctx) {
5
5
  await ctx.write(filename, text)
6
- return `written`;
6
+ if (!text) {
7
+ return "written empty string"
8
+ }
9
+ return `written ${text.length} bytes/chars`;
7
10
  };
File without changes