tune-sdk 0.2.4 → 0.2.5

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.
Files changed (79) hide show
  1. package/.github/workflows/publish.yml +27 -0
  2. package/README.md +2 -1
  3. package/package.json +1 -1
  4. package/tools/README.md +0 -636
  5. package/tools/append.schema.json +0 -17
  6. package/tools/append.tool.mjs +0 -5
  7. package/tools/brave.schema.json +0 -13
  8. package/tools/brave.tool.mjs +0 -32
  9. package/tools/claude.txt +0 -1
  10. package/tools/clipboard.txt +0 -1
  11. package/tools/default.llm.js +0 -2
  12. package/tools/dev.txt +0 -6
  13. package/tools/echo.txt +0 -1
  14. package/tools/editor-filename.chat +0 -10
  15. package/tools/gemini-dev.txt +0 -7
  16. package/tools/gemini25.txt +0 -1
  17. package/tools/gemini_files.schema.json +0 -13
  18. package/tools/gemini_files.tool.mjs +0 -204
  19. package/tools/gemini_ocr.schema.json +0 -21
  20. package/tools/gemini_ocr.tool.mjs +0 -211
  21. package/tools/gemini_tts.schema.json +0 -59
  22. package/tools/gemini_tts.tool.mjs +0 -175
  23. package/tools/gemini_veo.schema.json +0 -12
  24. package/tools/gemini_veo.tool.mjs +0 -233
  25. package/tools/groq_whisper.schema.json +0 -48
  26. package/tools/groq_whisper.tool.mjs +0 -59
  27. package/tools/head.proc.js +0 -24
  28. package/tools/init.proc.js +0 -19
  29. package/tools/jina_r.schema.json +0 -21
  30. package/tools/jina_r.tool.mjs +0 -27
  31. package/tools/js.schema.json +0 -19
  32. package/tools/js.tool.mjs +0 -60
  33. package/tools/json_format.proc.mjs +0 -22
  34. package/tools/linenum.proc.js +0 -21
  35. package/tools/list.schema.json +0 -19
  36. package/tools/list.tool.mjs +0 -20
  37. package/tools/llm-utils.js +0 -150
  38. package/tools/log.proc.js +0 -15
  39. package/tools/mcp.proc.mjs +0 -174
  40. package/tools/message.schema.json +0 -21
  41. package/tools/message.tool.js +0 -14
  42. package/tools/mock.proc.js +0 -35
  43. package/tools/nu.schema.json +0 -13
  44. package/tools/nu.tool.mjs +0 -14
  45. package/tools/openai.js +0 -27
  46. package/tools/openai_imgen.schema.json +0 -35
  47. package/tools/openai_imgen.tool.mjs +0 -83
  48. package/tools/openai_stt.schema.json +0 -49
  49. package/tools/openai_stt.tool.mjs +0 -66
  50. package/tools/openai_tts.schema.json +0 -26
  51. package/tools/openai_tts.tool.mjs +0 -26
  52. package/tools/osa.schema.json +0 -13
  53. package/tools/osa.tool.mjs +0 -12
  54. package/tools/package.json +0 -7
  55. package/tools/patch.schema.json +0 -17
  56. package/tools/patch.tool.mjs +0 -38
  57. package/tools/prop.proc.mjs +0 -34
  58. package/tools/py.schema.json +0 -17
  59. package/tools/py.tool.py +0 -22
  60. package/tools/queryimage.schema.json +0 -17
  61. package/tools/queryimage.tool.chat +0 -4
  62. package/tools/resolve.proc.js +0 -10
  63. package/tools/rf.schema.json +0 -17
  64. package/tools/rf.tool.mjs +0 -21
  65. package/tools/schema.schema.json +0 -13
  66. package/tools/schema.tool.chat +0 -81
  67. package/tools/sh.schema.json +0 -13
  68. package/tools/sh.tool.mjs +0 -12
  69. package/tools/short.txt +0 -1
  70. package/tools/shp.proc.mjs +0 -31
  71. package/tools/slice.proc.js +0 -55
  72. package/tools/tail.proc.js +0 -35
  73. package/tools/text.proc.js +0 -13
  74. package/tools/turn.schema.json +0 -17
  75. package/tools/turn.tool.mjs +0 -8
  76. package/tools/wf.schema.json +0 -17
  77. package/tools/wf.tool.mjs +0 -16
  78. package/tools/yandex_tts.schema.json +0 -41
  79. package/tools/yandex_tts.tool.mjs +0 -31
@@ -1,83 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- export default async function openaiImgen({ text, filename, images, quality, size }, ctx) {
5
- const key = await ctx.read('OPENAI_KEY');
6
- let body;
7
- let headers = {
8
- 'Authorization': `Bearer ${key}`
9
- };
10
- let apiUrl;
11
- switch(size) {
12
- case "square":
13
- size = "1024x1024";
14
- break;
15
- case "landscape":
16
- size = "1536x1024";
17
- break;
18
- case "portrait":
19
- size = "1024x1536";
20
- break;
21
- }
22
-
23
- // If images exist and length > 0, use FormData and the edits endpoint
24
- if (images && images.length > 0) {
25
- apiUrl = 'https://api.openai.com/v1/images/edits';
26
- const formData = new FormData();
27
- formData.append('model', 'gpt-image-1');
28
- formData.append('prompt', text);
29
- formData.append('quality', quality || "auto");
30
-
31
-
32
- // For each image, read its contents and attach it to the form
33
- for (let i = 0; i < images.length; i++) {
34
- const imageContent = await ctx.read(images[i]);
35
- // Attach image content with the filename
36
- const ext = path.extname(images[i])
37
- let mimeType = 'application/octet-stream'
38
- switch (ext) {
39
- case ".png":
40
- mimeType = "image/png";
41
- break;
42
- case ".jpg":
43
- mimeType = "image/jpeg";
44
- break
45
- case ".webp":
46
- mimeType = "image/webp";
47
- break
48
-
49
- }
50
- formData.append('image', new Blob([imageContent], { type: mimeType }), images[i]);
51
- }
52
- body = formData;
53
- // Note: Do not manually set the Content-Type header. FormData will handle it.
54
- } else {
55
- // No images provided: use JSON payload and the generations endpoint
56
- apiUrl = 'https://api.openai.com/v1/images/generations';
57
- body = JSON.stringify({
58
- model: 'gpt-image-1',
59
- prompt: text,
60
- quality: quality || "auto",
61
- size: size || "auto"
62
- });
63
- headers['Content-Type'] = 'application/json';
64
- }
65
-
66
- const response = await fetch(apiUrl, {
67
- method: 'POST',
68
- headers,
69
- body
70
- });
71
-
72
- if (!response.ok) {
73
- const { error } = await response.json();
74
- throw new Error(`Error: ${response.status} ${response.statusText}\n${error.message}`);
75
- }
76
-
77
- const res = await response.json();
78
-
79
- // Assuming the API returns the image data in a b64_json field
80
- const data = res.data[0].b64_json;
81
- await ctx.write(filename, Buffer.from(data, 'base64'));
82
- return 'image generated';
83
- }
@@ -1,49 +0,0 @@
1
- {
2
- "description": "Convert audio file to text using OpenAI's transcription API with advanced options",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "file": {
7
- "type": "string",
8
- "description": "Path or identifier of the audio file to transcribe"
9
- },
10
- "model": {
11
- "type": "string",
12
- "description": "Model to use for transcription",
13
- "default": "gpt-4o-transcribe"
14
- },
15
- "language": {
16
- "type": "string",
17
- "description": "Language spoken in the audio, optional"
18
- },
19
- "prompt": {
20
- "type": "string",
21
- "description": "Prompt to guide transcription, optional"
22
- },
23
- "response_format": {
24
- "type": "string",
25
- "enum": ["json", "verbose_json", "text"],
26
- "description": "Format of the transcription response",
27
- "default": "json"
28
- },
29
- "temperature": {
30
- "type": "number",
31
- "description": "Sampling temperature for transcription",
32
- "default": 0
33
- },
34
- "timestamp_granularities": {
35
- "type": "array",
36
- "items": {
37
- "type": "string"
38
- },
39
- "description": "Timestamp granularities for detailed transcription, supported only for whisper-1 model with verbose_json response_format"
40
- },
41
- "stream": {
42
- "type": "boolean",
43
- "description": "Whether to return a streaming response",
44
- "default": false
45
- }
46
- },
47
- "required": ["file"]
48
- }
49
- }
@@ -1,66 +0,0 @@
1
- import fs from 'fs';
2
-
3
- export default async function openaiSTT({
4
- file,
5
- model = "gpt-4o-transcribe",
6
- language,
7
- prompt,
8
- response_format = "json",
9
- temperature = 0,
10
- timestamp_granularities,
11
- stream = false
12
- }, ctx) {
13
- const key = await ctx.read("OPENAI_KEY");
14
-
15
- if (!file) {
16
- throw new Error('File parameter is required');
17
- }
18
-
19
- const formData = new FormData();
20
-
21
- // Add file
22
- const fileBlob = await fs.openAsBlob(file);
23
- formData.append('file', fileBlob, file);
24
-
25
- // Add required model
26
- formData.append('model', model);
27
-
28
- // Add optional parameters
29
- if (language) formData.append('language', language);
30
- if (prompt) formData.append('prompt', prompt);
31
- if (response_format) formData.append('response_format', response_format);
32
- if (temperature !== undefined) formData.append('temperature', temperature.toString());
33
- if (stream) formData.append('stream', stream.toString());
34
-
35
- // Timestamp granularities (only supported for whisper-1 with verbose_json)
36
- if (timestamp_granularities && model === 'whisper-1' && response_format === 'verbose_json') {
37
- timestamp_granularities.forEach(granularity => {
38
- formData.append('timestamp_granularities[]', granularity);
39
- });
40
- }
41
-
42
- const response = await fetch("https://api.openai.com/v1/audio/transcriptions", {
43
- method: "POST",
44
- headers: {
45
- "Authorization": `Bearer ${key}`,
46
- },
47
- body: formData,
48
- });
49
-
50
- if (!response.ok) {
51
- const errorText = await response.text();
52
- throw new Error(`Error: ${response.status} ${response.statusText}\n${errorText}`);
53
- }
54
-
55
- if (stream) {
56
- // For streaming responses, return the response stream
57
- return response.body;
58
- } else {
59
- // For non-streaming responses, parse JSON or return text based on response_format
60
- if (response_format === 'text') {
61
- return await response.text();
62
- } else {
63
- return await response.json();
64
- }
65
- }
66
- }
@@ -1,26 +0,0 @@
1
- {
2
- "description": "Fetch audio from OpenAI's TTS",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "Text input to convert to speech"
9
- },
10
- "voice": {
11
- "type": "string",
12
- "enum": ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
13
- "description": "Voice type to use for TTS"
14
- },
15
- "filename": {
16
- "type": "string",
17
- "description": "mp3 filename to save the audio to"
18
- },
19
- "instructions": {
20
- "type": "string",
21
- "description": "describe a way to create a speech, example:\n voice: Warm, relaxed, and friendly, with a steady cowboy drawl that feels approachable.\n\nPunctuation: Light and natural, with gentle pauses that create a conversational rhythm without feeling rushed.\n\nDelivery: Smooth and easygoing, with a laid-back pace that reassures the listener while keeping things clear.\n\nPhrasing: Simple, direct, and folksy, using casual, familiar language to make technical support feel more personable.\n\nTone: Lighthearted and welcoming, with a calm confidence that puts the caller at ease."
22
- }
23
- },
24
- "required": ["text", "voice", "filename"]
25
- }
26
- }
@@ -1,26 +0,0 @@
1
- import fs from 'fs';
2
- export default async function openaiTTS({ text, voice, instructions, filename }, ctx) {
3
- const key = await ctx.read("OPENAI_KEY");
4
- const response = await fetch("https://api.openai.com/v1/audio/speech", {
5
- method: "POST",
6
- headers: {
7
- "Authorization": `Bearer ${key}`,
8
- "Content-Type": "application/json",
9
- },
10
- body: JSON.stringify({
11
- "model": "gpt-4o-mini-tts",
12
- input: text,
13
- instructions,
14
- voice: voice
15
- }),
16
- });
17
-
18
-
19
- if (!response.ok) {
20
- const { error } = await response.json()
21
- throw new Error(`Error: ${response.status} ${response.statusText}\n${error.message}`);
22
- }
23
- const buf = await response.arrayBuffer();
24
- await ctx.write(filename, Buffer.from(buf));
25
- return "speech generated"
26
- }
@@ -1,13 +0,0 @@
1
- {
2
- "description": "Execute osascript command and return output",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "The osascript command to execute"
9
- }
10
- },
11
- "required": ["text"]
12
- }
13
- }
@@ -1,12 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import util from 'node:util'
3
-
4
- export default async function osa({ text }) {
5
- let result = ""
6
- try {
7
- result = execSync("osascript -", { input: text, encoding: "utf8" })
8
- } catch (e) {
9
- result = e.stderr + e.stdout
10
- }
11
- return (result || "").replaceAll("@", "\\@");
12
- }
@@ -1,7 +0,0 @@
1
- {
2
- "dependencies": {
3
- "escodegen": "^2.1.0",
4
- "esprima": "^4.0.1",
5
- "mime-types": "^3.0.1"
6
- }
7
- }
@@ -1,17 +0,0 @@
1
- {
2
- "description": "Apply patches to a specified file based on the given text",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "The text containing patches to apply, formated:\n```\n<<<<<<< ORIGINAL\nold code\n=======\nnew code\n>>>>>>> UPDATED\n```"
9
- },
10
- "filename": {
11
- "type": "string",
12
- "description": "The path to the file that needs to be patched."
13
- }
14
- },
15
- "required": ["text", "filename"]
16
- }
17
- }
@@ -1,38 +0,0 @@
1
- import fs from "node:fs/promises";
2
-
3
- // Patch tool to apply custom diffs marked with <<<<<<< ORIGINAL and >>>>>>> UPDATED
4
- // Handles patches with context and applies only the segments between markers.
5
-
6
- export default async function patch({ text, filename }, ctx) {
7
- // Regex to match each patch block
8
- const patchRegex = /<<<<<<< ORIGINAL[^\n]*\n([\s\S]*?)=======\n([\s\S]*?)>>>>>>> UPDATED[^\n]*(?:\n|$)/g;
9
- const patches = [];
10
- let match;
11
-
12
- // Extract all old/new segments
13
- while ((match = patchRegex.exec(text)) !== null) {
14
- const oldPart = match[1].replace(/^\n+|\n+$/g, "");
15
- const newPart = match[2].replace(/^\n+|\n+$/g, "");
16
- patches.push({ oldPart, newPart });
17
- }
18
-
19
- if (patches.length === 0) {
20
- throw new Error("No valid patch segments found");
21
- }
22
-
23
- let fileContent = await ctx.read(filename);
24
-
25
- for (const { oldPart, newPart } of patches) {
26
- // Escape regex special chars in oldPart, then allow flexible whitespace
27
- const escaped = oldPart
28
- .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
29
- .replace(/\s+/g, "\\s+");
30
- const oldRegex = new RegExp(escaped, "g");
31
-
32
- // Perform replacement using a function to avoid replacement string ambiguities
33
- fileContent = fileContent.replace(oldRegex, () => newPart);
34
- }
35
-
36
- await ctx.write(filename, fileContent);
37
- return "patched";
38
- }
@@ -1,34 +0,0 @@
1
- function parseVal(value) {
2
- try {
3
- return JSON.parse(value)
4
- } catch (e) { }
5
- return value
6
- }
7
- export default async function prop(node, args, ctx) {
8
- if (!node || node.type !== 'llm') {
9
- return node
10
- }
11
-
12
- const re = /(?<name>\w+)\s*=/
13
- let lastName;
14
- let m;
15
- let text = args;
16
- const vars = {};
17
- while ((m = re.exec(text)) !== null) {
18
- const { name } = m.groups
19
-
20
- if (lastName) {
21
- vars[lastName] = parseVal(text.slice(0, m.index).trim())
22
- }
23
- text = text.slice(m.index + m[0].length)
24
- lastName = name
25
- }
26
-
27
- if (lastName) {
28
- vars[lastName] = parseVal(text.trim())
29
- }
30
- return {
31
- ...node,
32
- exec: async (payload, ctx) => node.exec({ ...payload, ...vars }, ctx)
33
- }
34
- }
@@ -1,17 +0,0 @@
1
- {
2
- "description": "Execute Python code using a Node.js child process",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "The Python code to execute"
9
- },
10
- "filename": {
11
- "type": "string",
12
- "description": "filename to save script to"
13
- }
14
- },
15
- "required": ["text"]
16
- }
17
- }
package/tools/py.tool.py DELETED
@@ -1,22 +0,0 @@
1
- import ast
2
- import sys
3
-
4
- def main(params):
5
- if 'filename' in params:
6
- with open(params['filename'], 'w') as file:
7
- file.write(params['text'])
8
-
9
- parsed = ast.parse(params['text'])
10
- last_stmt = parsed.body[-1]
11
- if isinstance(last_stmt, ast.Expr):
12
- parsed.body[-1] = ast.Assign(
13
- targets=[ast.Name(id='myvariable', ctx=ast.Store())],
14
- value=last_stmt.value)
15
-
16
- ast.fix_missing_locations(parsed)
17
- compiled = compile(parsed, filename="cell.py", mode="exec")
18
- namespace = {}
19
- exec(compiled, namespace)
20
-
21
- return namespace.get('myvariable', None)
22
-
@@ -1,17 +0,0 @@
1
- {
2
- "description": "Answer questions based on the provided image",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "filename": {
7
- "type": "string",
8
- "description": "filename of the image"
9
- },
10
- "text": {
11
- "type": "string",
12
- "description": "Question to ask about the image"
13
- }
14
- },
15
- "required": ["filename", "text"]
16
- }
17
- }
@@ -1,4 +0,0 @@
1
- s: @mistral-small-latest
2
- You help answer questions about an image
3
- u: @{ filename | resolve }
4
- @text
@@ -1,10 +0,0 @@
1
- module.exports = async function resolve(node, args, ctx) {
2
- if (!node) {
3
- return
4
- }
5
- if (node.type !== "text") {
6
- throw Error(`can resolve only text nodes, got ${node.type}`)
7
- }
8
- const filename = await node.read()
9
- return ctx.resolve(filename.trim())
10
- }
@@ -1,17 +0,0 @@
1
- {
2
- "description": "Read the contents of a specified file",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "filename": {
7
- "type": "string",
8
- "description": "The name of the file to read"
9
- },
10
- "linenum": {
11
- "type": "boolean",
12
- "description": "prepend every line with linenumber"
13
- }
14
- },
15
- "required": ["filename"]
16
- }
17
- }
package/tools/rf.tool.mjs DELETED
@@ -1,21 +0,0 @@
1
- import { relative, dirname } from 'path'
2
-
3
- export default async function readFile({ filename, linenum }, ctx) {
4
- const resolved = await ctx.resolve(filename)
5
- if (!resolved) {
6
- return "File not found"
7
- }
8
- const relFile = relative(process.cwd(), filename)
9
- const path = [ relFile ]
10
- if (resolved.type !== 'text') {
11
- path.push('text')
12
- }
13
- if (linenum) {
14
- path.push('linenum')
15
- }
16
- if (path.length > 1) {
17
- return`@\{ ${path.join(" | ")} \}`;
18
- }
19
- return `@${relFile}`;
20
-
21
- }
@@ -1,13 +0,0 @@
1
- {
2
- "description": "generate tool schema file based on source content",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "content of a script for the schema"
9
- }
10
- },
11
- "required": ["text"]
12
- }
13
- }
@@ -1,81 +0,0 @@
1
- s: @{ gpt-4.1-mini | prop response_format={ "type": "json_object" \} }
2
- You're given chat with \@expansion variables or code or http request provide schema for it
3
- Your output json schema for tool calling like:
4
- ```json
5
- {
6
- "description": "Calculate number result based on user input",
7
- "parameters": {
8
- "type": "object",
9
- "properties": {
10
- "text": {
11
- "type": "string",
12
- "description": "math expression to calculate"
13
- }
14
- },
15
- "required": ["text"]
16
- }
17
- }
18
- ```
19
- u:
20
- s: You're calculator
21
- u: \@text
22
- a: {
23
- "description": "Calculate number result based on user input",
24
- "parameters": {
25
- "type": "object",
26
- "properties": {
27
- "text": {
28
- "type": "string",
29
- "description": "math expression to calculate"
30
- }
31
- },
32
- "required": ["text"]
33
- }
34
- }
35
- u: get_weather({ location }, ctx)
36
- a:
37
- {
38
- "description": "Get the current weather in a given location",
39
- "parameters": {
40
- "type": "object",
41
- "properties": {
42
- "location": {
43
- "type": "string",
44
- "description": "The city and state, e.g. San Francisco, CA"
45
- }
46
- },
47
- "required": ["location"]
48
- }
49
- }
50
- u:
51
- {
52
- url: "https://api.openai.com/v1/audio/transcription",
53
- method: "POST",
54
- headers: {
55
- content-type: "multiform/form-data",
56
- authorization: "Bearer ${openai_secret}"
57
- },
58
- body: {
59
- file: {audio},
60
- model: "whisper1",
61
- response_format: "text"
62
- }
63
- }
64
- a: {
65
- "description": "transcribe audio",
66
- "parameters": {
67
- "type": "object",
68
- "properties": {
69
- "audio": {
70
- "type": "buffer",
71
- "description": "audio file to transcribe"
72
- },
73
- "openai_secret": {
74
- "type": "string",
75
- "description": "openai secret"
76
- }
77
- },
78
- "required": ["audio", "openai_secret"]
79
- }
80
- }
81
- u: @text
@@ -1,13 +0,0 @@
1
- {
2
- "description": "Execute a shell command",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "The shell command to execute"
9
- }
10
- },
11
- "required": ["text"]
12
- }
13
- }
package/tools/sh.tool.mjs DELETED
@@ -1,12 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import util from 'node:util'
3
-
4
- export default async function sh({ text }) {
5
- let result = ""
6
- try {
7
- result = execSync(text, { encoding: "utf8" })
8
- } catch (e) {
9
- result = e.stderr + e.stdout
10
- }
11
- return (result || "").replaceAll("@", "\\@");
12
- }
package/tools/short.txt DELETED
@@ -1 +0,0 @@
1
- be short and precise, down to the point
@@ -1,31 +0,0 @@
1
- import { execSync, spawnSync } from 'node:child_process';
2
-
3
- const shp = async (node, args, ctx) => ({
4
- type: 'text',
5
- read: async () => {
6
- let input = null;
7
-
8
- if (node && node.type === 'text') {
9
- input = await node.read();
10
- }
11
-
12
- let result;
13
- try {
14
- if (input !== null) {
15
- const res = spawnSync(args.trim(), {
16
- input,
17
- encoding: 'utf8',
18
- shell: true
19
- });
20
- result = (res.stdout || '') + (res.stderr || '');
21
- } else {
22
- result = execSync(args.trim(), { encoding: 'utf8' });
23
- }
24
- } catch (e) {
25
- result = e.stderr + e.stdout;
26
- }
27
- return result.replaceAll('@', '\\@');
28
- }
29
- });
30
-
31
- export default shp;