tune-sdk 0.2.4 → 0.2.6

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 (82) hide show
  1. package/.github/workflows/publish.yml +27 -0
  2. package/README.md +4 -6
  3. package/dist/cli.js +8 -7
  4. package/dist/tune.js +6 -6
  5. package/docs/vscode.md +133 -0
  6. package/package.json +2 -5
  7. package/tools/README.md +0 -636
  8. package/tools/append.schema.json +0 -17
  9. package/tools/append.tool.mjs +0 -5
  10. package/tools/brave.schema.json +0 -13
  11. package/tools/brave.tool.mjs +0 -32
  12. package/tools/claude.txt +0 -1
  13. package/tools/clipboard.txt +0 -1
  14. package/tools/default.llm.js +0 -2
  15. package/tools/dev.txt +0 -6
  16. package/tools/echo.txt +0 -1
  17. package/tools/editor-filename.chat +0 -10
  18. package/tools/gemini-dev.txt +0 -7
  19. package/tools/gemini25.txt +0 -1
  20. package/tools/gemini_files.schema.json +0 -13
  21. package/tools/gemini_files.tool.mjs +0 -204
  22. package/tools/gemini_ocr.schema.json +0 -21
  23. package/tools/gemini_ocr.tool.mjs +0 -211
  24. package/tools/gemini_tts.schema.json +0 -59
  25. package/tools/gemini_tts.tool.mjs +0 -175
  26. package/tools/gemini_veo.schema.json +0 -12
  27. package/tools/gemini_veo.tool.mjs +0 -233
  28. package/tools/groq_whisper.schema.json +0 -48
  29. package/tools/groq_whisper.tool.mjs +0 -59
  30. package/tools/head.proc.js +0 -24
  31. package/tools/init.proc.js +0 -19
  32. package/tools/jina_r.schema.json +0 -21
  33. package/tools/jina_r.tool.mjs +0 -27
  34. package/tools/js.schema.json +0 -19
  35. package/tools/js.tool.mjs +0 -60
  36. package/tools/json_format.proc.mjs +0 -22
  37. package/tools/linenum.proc.js +0 -21
  38. package/tools/list.schema.json +0 -19
  39. package/tools/list.tool.mjs +0 -20
  40. package/tools/llm-utils.js +0 -150
  41. package/tools/log.proc.js +0 -15
  42. package/tools/mcp.proc.mjs +0 -174
  43. package/tools/message.schema.json +0 -21
  44. package/tools/message.tool.js +0 -14
  45. package/tools/mock.proc.js +0 -35
  46. package/tools/nu.schema.json +0 -13
  47. package/tools/nu.tool.mjs +0 -14
  48. package/tools/openai.js +0 -27
  49. package/tools/openai_imgen.schema.json +0 -35
  50. package/tools/openai_imgen.tool.mjs +0 -83
  51. package/tools/openai_stt.schema.json +0 -49
  52. package/tools/openai_stt.tool.mjs +0 -66
  53. package/tools/openai_tts.schema.json +0 -26
  54. package/tools/openai_tts.tool.mjs +0 -26
  55. package/tools/osa.schema.json +0 -13
  56. package/tools/osa.tool.mjs +0 -12
  57. package/tools/package.json +0 -7
  58. package/tools/patch.schema.json +0 -17
  59. package/tools/patch.tool.mjs +0 -38
  60. package/tools/prop.proc.mjs +0 -34
  61. package/tools/py.schema.json +0 -17
  62. package/tools/py.tool.py +0 -22
  63. package/tools/queryimage.schema.json +0 -17
  64. package/tools/queryimage.tool.chat +0 -4
  65. package/tools/resolve.proc.js +0 -10
  66. package/tools/rf.schema.json +0 -17
  67. package/tools/rf.tool.mjs +0 -21
  68. package/tools/schema.schema.json +0 -13
  69. package/tools/schema.tool.chat +0 -81
  70. package/tools/sh.schema.json +0 -13
  71. package/tools/sh.tool.mjs +0 -12
  72. package/tools/short.txt +0 -1
  73. package/tools/shp.proc.mjs +0 -31
  74. package/tools/slice.proc.js +0 -55
  75. package/tools/tail.proc.js +0 -35
  76. package/tools/text.proc.js +0 -13
  77. package/tools/turn.schema.json +0 -17
  78. package/tools/turn.tool.mjs +0 -8
  79. package/tools/wf.schema.json +0 -17
  80. package/tools/wf.tool.mjs +0 -16
  81. package/tools/yandex_tts.schema.json +0 -41
  82. package/tools/yandex_tts.tool.mjs +0 -31
package/tools/js.tool.mjs DELETED
@@ -1,60 +0,0 @@
1
- import { parseScript } from 'esprima';
2
- import { generate } from 'escodegen';
3
- import { spawnSync } from 'node:child_process';
4
- import { writeFileSync, unlinkSync } from 'node:fs';
5
- import { randomBytes } from 'crypto';
6
-
7
- export default async function execute({ text, inputType }, ctx) {
8
- // Parse the code into an Abstract Syntax Tree (AST)
9
- const ast = parseScript(text, { range: true });
10
-
11
- if (ast.body.length === 0) {
12
- return null;
13
- }
14
-
15
- const lastNode = ast.body[ast.body.length - 1];
16
- let modified = false;
17
-
18
- // If the last statement is an expression, replace it with an assignment
19
- if (lastNode.type === 'ExpressionStatement') {
20
- const assignExpression = {
21
- type: 'ExpressionStatement',
22
- expression: {
23
- type: 'AssignmentExpression',
24
- operator: '=',
25
- left: {
26
- type: 'Identifier',
27
- name: 'myVariable'
28
- },
29
- right: lastNode.expression
30
- }
31
- };
32
- ast.body[ast.body.length - 1] = assignExpression;
33
- modified = true;
34
- }
35
-
36
- const rand = randomBytes(50).toString('hex').substring(0, 10);
37
- const filename = (inputType === "module") ? `tune${rand}.mjs`:`tune${rand}.js`;
38
-
39
- let modifiedCode = generate(ast);
40
- if (modified) {
41
- if (inputType === "module") {
42
- modifiedCode = `${modifiedCode}\nimport util from 'util';\nconsole.log(util.inspect(myVariable)) `
43
- } else {
44
- modifiedCode = `${modifiedCode}\nconsole.log(require("util").inspect(myVariable))`
45
- }
46
- }
47
- writeFileSync(filename, modifiedCode)
48
-
49
- try {
50
- const res = spawnSync("node", [filename],
51
- {
52
- encoding: "utf8",
53
- input: modifiedCode,
54
- });
55
-
56
- return (res.stderr + res.stdout).trim().replace(/@/g, "\\@");
57
- } finally {
58
- unlinkSync(filename)
59
- }
60
- }
@@ -1,22 +0,0 @@
1
- import path from 'path';
2
-
3
- export default async function json_format(node, args, ctx) {
4
- if (!node) {
5
- return
6
- }
7
- let response_format = { "type": "json_object" }
8
- if (args.trim()) {
9
-
10
- let schema = await ctx.resolve(args.trim());
11
- if (!schema) throw Error(`schema file not found ${args.trim()}`)
12
- schema = await schema.read();
13
- response_format = {
14
- "type": "json_schema",
15
- "json_schema": JSON.parse(schema),
16
- }
17
- }
18
- return {
19
- ...node,
20
- exec: async (payload, ctx) => node.exec({ ...payload, response_format }, ctx)
21
- }
22
- }
@@ -1,21 +0,0 @@
1
- /*
2
- * { type: "text" | "image" | "llm" | "tool" | "processor" }
3
- * name
4
- * read (afn )
5
- */
6
- module.exports = async function(node, args) {
7
- if (! node) {
8
- return node
9
- }
10
- const res = Object.assign({}, node);
11
- res.read = async function(args) {
12
- let contents = await node.read(args);
13
- contents = contents.split("\n");
14
- const pad = `${contents.length}`.length;
15
- return contents.map((item, index) => {
16
- const lineNum = `${index + 1}`.padEnd(pad + 1, " ") + "|";
17
- return `${lineNum} ${item}`
18
- }).join("\n")
19
- }
20
- return res
21
- }
@@ -1,19 +0,0 @@
1
- {
2
- "description": "Manages todo lists",
3
- "strict": true,
4
- "parameters": {
5
- "type": "object",
6
- "properties": {
7
- "text": {
8
- "type": "string",
9
- "description": "lines in format 'status - item', they'll be used to update list or to insert to the list, to delete item change its status to deleted or cancelled\nThe lines should contain only those items that needs to be changed - inserted/updated/deleted"
10
- },
11
- "filename": {
12
- "type": "string",
13
- "description": "location of the todo list file"
14
- }
15
- },
16
- "required": ["text", "filename"],
17
- "additionalProperties": false
18
- }
19
- }
@@ -1,20 +0,0 @@
1
- function parse(text) {
2
- const lines = text.split("\n").map(item => item.trim()).filter(item => item);
3
- return lines.reduce((memo, line) => {
4
- const idx = line.indexOf("-")
5
- if (idx === -1) return memo
6
- const status = line.slice(0, idx).trim()
7
- const task = line.slice(idx+1).trim()
8
- memo[task] = status
9
- return memo
10
- },
11
- {})
12
- }
13
- export default async function list({text, filename}, ctx) {
14
- let todo = parse(await ctx.read(filename) || "")
15
- const changes = parse(text)
16
- todo = { ...todo, ...changes }
17
- todo = Object.keys(todo).map(key => `${todo[key]} - ${key}`).join("\n")
18
- await ctx.write(filename, todo)
19
- return "list updated"
20
- }
@@ -1,150 +0,0 @@
1
- const path = require("path");
2
- const fs = require("fs");
3
-
4
- // Create cache directory if it doesn't exist
5
- const cacheDir = path.join(__dirname, ".cache");
6
- if (!fs.existsSync(cacheDir)) {
7
- fs.mkdirSync(cacheDir, { recursive: true });
8
- }
9
-
10
- /**
11
- * Creates a model cache manager for a specific provider
12
- * @param {string} providerName - Name of the provider (used for cache file)
13
- * @param {function} fetchModelsFunction - Function to fetch models from API
14
- * @returns {function} getModels function that handles caching
15
- */
16
- function createModelCache(providerName, fetchModelsFunction) {
17
- const cacheFile = path.join(cacheDir, `${providerName}_models.json`);
18
- let cache;
19
-
20
- return async function getModels(...args) {
21
- if (cache) {
22
- return cache;
23
- }
24
-
25
- // Check if cache exists and is less than an hour old
26
- if (fs.existsSync(cacheFile)) {
27
- const stats = fs.statSync(cacheFile);
28
- const cacheAge = Date.now() - stats.mtimeMs;
29
- const oneHourMs = 60 * 60 * 1000; // 1 hour in milliseconds
30
-
31
- if (cacheAge < oneHourMs) {
32
- try {
33
- const cachedData = fs.readFileSync(cacheFile, "utf8");
34
- cache = JSON.parse(cachedData);
35
- return cache;
36
- } catch (error) {
37
- console.warn(`Error reading cache for ${providerName}:`, error);
38
- // Continue to fetch from API if cache reading fails
39
- }
40
- }
41
- }
42
-
43
- // Fetch from API if cache doesn't exist, is too old, or couldn't be read
44
- try {
45
- const models = await fetchModelsFunction(...args);
46
- cache = models;
47
- fs.writeFileSync(cacheFile, JSON.stringify(models, null, " "), "utf8");
48
- return models;
49
- } catch (error) {
50
- console.error(`Error fetching models for ${providerName}:`, error);
51
- throw error;
52
- }
53
- };
54
- }
55
-
56
- /**
57
- * Creates a context provider function with standard environment and regex matching
58
- * @param {string} providerName - Name of the provider
59
- * @param {Object} options - Configuration options
60
- * @returns {function} Provider context function
61
- */
62
- function createProviderContext(providerName, options) {
63
- const {
64
- apiKeyEnv,
65
- modelMatcher,
66
- modelFilter,
67
- createExecFunction,
68
- apiModelFetcher
69
- } = options;
70
-
71
- const getModels = createModelCache(providerName, apiModelFetcher);
72
- const envr = /^[A-Z_0-9]+$/;
73
-
74
- return async function providerContext(name, args) {
75
- // respond only to llm request or if type is 'any'
76
- if (args.type !== 'any' && args.type !== 'llm') {
77
- return;
78
- }
79
-
80
- const context = this;
81
- if (envr.test(name)) {
82
- return;
83
- }
84
-
85
- // Check if this model name should be handled by this provider
86
- if (modelMatcher && !modelMatcher(name)) {
87
- return;
88
- }
89
-
90
- const apiKey = await context.read(apiKeyEnv);
91
- if (!apiKey) {
92
- return;
93
- }
94
-
95
- try {
96
- const models = await getModels(apiKey);
97
-
98
- // Filter models based on name and args
99
- let matchedModels = [];
100
- if (modelFilter) {
101
- matchedModels = modelFilter(models, name, args);
102
- } else {
103
- // Default filter by exact match or regex
104
- let re;
105
- if (args.match === "regex") {
106
- re = new RegExp(name);
107
- }
108
-
109
- matchedModels = models.filter((item) => {
110
- if (args.match === "exact" && item.id === name) {
111
- return true;
112
- }
113
- if (re) {
114
- return re.test(item.id);
115
- }
116
- return false;
117
- });
118
- }
119
-
120
- if (!matchedModels.length) {
121
- return;
122
- }
123
-
124
- if (args.output === 'all') {
125
- return matchedModels.map(model => ({
126
- type: "llm",
127
- name: model.id || model.name
128
- }));
129
- }
130
-
131
- const model = matchedModels[0];
132
- return {
133
- type: "llm",
134
- exec: async (payload) => {
135
- // Get a fresh key in case it's rotated
136
- const key = await this.read(apiKeyEnv);
137
- return createExecFunction(model, payload, key, this);
138
- },
139
- };
140
- } catch (e ) {
141
- console.log(e)
142
- return
143
- }
144
- };
145
- }
146
-
147
- module.exports = {
148
- createModelCache,
149
- createProviderContext
150
- };
package/tools/log.proc.js DELETED
@@ -1,15 +0,0 @@
1
- const fs = require("fs")
2
- const path = require("path")
3
-
4
- module.exports = async (node, args, ctx) => ({
5
- ...node,
6
- exec: async function(payload, ctx) {
7
- const res = await node.exec(payload, ctx)
8
- const body = JSON.parse(res.body)
9
- payload = {...res, body};
10
- const filename = args.trim() || "log.json"
11
- const content = path.extname(filename) == ".chat" ? ctx.msg2text(payload.body.messages, true) : JSON.stringify(payload, null, " ")
12
- fs.writeFileSync(filename, content);
13
- return res
14
- }
15
- })
@@ -1,174 +0,0 @@
1
- import { fileURLToPath } from 'url';
2
- import path from 'path';
3
- import fs from 'fs';
4
- import { spawn } from "node:child_process";
5
-
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = path.dirname(__filename);
8
-
9
- /*
10
- const client = new Client({
11
- name: "Tune",
12
- version: "1.0.0"
13
- })
14
- */
15
-
16
- async function makeEnv(ctx) {
17
- const TUNE_PATH = await ctx.read('TUNE_PATH');
18
- if (!TUNE_PATH) {
19
- throw Error('TUNE_PATH not set')
20
-
21
- }
22
-
23
- return ctx.stack
24
- .filter(item => item.dirname)
25
- .map(item => item.dirname)
26
- .reverse()
27
- .concat(TUNE_PATH.split(path.delimiter))
28
- .reduce((env, dir, index, arr) => {
29
- if (arr.indexOf(dir) < index) {
30
- return env
31
- }
32
-
33
- const envFile = path.join(dir, ".env")
34
-
35
- if (!fs.existsSync(envFile)) {
36
- return env
37
- }
38
- fs.readFileSync(envFile, 'utf8')
39
- .split('\n')
40
- .forEach(line => {
41
- const m = line.match(/^\s*(\w+)\s*=\s*["']?(.*?)\s*["']?$/)
42
- if (!m) return
43
- env[m[1]] = m[2]
44
- })
45
- return env
46
-
47
- }, process.env)
48
- }
49
-
50
- async function getMcpClient(args, env) {
51
- const client = {}
52
- const [command, ...rest] = args.trim().split(/\s+/);
53
- const process = spawn(command, rest, { env })
54
- let chunks = []
55
- const nodes = []
56
- const callbacks = {}
57
- function onError(err ) {
58
- console.log("onError", err)
59
- if (client.onError) {
60
- client.onError(err)
61
- }
62
- Object.keys(callbacks).forEach(mid=> {
63
- callbacks[mid].reject(err)
64
- })
65
- }
66
- process.stdout.on('data', (data) => {
67
- try {
68
- chunks.push(data)
69
- let buf = Buffer.concat(chunks)
70
- let index
71
- while ((index = buf.indexOf('\n')) !== -1) {
72
- const line = buf.toString("utf8", 0, index);
73
- buf = buf.subarray(index + 1);
74
- const msg = JSON.parse(line)
75
- if (msg.id && callbacks[msg.id]) {
76
- const { resolve, reject} = callbacks[msg.id]
77
- if (msg.result) {
78
- resolve(msg.result)
79
- }
80
- if (msg.error) {
81
- reject(msg.error)
82
- }
83
- delete callbacks[msg.id]
84
- }
85
- }
86
- chunks = [buf]
87
- } catch (e) {
88
- onError(e)
89
- process.kill()
90
- }
91
- });
92
-
93
- let msgId = 1
94
- client.request = async (params) =>
95
- new Promise((resolve, reject) => {
96
- const payload = JSON.stringify({
97
- ...params,
98
- jsonrpc: "2.0",
99
- id: msgId,
100
- })
101
- process.stdin.write(`${payload}\n`)
102
- callbacks[msgId] = {resolve, reject}
103
- msgId++
104
- })
105
-
106
- const errChunks = []
107
- process.stderr.on('data', (data) => {
108
- errChunks.push(data)
109
- console.log(data.toString('utf8'))
110
- });
111
- process.on('error', onError);
112
- process.on('close', (code) => {
113
- client.err = Buffer.concat(errChunks).toString('utf8')
114
- client.data = Buffer.concat(chunks).toString('utf8')
115
- if (code !== 0) {
116
- return onError(new Error(client.err))
117
- }
118
- });
119
- let res = await client.request({
120
- method: "initialize",
121
- params: {
122
- protocolVersion: "2024-11-05",
123
- capabilities: { tools: {} },
124
- clientInfo: { name: "Tune", version: "1.0.0"}
125
- }
126
- })
127
- client.server = res
128
-
129
- client.close = () => process.kill()
130
- return client
131
- }
132
-
133
- export default async function mcp(node, args, ctx) {
134
- const env = await makeEnv(ctx)
135
- const client = await getMcpClient(args, env)
136
- if (! client.server.capabilities.tools) {
137
- throw Error(`${args} does not support tools`)
138
- }
139
- //client.onError()
140
-
141
- let res = await client.request({ method: "tools/list"})
142
- //const name = args.trim().toLowerCase().replace(/\W+/g, "_")
143
- //fs.writeFileSync(path.join(__dirname, `${name}-mcp.json` ), JSON.stringify(res.tools, null, " "))
144
- return res.tools.map(item => ({
145
- type: "tool",
146
- name: item.name,
147
- schema: {
148
- name: item.name,
149
- description: item.description,
150
- parameters: item.inputSchema
151
- },
152
- exec: async (args) => {
153
- let res = await client.request({method: "tools/call", params: {
154
- name: item.name,
155
- arguments: args
156
- }})
157
- res = res.toolResult || res
158
- const content = res.content
159
- .map(item => {
160
- if (item.type == "text") {
161
- return item.text.replaceAll("@", "\\@")
162
- }
163
- // not supported yet
164
- return ""
165
- })
166
- .join("\n")
167
-
168
- if (res.isError) {
169
- throw Error(`error calling ${item.name}\n${content}`)
170
- }
171
- return content
172
- }
173
- }))
174
- }
@@ -1,21 +0,0 @@
1
- {
2
- "description": "this tool sends a message to another ai chat as 'user' role, result of the tool is an 'assistant' reply",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "filename": {
7
- "type": "string",
8
- "description": "File name to read/write chat history, should have .chat extension"
9
- },
10
- "system": {
11
- "type": "string",
12
- "description": "Filename that contains system prompt, required once at the beginning of simulation"
13
- },
14
- "text": {
15
- "type": "string",
16
- "description": "User message to send"
17
- }
18
- },
19
- "required": ["filename", "text"]
20
- }
21
- }
@@ -1,14 +0,0 @@
1
- module.exports = async function message({ filename, system, text, stop }, ctx) {
2
- let chat = await ctx.read(filename);
3
- if (!chat && system) {
4
- chat = `system: @@${system}`
5
- }
6
- chat = `${chat}\nuser:\n${text}`
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 ""
14
- }
@@ -1,35 +0,0 @@
1
- module.exports = async function mock(node, args, ctx) {
2
- const re = /(?<name>\w+)\s*=/
3
- let lastName;
4
- let m;
5
- let text = args;
6
- const vars = {};
7
- while ((m = re.exec(text)) !== null) {
8
- const { name } = m.groups
9
-
10
- if (lastName) {
11
- vars[lastName] = text.slice(0, m.index).trim()
12
- }
13
- text = text.slice(m.index + m[0].length)
14
- lastName = name
15
- }
16
- if (lastName) {
17
- vars[lastName] = text.trim()
18
- }
19
- ctx.use((name, ctx, args)=> {
20
- if (!vars.hasOwnProperty(name)) {
21
- return
22
- }
23
- return {
24
- ...node,
25
- type: "text",
26
- name,
27
- read: async () => vars[name]
28
- }
29
- })
30
- return {
31
- ...node,
32
- type: "text",
33
- read: async() => ""
34
- }
35
- }
@@ -1,13 +0,0 @@
1
- {
2
- "description": "Execute a nushell command",
3
- "parameters": {
4
- "type": "object",
5
- "properties": {
6
- "text": {
7
- "type": "string",
8
- "description": "The nushell command to execute"
9
- }
10
- },
11
- "required": ["text"]
12
- }
13
- }
package/tools/nu.tool.mjs DELETED
@@ -1,14 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import util from 'node:util'
3
-
4
- export default async function nu({ text }) {
5
- let result = ""
6
- try {
7
- result = spawnSync("nu",
8
- ["-c", text, "--error-style", "plain"],
9
- { encoding: "utf8", shell: false })
10
- } catch (e) {
11
- result = e.stderr + e.stdout
12
- }
13
- return (result.stdout || result.stderr || "").replaceAll("@", "\\@");
14
- }
package/tools/openai.js DELETED
@@ -1,27 +0,0 @@
1
- module.exports = function(props, transform) {
2
- const { auth_key, url } = props;
3
- delete props.auth_key;
4
- delete props.url;
5
- return async function(payload, ctx) {
6
- const key = auth_key || await ctx.read('OPENAI_KEY');
7
- if (typeof(transform) === 'function') {
8
- payload = transform(payload)
9
- }
10
-
11
- const result = ({
12
- url: url || "https://api.openai.com/v1/chat/completions",
13
- method: "POST",
14
- headers: {
15
- "content-type": "application/json",
16
- authorization: `Bearer ${key}`
17
- },
18
- body: JSON.stringify({
19
- ...props,
20
- ...payload,
21
- messages: payload.messages.filter(msg => msg.role !== 'comment'),
22
- })
23
- })
24
- // console.log(result)
25
- return result
26
- }
27
- }
@@ -1,35 +0,0 @@
1
-
2
- {
3
- "description": "generate or change an image using openai image generation",
4
- "parameters": {
5
- "type": "object",
6
- "properties": {
7
- "text": {
8
- "type": "string",
9
- "description": "The prompt text for image generation. or details on what to change on existing images."
10
- },
11
- "filename": {
12
- "type": "string",
13
- "description": "The filename where the generated image will be saved."
14
- },
15
- "quality": {
16
- "type": "string",
17
- "enum": ["auto", "low", "medium", "high"],
18
- "description": "Quality of the result, auto is default"
19
- },
20
- "size": {
21
- "type": "string",
22
- "enum": ["auto", "square", "landscape", "portrait"],
23
- "description": "size of the image, auto is default"
24
- },
25
- "images": {
26
- "type": "array",
27
- "description": "Use it if you want to change existing image, or provide more context to newly generated image. If provided, the API will use the edits endpoint instead of generations. ",
28
- "items": {
29
- "type": "string"
30
- }
31
- }
32
- },
33
- "required": ["text", "filename"]
34
- }
35
- }