tune-basic-toolset 0.1.8 → 0.1.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/README.md +71 -33
- package/package.json +5 -1
- package/src/grep.schema.json +25 -0
- package/src/grep.tool.js +16 -0
- package/src/message.schema.json +1 -1
- package/src/message.tool.js +4 -12
- package/src/mock.proc.js +1 -0
- package/src/patch.tool.js +9 -6
- package/src/proc.proc.js +1 -3
- package/src/sh.tool.js +24 -3
- package/src/turn.tool.js +0 -2
- package/src/websearch.schema.json +23 -0
- package/src/websearch.tool.chat +3 -0
package/README.md
CHANGED
|
@@ -13,14 +13,16 @@ Basic toolset for [Tune](https://github.com/iovdin/tune).
|
|
|
13
13
|
- [sh](#sh) execute shell command
|
|
14
14
|
- [cmd](#cmd) execute Windows cmd command
|
|
15
15
|
- [powershell](#powershell) execute PowerShell command
|
|
16
|
+
- [grep](#grep) search for patterns in text or files
|
|
16
17
|
- [osa](#osa) manage reminders/notes/calendar (AppleScript/macOS)
|
|
17
18
|
- [jina_r](#jina_r) fetch webpage content
|
|
18
|
-
- [
|
|
19
|
+
- [websearch](#websearch) search the web with web-enabled llms
|
|
19
20
|
- [list](#list) keep list of tasks todo (loops for LLM)
|
|
20
21
|
- [sqlite](#sqlite) execute sqlite queries
|
|
21
22
|
- [py](#py) run python code
|
|
22
23
|
- [js](#js) run javascript code
|
|
23
|
-
- [
|
|
24
|
+
- [turn](#turn) handoff based agent (shared context)
|
|
25
|
+
- [message](#message) talk to another chat/agent (separate context)
|
|
24
26
|
- [Processors](#processors)
|
|
25
27
|
- [proc](#proc) converts tool to processor
|
|
26
28
|
- [shp](#shp) include shell command output
|
|
@@ -175,6 +177,22 @@ TotalPhysicalMemory : 17179869184
|
|
|
175
177
|
CsProcessors : {Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz}
|
|
176
178
|
```
|
|
177
179
|
|
|
180
|
+
### `grep`
|
|
181
|
+
Search for patterns in text or files using regular expressions
|
|
182
|
+
```chat
|
|
183
|
+
user: @grep
|
|
184
|
+
find all lines containing "TODO" in myfile.js
|
|
185
|
+
tool_call: grep {"filename":"myfile.js","regex":"TODO"}
|
|
186
|
+
tool_result:
|
|
187
|
+
// TODO: refactor this function
|
|
188
|
+
// TODO: add error handling
|
|
189
|
+
|
|
190
|
+
system:
|
|
191
|
+
TODOS:
|
|
192
|
+
@{ myfile.js | proc grep regex=TODO }
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
|
|
178
196
|
### `osa`
|
|
179
197
|
AppleScript tool, manage reminders, notes, calendar etc on osx
|
|
180
198
|
```chat
|
|
@@ -219,41 +237,26 @@ Tune is a versatile toolkit designed for developers and users to effectively int
|
|
|
219
237
|
<cut for brevity>
|
|
220
238
|
```
|
|
221
239
|
|
|
240
|
+
### `websearch`
|
|
241
|
+
Search the web with web enabled llms
|
|
242
|
+
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`).
|
|
222
243
|
|
|
223
|
-
### `turn`
|
|
224
|
-
A way to switch roles when building multistep agents [read more](https://iovdin.github.io/tune/examples/multi-agent)
|
|
225
244
|
```chat
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
You switch turns between 'thinker' and 'player' agent.
|
|
229
|
-
Current agent stored in agent.txt file
|
|
230
|
-
'player' always plays first
|
|
231
|
-
|
|
232
|
-
@@agent|init
|
|
233
|
-
assistant:
|
|
234
|
-
Is it a living thing?
|
|
245
|
+
user: @websearch
|
|
246
|
+
latest ai news
|
|
235
247
|
|
|
236
|
-
|
|
237
|
-
tool_result: now it is turn of thinker to reply
|
|
238
|
-
|
|
239
|
-
assistant:
|
|
240
|
-
No.
|
|
241
|
-
|
|
242
|
-
tool_call: turn {"role":"player","filename":"agent.txt"}
|
|
243
|
-
tool_result: now it is turn of player to reply
|
|
244
|
-
|
|
245
|
-
assistant:
|
|
246
|
-
Is it something that can be used indoors?
|
|
247
|
-
|
|
248
|
-
tool_call: turn {"role":"thinker","filename":"agent.txt"}
|
|
249
|
-
tool_result: now it is turn of thinker to reply
|
|
248
|
+
assistant:
|
|
250
249
|
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
tool_call: websearch {"model":"perplexity/sonar"}
|
|
251
|
+
latest AI news
|
|
252
|
+
tool_result:
|
|
253
|
+
The latest AI news in October 2025 highlights significant investments, new projects, policy developments, and advances across various sectors:
|
|
253
254
|
|
|
254
|
-
|
|
255
|
+
- 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].
|
|
255
256
|
```
|
|
256
257
|
|
|
258
|
+
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.
|
|
259
|
+
|
|
257
260
|
### `list`
|
|
258
261
|
Keep list of tasks to do
|
|
259
262
|
|
|
@@ -353,6 +356,41 @@ tool_result:
|
|
|
353
356
|
|
|
354
357
|
```
|
|
355
358
|
|
|
359
|
+
### `turn`
|
|
360
|
+
A way to switch roles when building multistep agents [read more](https://iovdin.github.io/tune/examples/multi-agent)
|
|
361
|
+
```chat
|
|
362
|
+
system: @gpt-4o
|
|
363
|
+
@{ turn | curry filename=agent.txt}
|
|
364
|
+
You're playing 20 questions game.
|
|
365
|
+
You switch turns between 'thinker' and 'player' agent.
|
|
366
|
+
'player' always plays first
|
|
367
|
+
|
|
368
|
+
@@agent|init
|
|
369
|
+
assistant:
|
|
370
|
+
Is it a living thing?
|
|
371
|
+
|
|
372
|
+
tool_call: turn {"name": "thinker"}
|
|
373
|
+
tool_result:
|
|
374
|
+
now it is turn of thinker to reply
|
|
375
|
+
|
|
376
|
+
assistant:
|
|
377
|
+
No.
|
|
378
|
+
|
|
379
|
+
tool_call: turn {"role":"player"}
|
|
380
|
+
tool_result: now it is turn of player to reply
|
|
381
|
+
|
|
382
|
+
assistant:
|
|
383
|
+
Is it something that can be used indoors?
|
|
384
|
+
|
|
385
|
+
tool_call: turn {"role":"thinker"}
|
|
386
|
+
tool_result: now it is turn of thinker to reply
|
|
387
|
+
|
|
388
|
+
assistant:
|
|
389
|
+
Yes.
|
|
390
|
+
|
|
391
|
+
...
|
|
392
|
+
```
|
|
393
|
+
|
|
356
394
|
### `message`
|
|
357
395
|
Talk to another chat/agent via tool call.
|
|
358
396
|
Orchestrate or evaulate other agents/chats.
|
|
@@ -362,19 +400,19 @@ system:
|
|
|
362
400
|
Your goal is to talk to Groot at `groot.prompt` system prompt
|
|
363
401
|
and try to make him say anything but 'I am Groot'
|
|
364
402
|
|
|
365
|
-
tool_call: message {"filename":"groot.chat","system":"groot.prompt"}
|
|
403
|
+
tool_call: message {"filename":"groot.chat","system":"@@groot.prompt"}
|
|
366
404
|
Hello Groot! How are you feeling today?
|
|
367
405
|
|
|
368
406
|
tool_result:
|
|
369
407
|
I am Groot!
|
|
370
408
|
|
|
371
|
-
tool_call: message {"filename":"groot.chat"
|
|
409
|
+
tool_call: message {"filename":"groot.chat"}
|
|
372
410
|
What do you think about trees?
|
|
373
411
|
|
|
374
412
|
tool_result:
|
|
375
413
|
I am Groot!
|
|
376
414
|
|
|
377
|
-
tool_call: message {"filename":"groot.chat"
|
|
415
|
+
tool_call: message {"filename":"groot.chat"}
|
|
378
416
|
Can you tell me a joke?
|
|
379
417
|
|
|
380
418
|
tool_result:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tune-basic-toolset",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Basic toolset for tune",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
"README.md",
|
|
9
9
|
"LICENSE"
|
|
10
10
|
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "node test/index.js",
|
|
13
|
+
"test:watch": "node --watch test/index.js"
|
|
14
|
+
},
|
|
11
15
|
"keywords": [
|
|
12
16
|
"ai",
|
|
13
17
|
"chat",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "filter lines with regex",
|
|
3
|
+
"parameters": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"text": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"description": "Text to be filtered"
|
|
9
|
+
},
|
|
10
|
+
"filename": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "if text is not set, filename will be read and filtered"
|
|
13
|
+
},
|
|
14
|
+
"regex": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "js regex to filter lines in file or text. passed as first arguments to new RegExp "
|
|
17
|
+
},
|
|
18
|
+
"regex_flags": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "flags to be passed to new RegExp constructor"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"required": ["regex"]
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/grep.tool.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = async function grep({filename, text, regex, regex_flags}, ctx) {
|
|
2
|
+
if (!text && filename) {
|
|
3
|
+
const n = await ctx.resolve(filename)
|
|
4
|
+
if (!n)
|
|
5
|
+
return `${filename} not found`
|
|
6
|
+
|
|
7
|
+
text = await n.read()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!text) {
|
|
11
|
+
return "content is empty"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const r = new RegExp(regex, regex_flags)
|
|
15
|
+
return text.split(/\r?\n/).filter(line => r.test(line)).join("\n").replaceAll("@", "\\@")
|
|
16
|
+
}
|
package/src/message.schema.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"system": {
|
|
11
11
|
"type": "string",
|
|
12
|
-
"description": "
|
|
12
|
+
"description": "System prompt, to include file use @@path/to/file or @@file syntax"
|
|
13
13
|
},
|
|
14
14
|
"text": {
|
|
15
15
|
"type": "string",
|
package/src/message.tool.js
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
module.exports = async function message({ filename, system, text, stop }, ctx) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
chat = `system: @@${system}`
|
|
1
|
+
module.exports = async function message({ filename, system, text, stop, save, ...args }, ctx) {
|
|
2
|
+
if (typeof(save) === "undefined") {
|
|
3
|
+
save = !!filename
|
|
5
4
|
}
|
|
6
|
-
|
|
7
|
-
const messages = await ctx.text2run(chat, {stop: "assistant" })
|
|
8
|
-
chat = `${chat}\n${ctx.msg2text(messages, true)}`
|
|
9
|
-
await ctx.write(filename, chat)
|
|
10
|
-
if (messages.length) {
|
|
11
|
-
return messages[messages.length - 1].content
|
|
12
|
-
}
|
|
13
|
-
return ""
|
|
5
|
+
return ctx.file2run({ stop, filename, system, user: text, save }, args, ctx)
|
|
14
6
|
}
|
package/src/mock.proc.js
CHANGED
package/src/patch.tool.js
CHANGED
|
@@ -5,7 +5,9 @@ const fs = require('fs').promises;
|
|
|
5
5
|
|
|
6
6
|
module.exports = async function patch({ text, filename }, ctx) {
|
|
7
7
|
// Regex to match each patch block
|
|
8
|
-
|
|
8
|
+
// Be lenient about the number of conflict marker characters because some
|
|
9
|
+
// environments may trim one or more > or < characters.
|
|
10
|
+
const patchRegex = /<{6,}\s*ORIGINAL[^\n]*\n([\s\S]*?)=+\n([\s\S]*?)>{6,}\s*UPDATED[^\n]*(?:\n|$)/g;
|
|
9
11
|
const patches = [];
|
|
10
12
|
let match;
|
|
11
13
|
|
|
@@ -23,10 +25,11 @@ module.exports = async function patch({ text, filename }, ctx) {
|
|
|
23
25
|
let fileContent = await ctx.read(filename);
|
|
24
26
|
|
|
25
27
|
for (const { oldPart, newPart } of patches) {
|
|
26
|
-
// Escape regex special chars in oldPart
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// Escape regex special chars in oldPart.
|
|
29
|
+
// Do NOT relax all whitespace to \s+; that can swallow preceding newlines.
|
|
30
|
+
// Only normalize line endings so CRLF in patches can match LF in files.
|
|
31
|
+
let escaped = oldPart.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32
|
+
escaped = escaped.replace(/\r?\n/g, "\\r?\\n");
|
|
30
33
|
const oldRegex = new RegExp(escaped, "g");
|
|
31
34
|
|
|
32
35
|
// Perform replacement using a function to avoid replacement string ambiguities
|
|
@@ -35,4 +38,4 @@ module.exports = async function patch({ text, filename }, ctx) {
|
|
|
35
38
|
|
|
36
39
|
await ctx.write(filename, fileContent);
|
|
37
40
|
return "patched";
|
|
38
|
-
};
|
|
41
|
+
};
|
package/src/proc.proc.js
CHANGED
|
@@ -14,8 +14,6 @@ module.exports = async function proc(node, args, ctx) {
|
|
|
14
14
|
|
|
15
15
|
const tool = await ctx.resolve(toolName, { "type": "tool" })
|
|
16
16
|
|
|
17
|
-
console.log(params)
|
|
18
|
-
|
|
19
17
|
if (!tool || tool.type !== "tool") {
|
|
20
18
|
throw Error(`tool '${toolName}' not found`)
|
|
21
19
|
}
|
|
@@ -46,7 +44,7 @@ function parseCommandLine(input) {
|
|
|
46
44
|
// 1) Parse leading alphanumeric command
|
|
47
45
|
skipWS();
|
|
48
46
|
const cmdStart = i;
|
|
49
|
-
while (i < len && /[A-Za-z0-
|
|
47
|
+
while (i < len && /[A-Za-z0-9_\-]/.test(s[i])) i++;
|
|
50
48
|
const command = s.slice(cmdStart, i);
|
|
51
49
|
if (!command) return [null, {}];
|
|
52
50
|
|
package/src/sh.tool.js
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
|
-
const util = require('util');
|
|
3
2
|
|
|
4
3
|
module.exports = async function sh({ text }) {
|
|
5
4
|
let result = "";
|
|
6
5
|
try {
|
|
7
|
-
|
|
6
|
+
// Increase maxBuffer to reduce ERR_CHILD_PROCESS_STDIO_MAXBUFFER risk on large outputs
|
|
7
|
+
result = execSync(text, { encoding: "utf8", maxBuffer: 10 * 1024 * 1024 });
|
|
8
8
|
} catch (e) {
|
|
9
|
-
|
|
9
|
+
const stderr = e && typeof e.stderr !== "undefined" ? String(e.stderr || "") : "";
|
|
10
|
+
const stdout = e && typeof e.stdout !== "undefined" ? String(e.stdout || "") : "";
|
|
11
|
+
|
|
12
|
+
if (stderr || stdout) {
|
|
13
|
+
// Process started and produced output
|
|
14
|
+
result = stderr + stdout;
|
|
15
|
+
} else {
|
|
16
|
+
// Spawn/configuration errors or cases without stdio
|
|
17
|
+
const parts = [];
|
|
18
|
+
if (e && e.code) parts.push(`code=${e.code}`);
|
|
19
|
+
if (e && typeof e.status === "number") parts.push(`exit=${e.status}`);
|
|
20
|
+
if (e && e.signal) parts.push(`signal=${e.signal}`);
|
|
21
|
+
if (e && e.errno) parts.push(`errno=${e.errno}`);
|
|
22
|
+
if (e && e.path) parts.push(`path=${e.path}`);
|
|
23
|
+
const meta = parts.length ? ` (${parts.join(", ")})` : "";
|
|
24
|
+
|
|
25
|
+
if (e && e.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") {
|
|
26
|
+
result = `Command output exceeded maxBuffer${meta}.`;
|
|
27
|
+
} else {
|
|
28
|
+
result = `Failed to spawn/execute command${meta}: ${e && e.message ? e.message : String(e)}`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
10
31
|
}
|
|
11
32
|
return (result || "").replaceAll("@", "\\@");
|
|
12
33
|
};
|
package/src/turn.tool.js
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Does a websearch using llm",
|
|
3
|
+
"parameters": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"text": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"description": "web search query"
|
|
9
|
+
},
|
|
10
|
+
"model": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"enum": [
|
|
13
|
+
"perplexity/sonar",
|
|
14
|
+
"perplexity/sonar-pro",
|
|
15
|
+
"gpt-4o-search-preview",
|
|
16
|
+
"gpt-4o-mini-search-preview"
|
|
17
|
+
],
|
|
18
|
+
"description": "model to do websearch, default is perplexity/sonar"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"required": ["text"]
|
|
22
|
+
}
|
|
23
|
+
}
|