@j-o-r/hello-dave 0.1.0 → 0.1.4

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 (173) hide show
  1. package/CHANGELOG.md +42 -25
  2. package/README.md +81 -221
  3. package/TODO.md +173 -35
  4. package/agents/agent_creator.js +105 -0
  5. package/agents/agent_creator.prompt.md +371 -0
  6. package/agents/ask_agent.js +64 -127
  7. package/agents/claude_agent.js +68 -0
  8. package/agents/code_agent.js +55 -135
  9. package/agents/code_agent.prompt.md +50 -0
  10. package/agents/echo_agent.js +76 -0
  11. package/agents/financial_expert.js +75 -0
  12. package/agents/gpt_agent.js +52 -103
  13. package/agents/gpt_code.js +81 -0
  14. package/agents/grok_agent.js +58 -114
  15. package/agents/minimax_agent.js +92 -0
  16. package/agents/mureka_agent.js +77 -0
  17. package/agents/planner_agent.js +172 -0
  18. package/agents/stability_agent.js +87 -0
  19. package/agents/test_agent.js +75 -157
  20. package/agents/weather_agent.js +73 -0
  21. package/agents/workflow_agent.js +189 -0
  22. package/bin/dave.js +436 -184
  23. package/docs/bin-dave.md +85 -35
  24. package/docs/cdn-ssh.md +100 -0
  25. package/docs/creating-agents.md +301 -0
  26. package/docs/creating-toolsets.md +336 -0
  27. package/docs/docs-organization.md +48 -0
  28. package/docs/project-overview.md +86 -51
  29. package/lib/API/elevenlabs.io/music.compose.md +441 -0
  30. package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
  31. package/lib/API/elevenlabs.io/music.stream.md +425 -0
  32. package/lib/API/lalal.ai/lalal.js +445 -0
  33. package/lib/API/lalal.ai/openapi.json +2614 -0
  34. package/lib/API/minimax/ImageToolset.js +82 -37
  35. package/lib/API/minimax/MusicToolset.js +125 -79
  36. package/lib/API/minimax/VideoToolset.js +170 -167
  37. package/lib/API/minimax/image.js +5 -1
  38. package/lib/API/minimax/music.js +210 -23
  39. package/lib/API/minimax/video.js +242 -53
  40. package/lib/API/mureka/MusicToolset.js +646 -0
  41. package/lib/API/mureka/README.md +41 -0
  42. package/lib/API/mureka/index.js +7 -0
  43. package/lib/API/mureka/music.js +658 -0
  44. package/lib/API/openai.com/index.js +7 -0
  45. package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
  46. package/lib/API/openai.com/video.create.character.md +40 -0
  47. package/lib/API/openai.com/video.create.md +219 -0
  48. package/lib/API/openai.com/video.delete.md +44 -0
  49. package/lib/API/openai.com/video.download.md +31 -0
  50. package/lib/API/openai.com/video.edit.md +155 -0
  51. package/lib/API/openai.com/video.extend.md +166 -0
  52. package/lib/API/openai.com/video.fetch.character.md +43 -0
  53. package/lib/API/openai.com/video.js +784 -0
  54. package/lib/API/openai.com/video.list.md +201 -0
  55. package/lib/API/openai.com/video.remix.md +175 -0
  56. package/lib/API/openai.com/video.retrieve.md +139 -0
  57. package/lib/API/openai.com/videoToolset.js +616 -0
  58. package/lib/API/stability.ai/ImageToolset.js +131 -40
  59. package/lib/API/stability.ai/MusicToolset.js +79 -47
  60. package/lib/API/stability.ai/audio.js +63 -131
  61. package/lib/API/x.ai/chat.responses.md +1040 -0
  62. package/lib/API/x.ai/image.js +229 -59
  63. package/lib/API/x.ai/imageToolset.js +376 -0
  64. package/lib/API/x.ai/index.js +1 -3
  65. package/lib/API/x.ai/responses.js +9 -18
  66. package/lib/Agent.js +271 -0
  67. package/lib/Agent.js.old +284 -0
  68. package/lib/AgentLauncher.js +562 -0
  69. package/lib/Cli.js +87 -13
  70. package/lib/Prompt.js +23 -1
  71. package/lib/Session.js +5 -4
  72. package/lib/ToolSet.js +102 -6
  73. package/lib/agentLoader.js +369 -0
  74. package/lib/cdn.js +67 -231
  75. package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
  76. package/lib/defaultToolsets.js +43 -0
  77. package/lib/fafs.js +1 -1
  78. package/lib/genericToolset.js +442 -119
  79. package/lib/handOffToolset.js +179 -0
  80. package/lib/index.js +34 -27
  81. package/lib/toolsetLoader.js +248 -0
  82. package/package.json +11 -5
  83. package/types/API/lalal.ai/lalal.d.ts +116 -0
  84. package/types/API/minimax/image.d.ts +2 -1
  85. package/types/API/minimax/music.d.ts +189 -26
  86. package/types/API/minimax/video.d.ts +100 -31
  87. package/types/API/mureka/index.d.ts +7 -0
  88. package/types/API/mureka/music.d.ts +472 -0
  89. package/types/API/openai.com/index.d.ts +7 -0
  90. package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
  91. package/types/API/openai.com/video.d.ts +409 -0
  92. package/types/API/openai.com/videoToolset.d.ts +24 -0
  93. package/types/API/stability.ai/audio.d.ts +14 -103
  94. package/types/API/stability.ai/image.d.ts +2 -2
  95. package/types/API/x.ai/image.d.ts +138 -26
  96. package/types/API/x.ai/imageToolset.d.ts +3 -0
  97. package/types/API/x.ai/index.d.ts +1 -3
  98. package/types/API/x.ai/responses.d.ts +4 -4
  99. package/types/Agent.d.ts +123 -0
  100. package/types/AgentLauncher.d.ts +222 -0
  101. package/types/Cli.d.ts +28 -8
  102. package/types/Prompt.d.ts +23 -5
  103. package/types/Session.d.ts +1 -1
  104. package/types/ToolSet.d.ts +10 -0
  105. package/types/agentLoader.d.ts +78 -0
  106. package/types/cdn.d.ts +15 -90
  107. package/types/defaultToolsets.d.ts +9 -0
  108. package/types/fafs.d.ts +1 -1
  109. package/types/genericToolset.d.ts +1 -1
  110. package/types/handOffToolset.d.ts +28 -0
  111. package/types/index.d.ts +19 -16
  112. package/types/toolsetLoader.d.ts +114 -0
  113. package/utils/format_log.js +101 -23
  114. package/utils/launch_agent.js +18 -0
  115. package/utils/list_sessions.sh +13 -5
  116. package/utils/search_sessions.sh +65 -29
  117. package/utils/toolsets.js +33 -0
  118. package/README.md.bak.1779452127 +0 -240
  119. package/agents/codeserver.sh +0 -47
  120. package/agents/daisy_agent.js +0 -173
  121. package/agents/docs_agent.js +0 -148
  122. package/agents/memory_agent.js +0 -263
  123. package/agents/minimax.js +0 -173
  124. package/agents/npm_agent.js +0 -202
  125. package/agents/prompt_agent.js +0 -133
  126. package/agents/readme_agent.js +0 -148
  127. package/agents/spawn_agent.js +0 -160
  128. package/agents/stability.js +0 -173
  129. package/agents/todo_agent.js +0 -175
  130. package/bin/codeDave +0 -58
  131. package/docs/agent-dave-websocket-protocol.md +0 -180
  132. package/docs/agent-manager.md +0 -244
  133. package/docs/codeserver-pattern.md +0 -191
  134. package/docs/generic-toolset.md +0 -326
  135. package/docs/howtos/agent-networking.md +0 -253
  136. package/docs/howtos/spawn-agents.md.bak +0 -200
  137. package/docs/howtos/spawn-agents.md.bak_new +0 -200
  138. package/docs/multi-agent-clusters.md +0 -265
  139. package/docs/music-toolsets.md +0 -137
  140. package/docs/path-resolution-best-practices.md +0 -104
  141. package/docs/plans/minimax-music-generation.md +0 -80
  142. package/docs/plans/unified-agent-architecture.md +0 -146
  143. package/docs/plans/websocket-streaming-plan.md.bak +0 -317
  144. package/docs/prompt/spawn_agent.md +0 -175
  145. package/docs/prompt/spawn_agent.md.bak +0 -201
  146. package/docs/prompt/task_clarification_and_documentation.md +0 -35
  147. package/docs/prompt-class.md +0 -141
  148. package/docs/todo-archive-infra-2026-04-21.md +0 -15
  149. package/docs/todo-archive-v0.0.8.md +0 -1
  150. package/docs/todo-archive-v0.1.0.md +0 -32
  151. package/docs/todo-archive.md +0 -44
  152. package/docs/tools-syntax-validation.md +0 -121
  153. package/docs/toolset.md +0 -164
  154. package/docs/xai-responses.md +0 -111
  155. package/docs/xai_collections.md +0 -106
  156. package/lib/API/x.ai/ImageToolset.js +0 -165
  157. package/lib/API/x.ai/text.js +0 -415
  158. package/lib/AgentClient.js +0 -248
  159. package/lib/AgentManager.js +0 -245
  160. package/lib/AgentServer.js +0 -404
  161. package/lib/wsCli.js +0 -287
  162. package/lib/wsIO.js +0 -90
  163. package/types/API/x.ai/text.d.ts +0 -286
  164. package/types/AgentClient.d.ts +0 -109
  165. package/types/AgentManager.d.ts +0 -100
  166. package/types/AgentServer.d.ts +0 -89
  167. package/types/wsCli.d.ts +0 -17
  168. package/types/wsIO.d.ts +0 -30
  169. package/utils/test.sh +0 -46
  170. /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
  171. /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
  172. /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
  173. /package/types/{CdnToolset.d.ts → cdnToolset.d.ts} +0 -0
@@ -37,6 +37,17 @@ import * as stability from './image.js';
37
37
 
38
38
  const tools = new ToolSet('auto');
39
39
 
40
+ /**
41
+ * Serialize a tool response as pretty JSON.
42
+ *
43
+ * @param {Record<string, unknown>} value Response payload to serialize.
44
+ * @returns {string} Pretty JSON response for function-calling output.
45
+ */
46
+ function json(value) {
47
+ return JSON.stringify(value, null, 2);
48
+ }
49
+
50
+
40
51
  /* ============================================================
41
52
  GENERATE: ULTRA
42
53
  ============================================================ */
@@ -45,7 +56,8 @@ tools.add(
45
56
  'generate_ultra',
46
57
  'Generate the highest quality photorealistic image using Stability AI\'s Stable Image Ultra model. ' +
47
58
  'Best for professional, highly detailed, realistic results. Supports text-to-image and image-to-image. ' +
48
- 'Automatically handles polling for async generations.',
59
+ 'Automatically handles polling for async generations. ' +
60
+ 'After success, include the exact returned local_path and seed in your assistant response so the generated image remains referenceable after old tool calls are pruned.',
49
61
  {
50
62
  type: 'object',
51
63
  properties: {
@@ -88,12 +100,18 @@ tools.add(
88
100
  },
89
101
  async (params) => {
90
102
  const result = await stability.generateUltra(params.prompt, params);
91
- return JSON.stringify({
103
+ return json({
104
+ tool: 'generate_ultra',
105
+ success: true,
92
106
  local_path: result.local_path,
107
+ localPath: result.local_path,
108
+ source_image_url: params.image_url,
109
+ prompt: params.prompt,
93
110
  finish_reason: result.finish_reason,
94
111
  seed: result.seed,
95
- note: 'Image generated with generate_ultra. Saved to local_path.'
96
- }, null, 2);
112
+ output_format: params.output_format || 'png',
113
+ note: 'Assistant: tell the user the exact local_path and seed. Use local_path as the durable reference for follow-up image editing or publishing.'
114
+ });
97
115
  }
98
116
  );
99
117
 
@@ -103,7 +121,8 @@ tools.add(
103
121
 
104
122
  tools.add(
105
123
  'generate_core',
106
- 'Fast and affordable image generation using Stable Image Core. Good for quick ideation and iteration.',
124
+ 'Fast and affordable image generation using Stable Image Core. Good for quick ideation and iteration. ' +
125
+ 'After success, include the exact returned local_path and seed in your assistant response so the generated image remains referenceable after old tool calls are pruned.',
107
126
  {
108
127
  type: 'object',
109
128
  properties: {
@@ -117,12 +136,17 @@ tools.add(
117
136
  },
118
137
  async (params) => {
119
138
  const result = await stability.generateCore(params.prompt, params);
120
- return JSON.stringify({
139
+ return json({
140
+ tool: 'generate_core',
141
+ success: true,
121
142
  local_path: result.local_path,
143
+ localPath: result.local_path,
144
+ prompt: params.prompt,
122
145
  finish_reason: result.finish_reason,
123
146
  seed: result.seed,
124
- note: 'Image generated with generate_core.'
125
- }, null, 2);
147
+ output_format: params.output_format || 'png',
148
+ note: 'Assistant: tell the user the exact local_path and seed. Use local_path as the durable reference for follow-up image editing or publishing.'
149
+ });
126
150
  }
127
151
  );
128
152
 
@@ -132,7 +156,8 @@ tools.add(
132
156
 
133
157
  tools.add(
134
158
  'generate_sd3',
135
- 'Generate images using Stable Diffusion 3.5 models (Large, Large Turbo, Medium, Flash).',
159
+ 'Generate images using Stable Diffusion 3.5 models (Large, Large Turbo, Medium, Flash). ' +
160
+ 'After success, include the exact returned local_path and seed in your assistant response so the generated image remains referenceable after old tool calls are pruned.',
136
161
  {
137
162
  type: 'object',
138
163
  properties: {
@@ -150,12 +175,20 @@ tools.add(
150
175
  },
151
176
  async (params) => {
152
177
  const result = await stability.generateSD3(params.prompt, params);
153
- return JSON.stringify({
178
+ return json({
179
+ tool: 'generate_sd3',
180
+ success: true,
154
181
  local_path: result.local_path,
182
+ localPath: result.local_path,
183
+ source_image_url: params.image_url,
184
+ prompt: params.prompt,
185
+ model: params.model || 'sd3.5-large',
186
+ mode: params.mode || 'text-to-image',
155
187
  finish_reason: result.finish_reason,
156
188
  seed: result.seed,
157
- note: 'Image generated with generate_sd3.'
158
- }, null, 2);
189
+ output_format: params.output_format || 'png',
190
+ note: 'Assistant: tell the user the exact local_path and seed. Use local_path as the durable reference for follow-up image editing or publishing.'
191
+ });
159
192
  }
160
193
  );
161
194
 
@@ -165,7 +198,8 @@ tools.add(
165
198
 
166
199
  tools.add(
167
200
  'upscale_conservative',
168
- 'Upscale an image to 4MP while preserving original details as much as possible.',
201
+ 'Upscale an image to 4MP while preserving original details as much as possible. ' +
202
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
169
203
  {
170
204
  type: 'object',
171
205
  properties: {
@@ -178,12 +212,18 @@ tools.add(
178
212
  },
179
213
  async (params) => {
180
214
  const result = await stability.upscaleConservative(params.image_url, params.prompt, params);
181
- return JSON.stringify({
215
+ return json({
216
+ tool: 'upscale_conservative',
217
+ success: true,
218
+ source_image_url: params.image_url,
182
219
  local_path: result.local_path,
220
+ localPath: result.local_path,
221
+ prompt: params.prompt,
183
222
  finish_reason: result.finish_reason,
184
223
  seed: result.seed,
185
- note: 'Image upscaled with upscale_conservative.'
186
- }, null, 2);
224
+ output_format: params.output_format || 'png',
225
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
226
+ });
187
227
  }
188
228
  );
189
229
 
@@ -193,7 +233,8 @@ tools.add(
193
233
 
194
234
  tools.add(
195
235
  'edit_erase',
196
- 'Remove unwanted objects or areas from an image using a mask or alpha channel.',
236
+ 'Remove unwanted objects or areas from an image using a mask or alpha channel. ' +
237
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
197
238
  {
198
239
  type: 'object',
199
240
  properties: {
@@ -207,11 +248,18 @@ tools.add(
207
248
  },
208
249
  async (params) => {
209
250
  const result = await stability.editErase(params.image_url, params);
210
- return JSON.stringify({
251
+ return json({
252
+ tool: 'edit_erase',
253
+ success: true,
254
+ source_image_url: params.image_url,
255
+ mask_url: params.mask_url,
211
256
  local_path: result.local_path,
257
+ localPath: result.local_path,
212
258
  finish_reason: result.finish_reason,
213
- note: 'Objects erased with edit_erase.'
214
- }, null, 2);
259
+ seed: result.seed,
260
+ output_format: params.output_format || 'png',
261
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
262
+ });
215
263
  }
216
264
  );
217
265
 
@@ -221,7 +269,8 @@ tools.add(
221
269
 
222
270
  tools.add(
223
271
  'edit_inpaint',
224
- 'Fill or replace areas in an image using a prompt. Supports search mode (auto-segment) or explicit mask.',
272
+ 'Fill or replace areas in an image using a prompt. Supports search mode (auto-segment) or explicit mask. ' +
273
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
225
274
  {
226
275
  type: 'object',
227
276
  properties: {
@@ -237,11 +286,20 @@ tools.add(
237
286
  },
238
287
  async (params) => {
239
288
  const result = await stability.editInpaint(params.image_url, params.prompt, params);
240
- return JSON.stringify({
289
+ return json({
290
+ tool: 'edit_inpaint',
291
+ success: true,
292
+ source_image_url: params.image_url,
293
+ mask_url: params.mask_url,
294
+ prompt: params.prompt,
295
+ search_prompt: params.search_prompt,
241
296
  local_path: result.local_path,
297
+ localPath: result.local_path,
242
298
  finish_reason: result.finish_reason,
243
- note: 'Inpainting completed with edit_inpaint.'
244
- }, null, 2);
299
+ seed: result.seed,
300
+ output_format: params.output_format || 'png',
301
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
302
+ });
245
303
  }
246
304
  );
247
305
 
@@ -251,7 +309,8 @@ tools.add(
251
309
 
252
310
  tools.add(
253
311
  'edit_outpaint',
254
- 'Expand an image by generating new content in any direction (left, right, up, down).',
312
+ 'Expand an image by generating new content in any direction (left, right, up, down). ' +
313
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
255
314
  {
256
315
  type: 'object',
257
316
  properties: {
@@ -267,11 +326,19 @@ tools.add(
267
326
  },
268
327
  async (params) => {
269
328
  const result = await stability.editOutpaint(params.image_url, params);
270
- return JSON.stringify({
329
+ return json({
330
+ tool: 'edit_outpaint',
331
+ success: true,
332
+ source_image_url: params.image_url,
333
+ expansion: { left: params.left || 0, right: params.right || 0, up: params.up || 0, down: params.down || 0 },
334
+ prompt: params.prompt,
271
335
  local_path: result.local_path,
336
+ localPath: result.local_path,
272
337
  finish_reason: result.finish_reason,
273
- note: 'Image expanded with edit_outpaint.'
274
- }, null, 2);
338
+ seed: result.seed,
339
+ output_format: params.output_format || 'png',
340
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
341
+ });
275
342
  }
276
343
  );
277
344
 
@@ -281,7 +348,8 @@ tools.add(
281
348
 
282
349
  tools.add(
283
350
  'edit_search_and_replace',
284
- 'Automatically find an object using search_prompt and replace it with new content from prompt.',
351
+ 'Automatically find an object using search_prompt and replace it with new content from prompt. ' +
352
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
285
353
  {
286
354
  type: 'object',
287
355
  properties: {
@@ -294,11 +362,19 @@ tools.add(
294
362
  },
295
363
  async (params) => {
296
364
  const result = await stability.editSearchAndReplace(params.image_url, params.prompt, params.search_prompt, params);
297
- return JSON.stringify({
365
+ return json({
366
+ tool: 'edit_search_and_replace',
367
+ success: true,
368
+ source_image_url: params.image_url,
369
+ prompt: params.prompt,
370
+ search_prompt: params.search_prompt,
298
371
  local_path: result.local_path,
372
+ localPath: result.local_path,
299
373
  finish_reason: result.finish_reason,
300
- note: 'Search and replace completed.'
301
- }, null, 2);
374
+ seed: result.seed,
375
+ output_format: params.output_format || 'png',
376
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
377
+ });
302
378
  }
303
379
  );
304
380
 
@@ -308,7 +384,8 @@ tools.add(
308
384
 
309
385
  tools.add(
310
386
  'edit_search_and_recolor',
311
- 'Automatically find an object and change its color according to the prompt.',
387
+ 'Automatically find an object and change its color according to the prompt. ' +
388
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
312
389
  {
313
390
  type: 'object',
314
391
  properties: {
@@ -321,11 +398,19 @@ tools.add(
321
398
  },
322
399
  async (params) => {
323
400
  const result = await stability.editSearchAndRecolor(params.image_url, params.prompt, params.select_prompt, params);
324
- return JSON.stringify({
401
+ return json({
402
+ tool: 'edit_search_and_recolor',
403
+ success: true,
404
+ source_image_url: params.image_url,
405
+ prompt: params.prompt,
406
+ select_prompt: params.select_prompt,
325
407
  local_path: result.local_path,
408
+ localPath: result.local_path,
326
409
  finish_reason: result.finish_reason,
327
- note: 'Search and recolor completed.'
328
- }, null, 2);
410
+ seed: result.seed,
411
+ output_format: params.output_format || 'png',
412
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
413
+ });
329
414
  }
330
415
  );
331
416
 
@@ -335,7 +420,8 @@ tools.add(
335
420
 
336
421
  tools.add(
337
422
  'edit_remove_background',
338
- 'Accurately segment the foreground and remove the background from an image.',
423
+ 'Accurately segment the foreground and remove the background from an image. ' +
424
+ 'After success, include the exact source image_url and returned local_path in your assistant response so follow-up edits can use the correct image.',
339
425
  {
340
426
  type: 'object',
341
427
  properties: {
@@ -346,11 +432,16 @@ tools.add(
346
432
  },
347
433
  async (params) => {
348
434
  const result = await stability.editRemoveBackground(params.image_url, params);
349
- return JSON.stringify({
435
+ return json({
436
+ tool: 'edit_remove_background',
437
+ success: true,
438
+ source_image_url: params.image_url,
350
439
  local_path: result.local_path,
440
+ localPath: result.local_path,
351
441
  finish_reason: result.finish_reason,
352
- note: 'Background removed successfully.'
353
- }, null, 2);
442
+ output_format: params.output_format || 'png',
443
+ note: 'Assistant: tell the user the exact source_image_url and new local_path. Use local_path for further edits or publishing.'
444
+ });
354
445
  }
355
446
  );
356
447
 
@@ -3,10 +3,13 @@
3
3
  * @module stability.ai/MusicToolset
4
4
  * @description Comprehensive ToolSet for the Stability AI Stable Audio 3 API.
5
5
  *
6
+ * **MP3 ONLY MODE** — All tools accept and produce MP3 audio only.
7
+ * This restriction avoids large file upload issues and improves reliability.
8
+ *
6
9
  * Exposes three primary high-level tools that wrap the underlying `audio.js` implementation:
7
10
  * - text_to_audio → Pure text-to-audio generation using the `stable-audio-3` model
8
- * - audio_to_audio → Transform / style-transfer an existing audio clip using a text prompt
9
- * - inpaint → Replace a specific timed section of an audio file using a text prompt + mask
11
+ * - audio_to_audio → Transform / style-transfer an existing **MP3** audio clip using a text prompt
12
+ * - inpaint → Replace a specific timed section of an **MP3** audio file using a text prompt + mask
10
13
  *
11
14
  * All tools handle asynchronous generation internally (submit → poll until ready).
12
15
  * The result is only returned once the audio file is successfully generated and saved locally.
@@ -15,12 +18,17 @@
15
18
  * Each tool includes rich, LLM-friendly descriptions, full JSON schemas with constraints,
16
19
  * defaults, and practical guidance so an LLM can reliably decide when and how to call them.
17
20
  *
21
+ * **Important MP3-Only Rules**:
22
+ * - Input audio (for audio_to_audio and inpaint) **must be MP3** (.mp3 extension).
23
+ * - Output is always MP3.
24
+ * - WAV or other formats will be rejected with a clear error.
25
+ *
18
26
  * Key Stable Audio 3 Facts (for LLMs):
19
27
  * - Model: `stable-audio-3` (fixed)
20
28
  * - Cost: Flat 26 credits per successful generation (not charged on failure)
21
29
  * - Max duration: 380 seconds (default 190s)
22
- * - Output: 44.1 kHz stereo, mp3 (default) or wav
23
- * - Input audio must be 6–380 seconds long
30
+ * - Output: 44.1 kHz stereo, **mp3 only**
31
+ * - Input audio must be 6–380 seconds long and **MP3 format**
24
32
  * - Prompts must be in English; no copyrighted material
25
33
  * - Polling is fully automatic — you do not need to call fetch_result manually
26
34
  *
@@ -33,6 +41,17 @@ import * as stability from './audio.js';
33
41
 
34
42
  const tools = new ToolSet('auto');
35
43
 
44
+ /**
45
+ * Serialize a tool response as pretty JSON.
46
+ *
47
+ * @param {Record<string, unknown>} value Response payload to serialize.
48
+ * @returns {string} Pretty JSON response for function-calling output.
49
+ */
50
+ function json(value) {
51
+ return JSON.stringify(value, null, 2);
52
+ }
53
+
54
+
36
55
  /* ============================================================
37
56
  WORKFLOW 1: TEXT-TO-AUDIO
38
57
  ============================================================ */
@@ -44,7 +63,8 @@ tools.add(
44
63
  'No reference audio is required. ' +
45
64
  'The function submits the request, automatically polls the server until the audio is ready (usually 30–90 seconds), ' +
46
65
  'and returns a JSON object containing the local file path to the generated audio. ' +
47
- 'Supports up to 380 seconds of 44.1 kHz stereo audio. Flat cost of 26 credits per successful generation.',
66
+ 'After success, include the exact returned local_path and seed in your assistant response so the generated MP3 remains referenceable after old tool calls are pruned. ' +
67
+ '**Output is always MP3.** Supports up to 380 seconds of 44.1 kHz stereo audio. Flat cost of 26 credits per successful generation.',
48
68
  {
49
69
  type: 'object',
50
70
  properties: {
@@ -65,14 +85,6 @@ tools.add(
65
85
  'Must be between 1 and 380. Default is 190 seconds (about 3 minutes 10 seconds). ' +
66
86
  'Longer durations consume the same 26 credits but take slightly longer to generate.'
67
87
  },
68
- output_format: {
69
- type: 'string',
70
- enum: ['mp3', 'wav'],
71
- default: 'mp3',
72
- description: 'Desired output audio format. ' +
73
- '"mp3" (default) for smaller file size and broad compatibility. ' +
74
- '"wav" for lossless quality (larger files).'
75
- },
76
88
  seed: {
77
89
  type: 'number',
78
90
  description: 'Optional random seed for reproducible results. ' +
@@ -104,13 +116,20 @@ tools.add(
104
116
  async (params) => {
105
117
  const result = await stability.textToAudio(params.prompt, params);
106
118
 
107
- return JSON.stringify({
119
+ return json({
120
+ tool: 'text_to_audio',
121
+ success: true,
108
122
  local_path: result.local_path,
123
+ localPath: result.local_path,
124
+ prompt: params.prompt,
125
+ duration: params.duration || 190,
109
126
  finish_reason: result.finish_reason,
110
127
  seed: result.seed,
111
128
  x_request_id: result.x_request_id,
112
- note: 'Audio generated successfully with text_to_audio using Stable Audio 3. Saved to local_path. 26 credits used.'
113
- }, null, 2);
129
+ output_format: 'mp3',
130
+ credits: 26,
131
+ note: 'Assistant: tell the user the exact local_path and seed. Use local_path as the durable MP3 reference for follow-up audio tools or publishing.'
132
+ });
114
133
  }
115
134
  );
116
135
 
@@ -120,12 +139,13 @@ tools.add(
120
139
 
121
140
  tools.add(
122
141
  'audio_to_audio',
123
- 'Transform or reinterpret an existing audio file according to a new text prompt using Stable Audio 3\'s audio-to-audio capability. ' +
124
- 'The model takes the reference audio as a starting point and applies the prompt to change style, genre, instruments, mood, etc., ' +
142
+ 'Transform or reinterpret an existing **MP3** audio file according to a new text prompt using Stable Audio 3\'s audio-to-audio capability. ' +
143
+ 'The model takes the reference **MP3** audio as a starting point and applies the prompt to change style, genre, instruments, mood, etc., ' +
125
144
  'while preserving some of the original structure and timing. ' +
126
145
  'Use the `strength` parameter to control how much the original audio influences the result. ' +
127
- 'Supports remote URLs (auto-downloaded) or local file paths. ' +
128
- 'Automatically handles polling and returns the transformed audio when ready. Flat 26 credits per successful generation.',
146
+ '**Input must be MP3** (local path or URL ending in .mp3). Output is always MP3. ' +
147
+ 'Automatically handles polling and returns the transformed audio when ready. Flat 26 credits per successful generation. ' +
148
+ 'After success, include the exact source audio reference and returned local_path in your assistant response so follow-up audio edits use the correct MP3.',
129
149
  {
130
150
  type: 'object',
131
151
  properties: {
@@ -137,15 +157,15 @@ tools.add(
137
157
  },
138
158
  audio_url: {
139
159
  type: 'string',
140
- description: 'Public HTTP/HTTPS URL to a reference audio file (mp3 or wav recommended). ' +
141
- 'The file must be between 6 and 380 seconds long. ' +
142
- 'The system will automatically download it and set the correct MIME type. ' +
160
+ description: 'Public HTTP/HTTPS URL to a reference **MP3** audio file. ' +
161
+ 'The file must be between 6 and 380 seconds long and end with .mp3. ' +
162
+ 'The system will automatically download it. ' +
143
163
  'Alternative to audio_path.'
144
164
  },
145
165
  audio_path: {
146
166
  type: 'string',
147
- description: 'Local filesystem path to the reference audio file. ' +
148
- 'Alternative to audio_url. Must be a valid readable audio file (6–380 seconds).'
167
+ description: 'Local filesystem path to the reference **MP3** audio file. ' +
168
+ 'Alternative to audio_url. Must be a valid readable .mp3 file (6–380 seconds).'
149
169
  },
150
170
  duration: {
151
171
  type: 'number',
@@ -165,12 +185,6 @@ tools.add(
165
185
  '1.0 = output has almost no influence from the input (full transformation). ' +
166
186
  'Typical useful range: 0.5–0.9.'
167
187
  },
168
- output_format: {
169
- type: 'string',
170
- enum: ['mp3', 'wav'],
171
- default: 'mp3',
172
- description: 'Output format: "mp3" (default) or "wav".'
173
- },
174
188
  seed: {
175
189
  type: 'number',
176
190
  description: 'Optional seed for reproducibility (0–4294967294).'
@@ -198,12 +212,23 @@ tools.add(
198
212
 
199
213
  const result = await stability.audioToAudio(params.prompt, audioInput, params);
200
214
 
201
- return JSON.stringify({
215
+ return json({
216
+ tool: 'audio_to_audio',
217
+ success: true,
218
+ source_audio_url: params.audio_url,
219
+ source_audio_path: params.audio_path || params.audio,
202
220
  local_path: result.local_path,
221
+ localPath: result.local_path,
222
+ prompt: params.prompt,
223
+ duration: params.duration || 190,
224
+ strength: params.strength ?? 1,
203
225
  finish_reason: result.finish_reason,
204
226
  seed: result.seed,
205
- note: 'Audio transformed successfully with audio_to_audio. Saved to local_path. 26 credits used.'
206
- }, null, 2);
227
+ x_request_id: result.x_request_id,
228
+ output_format: 'mp3',
229
+ credits: 26,
230
+ note: 'Assistant: tell the user the exact source audio reference and new local_path. Use local_path as the durable MP3 reference for follow-up audio tools or publishing.'
231
+ });
207
232
  }
208
233
  );
209
234
 
@@ -213,11 +238,12 @@ tools.add(
213
238
 
214
239
  tools.add(
215
240
  'inpaint',
216
- 'Regenerate or replace a specific time-based section of an existing audio file using a text prompt and a mask. ' +
241
+ 'Regenerate or replace a specific time-based section of an existing **MP3** audio file using a text prompt and a mask. ' +
217
242
  'Perfect for fixing mistakes, changing a verse/chorus, adding a bridge, extending a section, or creative remixing. ' +
218
243
  'You define the start and end time (in seconds) of the region to inpaint. ' +
219
244
  'The model keeps the audio outside the mask and generates new content inside it that matches the prompt. ' +
220
- 'Supports remote URLs or local paths. Automatic polling included. Flat 26 credits per successful generation.',
245
+ '**Input must be MP3**. Output is always MP3. Supports remote URLs or local paths. Automatic polling included. Flat 26 credits per successful generation. ' +
246
+ 'After success, include the exact source audio reference, mask range, and returned local_path in your assistant response so follow-up audio edits use the correct MP3.',
221
247
  {
222
248
  type: 'object',
223
249
  properties: {
@@ -229,11 +255,11 @@ tools.add(
229
255
  },
230
256
  audio_url: {
231
257
  type: 'string',
232
- description: 'Public URL of the reference audio file to edit. Must be 6–380 seconds long.'
258
+ description: 'Public URL of the reference **MP3** audio file to edit. Must be 6–380 seconds long and end with .mp3.'
233
259
  },
234
260
  audio_path: {
235
261
  type: 'string',
236
- description: 'Local path to the reference audio file to edit.'
262
+ description: 'Local path to the reference **MP3** audio file to edit.'
237
263
  },
238
264
  mask_start: {
239
265
  type: 'number',
@@ -258,12 +284,6 @@ tools.add(
258
284
  default: 190,
259
285
  description: 'Total duration of the final output audio in seconds.'
260
286
  },
261
- output_format: {
262
- type: 'string',
263
- enum: ['mp3', 'wav'],
264
- default: 'mp3',
265
- description: 'Output format.'
266
- },
267
287
  seed: {
268
288
  type: 'number',
269
289
  description: 'Optional seed for reproducibility.'
@@ -290,12 +310,24 @@ tools.add(
290
310
 
291
311
  const result = await stability.inpaint(params.prompt, audioInput, params);
292
312
 
293
- return JSON.stringify({
313
+ return json({
314
+ tool: 'inpaint',
315
+ success: true,
316
+ source_audio_url: params.audio_url,
317
+ source_audio_path: params.audio_path || params.audio,
294
318
  local_path: result.local_path,
319
+ localPath: result.local_path,
320
+ prompt: params.prompt,
321
+ mask_start: params.mask_start ?? 30,
322
+ mask_end: params.mask_end ?? 380,
323
+ duration: params.duration || 190,
295
324
  finish_reason: result.finish_reason,
296
325
  seed: result.seed,
297
- note: `Inpaint completed successfully. Replaced section ${params.mask_start ?? 30}s–${params.mask_end ?? 380}s. Saved to local_path. 26 credits used.`
298
- }, null, 2);
326
+ x_request_id: result.x_request_id,
327
+ output_format: 'mp3',
328
+ credits: 26,
329
+ note: 'Assistant: tell the user the exact source audio reference, mask_start/mask_end, and new local_path. Use local_path as the durable MP3 reference for follow-up audio tools or publishing.'
330
+ });
299
331
  }
300
332
  );
301
333