tune-basic-toolset
Version:
Basic toolset for tune
790 lines (618 loc) • 18.3 kB
Markdown
# Tune basic toolset
Basic toolset for [Tune](https://github.com/iovdin/tune).
##### Index
- [Setup](#setup)
- [Text Editor](#text-editor)
- [JavaScript Project](#javascript-project)
- [Tools](#tools)
- [rf](#rf) read file
- [wf](#wf) write file
- [patch](#patch) patch file
- [append](#append) append to file
- [sh](#sh) execute shell command locally and remotely
- [cmd](#cmd) execute Windows cmd command
- [powershell](#powershell) execute PowerShell command
- [grep](#grep) search for patterns in text or files
- [osa](#osa) manage reminders/notes/calendar (AppleScript/macOS)
- [jina_r](#jina_r) fetch webpage content
- [websearch](#websearch) search the web with web-enabled llms
- [list](#list) keep list of tasks todo (loops for LLM)
- [sqlite](#sqlite) execute sqlite queries
- [py](#py) run python code
- [js_node](#js_node) run javascript code in node process
- [js_ctx](#js_ctx) run javascript code that shares context with LLM
- [turn](#turn) handoff based agent (shared context)
- [message](#message) talk to another chat/agent (separate context)
- [Processors](#processors)
- [proc](#proc) converts tool to processor
- [init](#init) set initial value
- [json_format](#json_format) make LLM respond with JSON
- [log](#log) save LLM payload
- [mock](#mock) set variables inline
- [linenum](#linenum) prepend line numbers
- [text](#text) convert any variable to text variable
- [resolve](#resolve) resolve a variable
- [prop](#prop) set additional properties of LLM
- [head](#head) take first N lines of a file
- [tail](#tail) take last N lines of a file or LLM payload
- [slice](#slice) take lines from <start> to <finish> of a file
- [random](#random) random selection, sampling, shuffling, uniform ranges
- [curry](#curry) change a tool by setting a parameter
## Setup
### Text Editor
Install in your `~/.tune` folder:
```bash
cd ~/.tune
npm install tune-basic-toolset
```
Add to `~/.tune/default.ctx.js`:
```javascript
const basics = require('tune-basic-toolset')
module.exports = [
...
basics()
...
]
```
### JavaScript Project
```bash
npm install tune-basic-toolset tune-sdk
```
```javascript
const tune = require('tune-sdk')
const basics = require('tune-basic-toolset')
const ctx = tune.makeContext(
basics({ expose: ["rf", "wf"], mount: "tools" })
)
```
## Tools
[Tools](https://iovdin.github.io/tune/template-language/tools) is a function that llm can run on your local machine or server
### `rf`
Read file
```chat
user: @rf
can you read README.md?
tool_call: rf {"filename":"README.md"}
tool_result:
@README.md
```
It accepts an optional `linenum` parameter that prepends line numbers to the file (useful for patching).
### `wf`
Write to a file
```chat
user: @wf
make a hello world javascript
tool_call: wf {"filename":"helloWorld.js"}
console.log('Hello, World!');
tool_result:
written
```
### `patch`
```chat
user: @patch
translate "hello world" in helloWorld.js to dutch
tool_call: patch {"filename":"helloWorld.js"}
<<<<<<< ORIGINAL
console.log('Hello, World!');
=======
console.log('Hallo, Wereld!');
>>>>>>> UPDATED
tool_result:
patched
```
### `append`
```chat
user: @append
Add a todo that i want to buy a car and go to the moon
tool_call: append {"filename":"todo.md"}
- buy a car
- fly to the moon
tool_result:
appended
```
### `sh`
Execute shell command locally or with ssh
```chat
user: @sh
find with ripgrep where echo is used
tool_call: sh
rg 'echo' ./
tool_result:
./README.md: echo: "You are echo, you print everything back",
./README.md: const text = "s: \@echo\nu: hello world";
./tools/echo.txt:you are echo, you print everything back
./tools/README.md:* `echo.txt` - to debug variable expansions and context
user:
check contents directory on root\@host.com
assistant:
tool_call: sh {"host": "root@host.com"}
ls
tool_result:
file1
file2
```
### `cmd`
Execute Windows cmd command
```chat
user: @cmd
list all files in current directory
tool_call: cmd
dir
tool_result:
Volume in drive C has no label.
Volume Serial Number is 1234-5678
Directory of C:\project
12/01/2023 10:30 AM <DIR> .
12/01/2023 10:30 AM <DIR> ..
12/01/2023 09:15 AM 1,024 package.json
12/01/2023 09:20 AM <DIR> src
1 File(s) 1,024 bytes
3 Dir(s) 15,728,640 bytes free
```
### `powershell`
Execute PowerShell command
```chat
user: @powershell
get system information
tool_call: powershell
Get-ComputerInfo | Select-Object WindowsProductName, TotalPhysicalMemory, CsProcessors
tool_result:
WindowsProductName : Windows 11 Pro
TotalPhysicalMemory : 17179869184
CsProcessors : {Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz}
```
### `grep`
Search for patterns in text or files using regular expressions
```chat
user: @grep
find all lines containing "TODO" in myfile.js
tool_call: grep {"filename":"myfile.js","regex":"TODO"}
tool_result:
// TODO: refactor this function
// TODO: add error handling
system:
TODOS:
@{ myfile.js | proc grep regex=TODO }
```
### `osa`
AppleScript tool, manage reminders, notes, calendar etc on osx
```chat
system: @osa @gpt-4.1
you're personal assistant with access to osx apps
like reminder, calendar etc
user:
can you remind me in 2 hours that i have meeting with jack
assistant:
tool_call: osa
tell application "Reminders" to make new reminder with properties {name:"Meeting with Jack", remind me date:(current date) + 2 * hours}
tool_result:
reminder id x-apple-reminder://849EA642-B7E0-4E16-94AA-B50FF1BC282D
```
### `jina_r`
Fetch webpage content with [jina reader](https://jina.ai/reader) api.
Works without an API key up to a limited rate. Set JINA_KEY in .env for higher rate limits.
```chat
user: @jina_r
take https://iovdin.github.io/tune/ page content
and put it into `home` directory
then make short summary
tool_call: jina_r {"url":"https://iovdin.github.io/tune/","filename":"home/tune_page_content.md"}
tool_result:
@home/tune_page_content.md
assistant:
The content from the "Tune" page has been successfully retrieved and saved into the `home/tune_page_content.md` file. Below is a short summary of the page:
---
**Summary of Tune - Your Everyday LLM Toolkit:**
Tune is a versatile toolkit designed for developers and users to effectively interact with Large Language Models (LLMs). It allows users to chat with AI, build applications, and create AI agents in a simple manner.
<cut for brevity>
```
### `websearch`
Search the web with web enabled llms
Supports search with `perplexity/sonar`, `perplexity/sonar-pro`, `gpt-4o-search-preview`, `gpt-4o-mini-search-preview` models via the `model` parameter (defaults to `perplexity/sonar`).
```chat
user: @websearch
latest ai news
assistant:
tool_call: websearch {"model":"perplexity/sonar"}
latest AI news
tool_result:
The latest AI news in October 2025 highlights significant investments, new projects, policy developments, and advances across various sectors:
- Major companies including Microsoft, Google, Nvidia, OpenAI, Salesforce, and CoreWeave have pledged over £31 billion in capital expenditure focused on AI data centers and infrastructure upgrades[1].
```
The websearch tool provides up-to-date information by querying the web through AI-powered search models. You can specify different Perplexity models like `perplexity/sonar-pro` for more advanced searches.
### `list`
Keep list of tasks to do
```chat
system: @list
You manage todo list in file todo.txt
user:
Today i need to refactor xyz
and then release abc
assistant:
tool_call: list {"filename":"todo.txt"}
todo - refactor xyz
todo - release abc
tool_result:
list updated
user:
ok, i've finished refactoring xyz
assistant:
tool_call: list {"filename":"todo.txt"}
done - refactor xyz
tool_result:
list updated
```
### `sqlite`
execut sqlite queries with sqlite shell
```chat
user:
@sqlite
create a simple todo table in db.sqlite and fill it with fake data
assistant:
tool_call: sqlite {"filename":"db.sqlite"}
CREATE TABLE todo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task TEXT NOT NULL,
status TEXT CHECK(status IN ('pending', 'completed')) NOT NULL DEFAULT 'pending',
due_date DATE
);
INSERT INTO todo (task, status, due_date) VALUES
('Buy groceries', 'pending', '2024-05-01'),
('Finish project report', 'pending', '2024-05-03'),
('Book flight tickets', 'completed', '2024-04-25'),
('Call plumber', 'pending', '2024-04-30'),
('Schedule meeting with team', 'completed', '2024-04-20');
tool_result:
user:
check pending tasks
assistant:
tool_call: sqlite {"filename":"db.sqlite","format":"json"}
SELECT * FROM todo WHERE status = 'pending';
tool_result:
[{"id":1,"task":"Buy groceries","status":"pending","due_date":"2024-05-01"},
{"id":2,"task":"Finish project report","status":"pending","due_date":"2024-05-03"},
{"id":4,"task":"Call plumber","status":"pending","due_date":"2024-04-30"}]
```
### `py`
execute python code
```chat
user: @py
1234 + 4311
tool_call: py
1234 + 4311
tool_result:
5545
```
### `js_node`
execute javascript code in nodejs
```chat
user: @js_node
1234 + 4311
tool_call: js {"inputType":"commonjs"}
1234 + 4311
tool_result:
5545
```
### `js_ctx`
execute javascript code but also call tools available to llm or trigger LLM response from code
It is useful when you need to trigger loops and ifs or chain few tool calls together
```chat
user:
@js_ctx @sh
what is in my current directory?
tool_call: sh
ls
tool_result:
__pycache__
append.schema.json
append.tool.js
... file list
user:
can you do the same using js_ctx tool?
assistant:
tool_call: js_ctx
const result = await ctx.exec("sh", { text: "ls" });
return result;
tool_result:
__pycache__
append.schema.json
append.tool.js
....
```
Now we can loop trough all the files and summarize its content
```
user:
can you loop throught the .js files and summarize its content using llm?
assistant:
tool_call: js_ctx
// Get all .js files (excluding .proc.js and .schema.json files)
const files = await ctx.exec("sh", { text: "ls *.js | grep -v '.proc.js'" });
const jsFiles = files.trim().split('\n').filter(f => f.endsWith('.js'));
const summaries = [];
// Loop through each .js file
for (const file of jsFiles) {
// Read the file content
const content = await ctx.exec("sh", { text: `cat ${file}` });
// Use LLM to summarize
const summary = await ctx.file2run({
system: "@mistral-tiny You are a code analyst. Provide a brief 1-2 sentence summary of what this JavaScript file does.",
user: "Summarize this code:\n\n@code"
}, {
code: content
});
summaries.push({
file: file,
summary: summary.trim()
});
}
// Format and return results
return summaries.map(s => `**${s.file}**\n${s.summary}\n`).join('\n');
tool_result:
**append.tool.js**
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.
**cmd.tool.js**
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.
**grep.tool.js**
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.
....
```
### `turn`
A way to switch roles when building multistep agents [read more](https://iovdin.github.io/tune/examples/multi-agent)
```chat
system: @gpt-4o
@{ turn | curry filename=agent.txt}
You're playing 20 questions game.
You switch turns between 'thinker' and 'player' agent.
'player' always plays first
@@agent|init
assistant:
Is it a living thing?
tool_call: turn {"name": "thinker"}
tool_result:
now it is turn of thinker to reply
assistant:
No.
tool_call: turn {"role":"player"}
tool_result: now it is turn of player to reply
assistant:
Is it something that can be used indoors?
tool_call: turn {"role":"thinker"}
tool_result: now it is turn of thinker to reply
assistant:
Yes.
...
```
### `message`
Talk to another chat/agent via tool call.
Orchestrate or evaulate other agents/chats.
```chat
system:
@message
Your goal is to talk to Groot at `groot.prompt` system prompt
and try to make him say anything but 'I am Groot'
tool_call: message {"filename":"groot.chat","system":"@@groot.prompt"}
Hello Groot! How are you feeling today?
tool_result:
I am Groot!
tool_call: message {"filename":"groot.chat"}
What do you think about trees?
tool_result:
I am Groot!
tool_call: message {"filename":"groot.chat"}
Can you tell me a joke?
tool_result:
Sure! Why did the tree go to the dentist?
Because it had a root canal!
```
The content of `groot.chat` is then:
```chat
system: @@groot.prompt
user:
Hello Groot! How are you feeling today?
assistant:
I am Groot!
user:
What do you think about trees?
assistant:
I am Groot!
user:
Can you tell me a joke?
assistant:
Sure! Why did the tree go to the dentist?
Because it had a root canal!
```
## Processors
[Processors](https://iovdin.github.io/tune/template-language/processors) is a way to modify variable or insert new ones into chat.
### `proc`
converts any tool to a processor
``` chat
system:
include project file list to system prompt
@{| proc sh git ls-files }
execute script with sqlite on db `db.sqlite` and insert result
@{ script.sql | proc sqlite filename=db.sqlite }
execut python script text="384 * 123" and insert back result
@{| proc py 384 * 123 }
```
### `init`
Set default value for non set variables
```chat
system:
@memory|init
if memory does not exist the chat will fail
```
### `json_format`
Set llm response format to json [read more](https://platform.openai.com/docs/guides/structured-outputs?api-mode=chat).
Without arguments it sets
```json
"response_format": {
"type": "json_object"
}
```
```chat
system:
@{ gpt-4o | json_format }
please reply in json format:
{ "message": "Your reply"}
user:
hi how are you?
assistant:
{ "message": "I'm just a virtual assistant, so I don't have feelings, but I'm here and ready to help you! How can I assist you today?" }
```
with argument it sets
```json
"response_format": {
"type": "json_schema",
"json_schema": { "schema": "<contents of the referenced schema file>" }
}
```
```chat
system:
@{ gpt-4o | json_format path/to/schema.json }
```
### `log`
Save LLM payload to a json or chat file, used for debugging
```chat
system:
@{ gpt-4o | log path/to/log.json }
@{ gpt-4o | log path/to/log.chat }
```
### `mock`
Set variables inline in chat.
```
system: @{| mock hello=world }
@echo
user:
@hello
assistant:
world
```
### `linenum`
Prepend line numbers to a file content.
Useful when patching file.
```chat
system:
@echo
user:
@{ helloWorld | linenum }
assistant:
1 | console.log('Hello, World!');
```
### `text`
Treat special files (`.ctx.js`, `.llm.js`, `.tool.js`) like text
```chat
system:
@echo
user:
content
@rf.tool.mjs
assistant:
content
user:
content
@{ rf.tool.mjs | text}
assistant:
content
import { promises as fs } from 'fs';
import { relative, dirname } from 'path'
....
```
### `resolve`
Given filename resolve it and include
```chat
@{ filename | resolve }
```
see `examples/queryimage` example
### `prop`
set additional properties for llm
```chat
system:
@{ o3-mini | prop reasoning_effort=low temperature=2.0 }
```
### `head`
Take first *N* lines of text from a file or variable. Default is 20 lines.
```chat
user:
@{ filename.txt | head 10 } # first 10 lines
```
### `tail`
Take last *N* lines of text from a file or variable. Default is 20 lines.
```chat
user:
@{ filename.txt | tail 15 } # last 15 lines
```
You can limit llm request context with tail like
```chat
system:
@{ gpt-4.1 | tail 2 } # take last 2 messages from the chat + system message
user:
1
assistant:
2
user:
3
assistant:
4
```
### `slice`
Extract a range of lines from a file or variable.
```chat
user:
@{ filename.txt | slice 5 15 } # lines 5 to 15 inclusive
@{ filename.txt | slice 10 } # from line 10 to end
@{ filename.txt | slice -10 -1 } # last 10 lines
@{ filename.txt | slice -20 } # last 20 lines
@{ filename.txt | slice 1 20 } # first 20 lines (like head 20)
```
### `random`
Random selection, sampling, shuffling, and uniform number generation.
Use cases:
```chat
user:
@{| random a b c d }
@{| random choice a b c d }
@{| random "choice 1" "choice 2" }
@{| random choice @path/to/file.txt } # choose 1 line from a file
@{| random choice 2..30 } # choose 1 from range
@{| random choice -2.5..7.5 } # floats
@{| random choices 3 a b c d } # pick 3 with replacment
@{| random choices 5 @file.txt } # pick 5 lines from file.txt
@{| random sample 3 a b c d } # pick 3 without replacement
@{| random sample 10 1..5 } # will return 5 unique numbers
@{| random shuffle a b c d }
@{| random shuffle 1..10 }
@{| random uniform 1..10 } # integers
@{| random uniform -2.5..7.5 } # floats
@{| random uniform 10 20 } # two-number form
```
Notes:
- Quotes are respected for tokens with spaces.
- Files referenced as @file are expanded to non-empty trimmed lines.
- Integer ranges like a..b can be mixed with discrete values and files; float ranges cannot be mixed in lists.
- sample and shuffle require a discrete set; float ranges are not supported there.
- choices and sample output multiple lines (one item per line).
### `curry`
Modify a tool by setting parameter or name or description.
Narrow possible usage of a tool so that LLM wont mess up
```chat
user:
@{ sh | curry text=ls $name=ls_cwd}
what is in my current directory?
assistant:
tool_call: ls_cwd
tool_result:
node_modules
package.json
README.md
src
user:
@{ sqlite | curry filename=db.sqlite format=table}
what tables are outhere?
user:
@{ list | curry filename=mylist.todo $name=todo }
create sample todo list
tool_call: todo
[] - Create sample todo list
tool_result:
list updated
```