tune-sdk 0.1.9 → 0.1.12

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
@@ -1,4 +1,4 @@
1
- # Tune your everyday LLM toolkit
1
+ # Tune - AI chat in text file
2
2
 
3
3
  Tune is a handy [extension](https://marketplace.visualstudio.com/items?itemName=iovdin.tune) for Visual Studio Code and [plugin](https://github.com/iovdin/tune.nvim) for Neovim that lets you chat with large language models (LLMs) in a text file.
4
4
  With tune [javascript sdk](https://www.npmjs.com/package/tune-sdk) you can make apps and agents.
@@ -6,10 +6,57 @@ With tune [javascript sdk](https://www.npmjs.com/package/tune-sdk) you can make
6
6
  ## Demo
7
7
  <img src="https://github.com/iovdin/tune/blob/770f382a03a25e15eeef293f553b6aee0f3531f6/docs/assets/gifs/tune.gif">
8
8
 
9
+ ## Template Language
10
+
11
+ ```chat
12
+ @myprompt include file
13
+ @image include image
14
+ @path/to/file include file at path
15
+ @gpt-4.1 connect model
16
+ @shell connect tool
17
+ @@prompt include file recursively
18
+
19
+ @{ name with whitespaces } - include file with whitespaces
20
+ @{ image | resize 512 } - modify with processors
21
+ @{ largefile | tail 100 } - modify with processors
22
+ @{| sh tree } - insert generated content with processors
23
+
24
+ ```
25
+ [read more](https://iovdin.github.io/tune/template-language)
26
+
27
+
28
+ ## Batteries Included
29
+ **Anthropic/OpenAI/Gemini/Openrouter/Mistral/Groq** models providers are supported and **30+ tools** come with text editor.
30
+ ```chat
31
+ system:
32
+ @gemini-2.5-pro @openai_imgen
33
+
34
+ user:
35
+ draw a stickman with talking bubble "Hello world"
36
+
37
+ assistant:
38
+ tool_call: openai_imgen {"filename":"stickman_hello_world.png"}
39
+ a simple stickman drawing with a talking bubble saying 'Hello world'
40
+
41
+ tool_result:
42
+ image generated
43
+ ```
44
+ [read more](tools/README.md)
45
+
46
+ ## CLI
47
+
48
+ ```bash
49
+ # append user message to newchat.chat run and save
50
+ npx tune-sdk --user "hi how are you?" --filename newchat.chat --save
51
+
52
+ # start new chat with system prompt and initial user message
53
+ # print result to console
54
+ npx tune-sdk --system "You are Groot" --user "Hi how are you?"
55
+
56
+ #set context variable
57
+ npx tune-sdk --set "test=hello" --user "@test" --system "You are echo you print everythting back"
58
+ ```
9
59
 
10
- ## Read more about
11
- How to [connect LLMs](https://iovdin.github.io/tune/template-language/connect-llm)
12
- or how to [use tools](https://iovdin.github.io/tune/template-language/tools)
13
60
 
14
61
  ## Javascript SDK
15
62
  `npm install tune-sdk`
package/bin/cli.js CHANGED
@@ -1,115 +1,133 @@
1
- #!/usr/bin/env node
1
+ var tune, rpc;
2
2
 
3
- // Minimal inline argument parser
4
- const args = {};
5
- let currentKey = null;
6
-
7
- process.argv.slice(2).forEach(arg => {
8
- if (arg.startsWith('--')) {
9
- const [key, value] = arg.substring(2).split('=');
10
- if (typeof value !== 'undefined') {
11
- args[key] = value;
12
- currentKey = null;
3
+ function parseArgs(args) {
4
+ var curKey, res, res1, key, value, _ref, _len;
5
+ var curKey;
6
+ curKey = null;
7
+ var res;
8
+ res = args.reduce((function(memo, arg) {
9
+ var key, value, _ref, _i;
10
+ if (arg.startsWith("--")) {
11
+ _ref = arg.substring(2)
12
+ .split("=");
13
+ key = _ref[0];
14
+ value = _ref[1];
15
+ if (!!value) {
16
+ memo[key] = value;
17
+ curKey = null;
18
+ } else {
19
+ curKey = key;
20
+ memo[key] = true;
21
+ }
22
+ } else if (curKey) {
23
+ memo[curKey] = arg;
24
+ curKey = null;
25
+ }
26
+ return memo;
27
+ }), {});
28
+ var res1;
29
+ res1 = {};
30
+ _ref = res;
31
+ for (key in _ref) {
32
+ value = _ref[key];
33
+ if (key.startsWith("set-")) {
34
+ res1.params = res1.params || {}
35
+ res1.params[key.substr(4)] = value;
13
36
  } else {
14
- currentKey = key;
15
- args[currentKey] = true
37
+ res1[key] = value;
16
38
  }
17
- } else if (currentKey) {
18
- args[currentKey] = arg;
19
- currentKey = null;
20
39
  }
21
- });
22
-
23
- const tune = require('../dist/tune.js');
24
- const { fsctx } = require('../dist/fsctx.js');
25
- const fs = require("fs");
26
- const path = require("path");
27
-
40
+ return res1;
41
+ }
42
+ parseArgs;
43
+ tune = require("../dist/tune.js");
44
+ rpc = require("../dist/rpc.js");
45
+ async function rpc(args, ctx) {
46
+ var server;
47
+ var server;
48
+ return (server = jsonrpc());
49
+ }
50
+ rpc;
51
+ async function run(args, ctx) {
52
+ var stopVal, params;
53
+ var stopVal;
54
+ stopVal = args.stop || "assistant";
55
+ if ((stopVal !== "step" && stopVal !== "assistant")) stopVal = (function(msgs) {
56
+ var lastMsg;
57
+ if (!msgs.length) return false;
58
+ var lastMsg;
59
+ lastMsg = msgs["slice"](-1)[0];
60
+ if (!lastMsg.content) return false;
61
+ return (-1 !== lastMsg.content.inexOf(args.stop || "assistant"));
62
+ });
63
+ var params;
64
+ params = args.params;
65
+ delete args.params;
66
+ return ctx.file2run(args, params);
67
+ }
68
+ run;
28
69
  async function main() {
29
- try {
30
- let chat = ""
31
- // where to search for inclusions
32
- let dirs = [];
33
-
34
- if (args.filename && fs.existsSync(args.filename)) {
35
- chat = fs.readFileSync(args.filename, "utf8")
36
- dirs.push(path.dirname(path.resolve(args.filename)))
37
- }
38
-
39
- if (!chat && args.system) {
40
- chat = `system:\n${args.system}`
41
- }
42
-
43
- if (args.user) {
44
- chat = `${chat}\nuser:\n${args.user}`
45
- }
46
-
47
- if(process.env.TUNE_PATH) {
48
- dirs = dirs.concat(process.env.TUNE_PATH.split(path.delimiter))
49
- }
50
-
51
- dirs.push(process.cwd())
52
-
53
- const ctx = tune.makeContext(process.env)
54
- if (args.filename) {
55
- ctx.stack.push({
56
- filename: args.filename,
57
- name: path.basename(args.filename),
58
- dirname: path.dirname(path.resolve(args.filename))
59
- })
70
+ var dirs, args, ctx, dir, ctxName, ext, module, m, _i, _res, _ref, _len, _ref0, _i0, _res0, _ref1, _len0, _ref2;
71
+ var dirs;
72
+ var args;
73
+ dirs = [];
74
+ args = parseArgs(process.argv.slice(2));
75
+ if (args.path) {
76
+ dirs = args.path.split(path.delimiter);
77
+ } else {
78
+ if (process.env.TUNE_PATH) dirs = process.env.TUNE_PATH.split(path.delimiter);
79
+ dirs.push(process.cwd());
80
+ }
81
+ ctx = tune.makeContext(process.env);
82
+ _res = [];
83
+ _ref = dirs;
84
+ for (_i = 0, _len = _ref.length; _i < _len; ++_i) {
85
+ dir = _ref[_i];
86
+ var ctxName;
87
+ ctxName = ["default.ctx.js", "default.ctx.cjs", "default.ctx.mjs"]
88
+ .map((function(name) {
89
+ return path.join(dir, name);
90
+ }))
91
+ .find((function(name) {
92
+ return fs.existsSync(name);
93
+ }));
94
+ if (!ctxName) continue;
95
+ var ext;
96
+ var module;
97
+ ext = path.extname(filename);
98
+ module = null;
99
+ if ((ext === ".js" || ext === ".cjs")) {
100
+ module = require(ctxName);
101
+ } else {
102
+ module = await import(ctxName);
103
+ module = module.default;
60
104
  }
61
- ctx.use(fsctx(dirs))
62
-
63
- for (const dir of dirs) {
64
- let filename = ["default.ctx.js", "default.ctx.cjs", "default.ctx.mjs"].find(name => fs.existsSync(path.join(dir, name)));
65
- if (!filename) continue;
66
- filename = path.join(dir, filename);
67
- let ext = path.extname(filename);
68
- let module
69
- if ((ext === ".js" || ext === ".cjs")) {
70
- module = require(filename);
71
- } else {
72
- module = await import(filename);
73
- module = module.default;
74
- }
75
- if (typeof module === "function") {
76
- ctx.use(module);
77
- } else if (Array.isArray(module)) {
78
- for (const m of module) {
79
- if (typeof m === "function") {
80
- ctx.use(m)
81
- } else {
82
- throw(Error(`err: Context file export is not an array of functions or function ${filename}`))
83
- }
105
+ if ((typeof module === "function")) {
106
+ _ref0 = ctx.use(module);
107
+ } else if (Array.isArray(module)) {
108
+ _res0 = [];
109
+ _ref1 = module;
110
+ for (_i0 = 0, _len0 = _ref1.length; _i0 < _len0; ++_i0) {
111
+ m = _ref1[_i0];
112
+ if ((typeof m === "function")) {
113
+ _ref2 = ctx.use(module);
114
+ } else {
115
+ _ref2 = undefined;
116
+ throw Error(tpl("err: Context file export is not an array of functions or function {}", ctxName));
84
117
  }
85
- } else {
86
- throw(Error(`err: Context file export is not an array of functions or function ${filename}`))
118
+ if (typeof _ref2 !== 'undefined') _res0.push(_ref2);
87
119
  }
120
+ _ref0 = _res0;
121
+ } else {
122
+ _ref0 = undefined;
123
+ throw Error(tpl("err: Context file export is not an array of functions or function {}", ctxName));
88
124
  }
89
- let stopVal = args.stop || "assistant";
90
- if (stopVal !== "step" && stopVal != "assistant") {
91
- stopVal = function(msgs) {
92
- if (!msgs.length) return false
93
- const lastMsg = msgs[msgs.length - 1]
94
- if (!lastMsg.content) return false
95
- return (lastMsg.content.indexOf(args.stop) !== -1)
96
- }
97
- }
98
-
99
- let res = await tune.text2run(chat, ctx, { stop: stopVal })
100
-
101
- const longFormatRegex = /^(system|user|tool_call|tool_result|assistant|error):/;
102
- res = tune.msg2text(res, longFormatRegex.test(chat))
103
- if (args.filename && args.save) {
104
- chat += "\n" + res
105
- fs.writeFileSync(args.filename, chat)
106
- }
107
- if (!args.save) {
108
- console.log(res)
109
- }
110
- } catch (e) {
111
- console.error(e)
125
+ if (typeof _ref0 !== 'undefined') _res.push(_ref0);
112
126
  }
127
+ return _res;
113
128
  }
114
-
115
- main()
129
+ main;
130
+ exports.parseArgs = parseArgs;
131
+ exports.rpc = rpc;
132
+ exports.main = main;
133
+ exports.run = run;