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 +98 -57
- package/config/default.ctx.js +2 -0
- package/package.json +5 -2
- package/src/man.js +117 -0
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://
|
|
83
|
-
* [tune-models](https://
|
|
84
|
-
* [tune-basic-toolset](https://
|
|
85
|
-
* [tune-s3](https://
|
|
86
|
-
* [tune-mcp](https://
|
|
87
|
-
* [maik](https://
|
|
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
|
-
|
|
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
|
-
|
|
124
|
+
```javascript
|
|
125
|
+
const tune = require("tune-sdk")
|
|
163
126
|
|
|
164
127
|
async function main() {
|
|
165
|
-
const ctx = tune.makeContext(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"
|
|
169
|
-
|
|
170
|
-
|
|
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
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
+
```
|
package/config/default.ctx.js
CHANGED
|
@@ -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.
|
|
4
|
-
"description": "
|
|
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;
|