tune-sdk 0.3.0 → 0.3.1

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
@@ -14,6 +14,7 @@ install tune-sdk
14
14
  ```bash
15
15
  npm install -g tune-sdk
16
16
 
17
+ # create ~/.tune folder and install batteries
17
18
  tune init
18
19
  ```
19
20
 
@@ -39,52 +40,15 @@ user:
39
40
  ```
40
41
  [read more](https://iovdin.github.io/tune/template-language)
41
42
 
42
-
43
- ## Diagram
44
-
45
- ```mermaid
46
- flowchart TD
47
-
48
- subgraph Entry[" "]
49
- Editor["VSCode/Neovim/Sublime Text"]
50
- CLI["CLI"]
51
- App["App"]
52
- end
53
-
54
- subgraph Core[" "]
55
- MD1["~/.tune/default.ctx.js"]
56
- MD2["require('tune-fs')
57
- require('tune-models')
58
- "]
59
- CTX["tune.makeContext(...middlewares)"]
60
- F2R["ctx.file2run(params)"]
61
- end
62
-
63
-
64
- MD1 --> |cli middlewares| CTX
65
- MD2 --> |app middlewares| CTX
66
- Editor -->| $ tune rpc | Core
67
- CLI --> | $ tune --user hello | Core
68
- App --> Core
69
-
70
-
71
-
72
- F2R -->|ctx.resolve #40; system.txt #124; shell #124; gpt-5 #41; | CTX
73
- CTX -->| #123; type: text #124; tool #124; llm #125; | F2R
74
-
75
- F2R --> |fetch| LLM["https://provider.com/v1/chat/completions"]
76
- F2R --> |call| Tool
77
- ```
78
-
79
43
  ## Extend with Middlewares
80
44
  Extend Tune with middlewares:
81
45
 
82
- * [tune-fs](https://www.npmjs.com/package/tune-fs) - connect tools & files from local filesystem
83
- * [tune-models](https://www.npmjs.com/package/tune-models) - connect llm models from Anthropic/OpenAI/Gemini/Openrouter/Mistral/Groq
84
- * [tune-basic-toolset](https://www.npmjs.com/package/tune-basic-toolset) - basic tools like read file, write file, shell etc.
85
- * [tune-s3](https://www.npmjs.com/package/tune-s3) - read/write files from s3
86
- * [tune-mcp](https://www.npmjs.com/package/tune-mcp) - connect tools from mcp servers
87
- * [maik](https://www.npmjs.com/package/@iovdin/maik) - fetch all you emails, and index them into sqlite database
46
+ * [tune-fs](https://github.com/iovdin/tune-fs) - connect tools & files from local filesystem
47
+ * [tune-models](https://github.com/iovdin/tune-models) - connect llm models from Anthropic/OpenAI/Gemini/Openrouter/Mistral/Groq
48
+ * [tune-basic-toolset](https://github.com/iovdin/tune-basic-toolset) - basic tools like read file, write file, shell etc.
49
+ * [tune-s3](https://github.com/iovdin/tune-s3) - read/write files from s3
50
+ * [tune-mcp](https://github.com/iovdin/tune-mcp) - connect tools from mcp servers
51
+ * [maik](https://github.com/iovdin/maik) - fetch all you emails, and index them into sqlite database
88
52
 
89
53
 
90
54
  For example:
@@ -155,27 +119,104 @@ tune --set test="hello" --user "@test" --system "You are echo you print everytht
155
119
  ## Javascript SDK
156
120
  `npm install tune-sdk`
157
121
 
158
- ```javascript
159
- const tune = require("tune-sdk");
160
- const sonnet = require("./sonnet.llm.js");
122
+ Tune core is middleware-based. A context resolves `@name` references into nodes like `text`, `tool`, `llm`, and `processor`.
161
123
 
162
- require('dotenv').config();
124
+ ```javascript
125
+ const tune = require("tune-sdk")
163
126
 
164
127
  async function main() {
165
- const ctx = tune.makeContext({
166
- echo: "You are echo, you print everything back",
167
- OPENROUTER_KEY: process.env.OPENROUTER_KEY,
168
- "default": {
169
- type: "llm",
170
- exec: sonnet
128
+ const ctx = tune.makeContext()
129
+
130
+ ctx.use(async function middleware(name) {
131
+ if (name === "file.txt") {
132
+ return {
133
+ type: "text",
134
+ name: "file.txt",
135
+ read: async () => fs.readFileSync("file.txt", "utf8")
136
+ }
137
+ }
138
+
139
+ if (name === "readfile") {
140
+ return {
141
+ type: "tool",
142
+ name: "readfile",
143
+ schema: {
144
+ type: "object",
145
+ properties: {
146
+ filename: { type: "string" }
147
+ }
148
+ },
149
+ exec: async ({ filename }) => fs.readFileSync(filename, "utf8")
150
+ }
151
+ }
152
+
153
+ if (name === "gpt-5") {
154
+ return {
155
+ type: "llm",
156
+ name: "gpt-5",
157
+ exec: async (payload) => ({
158
+ url: "https://api.openai.com/v1/chat/completions",
159
+ method: "POST",
160
+ headers: {
161
+ Authorization: `Bearer ${process.env.OPENAI_KEY}`,
162
+ "Content-Type": "application/json"
163
+ },
164
+ body: JSON.stringify({
165
+ model: "gpt-5",
166
+ ...payload
167
+ })
168
+ })
169
+ }
170
+ }
171
+
172
+ if (name === "tail") {
173
+ return {
174
+ type: "processor",
175
+ name: "tail",
176
+ exec: async (node, args) => {
177
+ if (!node) return
178
+ if (node.type !== "text") throw Error("tail can only modify text nodes")
179
+ return {
180
+ ...node,
181
+ read: async () => {
182
+ const content = await node.read()
183
+ const n = parseInt(args.trim(), 10) || 20
184
+ return content.split("\n").slice(-n).join("\n")
185
+ }
186
+ }
187
+ }
188
+ }
171
189
  }
172
190
  })
173
191
 
174
- const text = "s: @echo\nu: hello world";
175
- const messages = await tune.text2run(text, ctx)
176
- console.log(tune.msg2text(messages))
177
- // a: hello world
192
+ const content = await ctx.file2run({
193
+ system: "@gpt-5 @readfile",
194
+ user: "can you read file.txt?",
195
+ stream: false,
196
+ response: "content"
197
+ })
198
+
199
+ console.log(content)
178
200
  }
201
+
179
202
  main()
180
203
  ```
204
+
181
205
  [read more](https://iovdin.github.io/tune/api) about javascript sdk
206
+
207
+ ## Help / Manual
208
+
209
+ You can access tune manuals and available middlewares manuals from
210
+
211
+ ```chat
212
+ system:
213
+ @man include all manuals for all connected packages
214
+ @man/ - list all the manuals, like list directory
215
+ @man/tune - get manual for tune core package
216
+ @man/tune-basic-toolset - get manual for tune-basic-tool set package
217
+
218
+ tool_call: rf { "filename": "man/tune-basic-toolset"}
219
+ tool_result:
220
+ @man/tune-basic-toolset
221
+
222
+ ```
@@ -1,5 +1,6 @@
1
1
  const path = require('path')
2
2
 
3
+ const man = require("tune-sdk/man");
3
4
  const models = require("tune-models")
4
5
  const basics = require("tune-basic-toolset")
5
6
  const tunefs = require("tune-fs")
@@ -11,6 +12,7 @@ if (process.env.TUNE_PATH) {
11
12
  }
12
13
 
13
14
  module.exports = [
15
+ man(),
14
16
  current(),
15
17
  basics(),
16
18
  tunefs({ paths: dirs, makeSchema: true }),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tune-sdk",
3
- "version": "0.3.0",
4
- "description": "tune - LLM chat in text file",
3
+ "version": "0.3.1",
4
+ "description": "chat with llm in a text file. core package",
5
5
  "main": "dist/tune.js",
6
6
  "module": "dist/tune.mjs",
7
7
  "bin": {
@@ -21,6 +21,9 @@
21
21
  },
22
22
  "./contextws": {
23
23
  "require": "./src/contextws.js"
24
+ },
25
+ "./man": {
26
+ "require": "./src/man.js"
24
27
  }
25
28
  },
26
29
  "keywords": [
package/src/man.js ADDED
@@ -0,0 +1,117 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+ // all the registered manuals
4
+ // { name, description, filename/content }
5
+
6
+ let mans = [
7
+ ]
8
+
9
+ /*
10
+ @man include all manuals for all packages included
11
+ @man/ - list all the manuals, like list directory
12
+ @man/tune - get manual for tune core package
13
+ @man/tune-basic-toolset - get manual for tune-basic-tool set package
14
+
15
+ TODO:
16
+ @man/tune/js-api - lis
17
+ @man/tune/agents - lis
18
+ */
19
+
20
+ function read({ filename, content }) {
21
+ if (content) {
22
+ return content
23
+ }
24
+ if (!fs.existsSync(filename)) {
25
+ return `file ${filename} not found`
26
+ }
27
+ return fs.readFileSync(filename)
28
+ }
29
+
30
+ module.exports = ({ mount } = {}) => async (name, { type }) => {
31
+ if ((type || "any") !== 'any' && type !== 'text' ) {
32
+ return
33
+ }
34
+ mount ||= "man"
35
+
36
+ // supported only with mount
37
+ if (!mount) {
38
+ return
39
+ }
40
+
41
+ // @man include all the manuals
42
+ if (name === mount) {
43
+ return {
44
+ type: "text",
45
+ name,
46
+ read: async () => mans.map(man => `<${man.name}>\n ${read(man)} \n</${man.name}>`).join("\n")
47
+ }
48
+ }
49
+
50
+ if (!name.startsWith(mount + '/')) {
51
+ return
52
+ }
53
+
54
+ // @man/ - list all the manuals to include
55
+ if (name === mount + '/') {
56
+ return {
57
+ type: "text",
58
+ name,
59
+ read: async () => mans.map(man => `${man.name} - ${man.description}`).join("\n")
60
+ }
61
+ }
62
+
63
+
64
+ // @man/tune - get manual for tune core package
65
+ // @man/tune-basic-toolset - get manual for tune-basic-tool set package
66
+
67
+ const actualName = name.slice(mount.length + 1);
68
+
69
+ const man = mans.find(man => man.name === actualName);
70
+ if (!man) return
71
+
72
+ return {
73
+ type: "text",
74
+ name,
75
+ read: async() => read(man.filename)
76
+ }
77
+ }
78
+
79
+ const addManual = (dirname) => {
80
+ let package = path.resolve(dirname, "package.json");
81
+ if (!fs.existsSync(package)){
82
+ dirname = path.resolve(dirname, "..")
83
+ package = path.resolve(dirname, "package.json");
84
+ }
85
+
86
+ if (!fs.existsSync(package)){
87
+ throw Error(`cant make manual ${package} not found`);
88
+ }
89
+
90
+ const { name, version, description } = JSON.parse(fs.readFileSync(package, "utf8"));
91
+
92
+ const newMans = mans.filter(man => man.name !== name)
93
+
94
+ const filename = path.resolve(dirname, "README.md")
95
+
96
+ newMans.push({name, description, filename})
97
+ mans = newMans
98
+ }
99
+
100
+ addManual(__dirname)
101
+ /*
102
+ const addManual = ({name, description, content, filename}) => {
103
+ const = params;
104
+
105
+ const newMans = mans.filter(man => man.name !== name)
106
+ if (!name) {
107
+ throw Error(`name is not set for manual`)
108
+ }
109
+ if (!content && !filename) {
110
+ throw Error(`neither content nor filename is set for '${name}' manual`)
111
+ }
112
+
113
+ newMans.push({name, description, content, filename})
114
+ }
115
+ */
116
+
117
+ module.exports.addManual = addManual;