@j-o-r/hello-dave 0.1.1 → 0.1.5

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 -1
  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 +593 -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 +10 -4
  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 -1
  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 +250 -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 -17
  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
@@ -0,0 +1,646 @@
1
+ /**
2
+ * @file lib/API/mureka/MusicToolset.js
3
+ * @module mureka/MusicToolset
4
+ * @description Comprehensive ToolSet for the Mureka AI Music API.
5
+ *
6
+ * This ToolSet is designed for AI agents / LLMs. Every tool has rich, detailed documentation
7
+ * so that language models understand exactly when and how to use each function.
8
+ *
9
+ * **Key behavior**: Most generation tools automatically wait for async tasks to complete
10
+ * and return the final result (including locally saved audio paths).
11
+ */
12
+
13
+ import ToolSet from '../../ToolSet.js';
14
+ import * as mureka from './music.js';
15
+
16
+ const tools = new ToolSet('auto');
17
+
18
+ /* ============================================================
19
+ HELPER: Merge extra params into top level (prevents 404s)
20
+ ============================================================ */
21
+ function mergeExtra(params) {
22
+ const { extra = {}, ...rest } = params;
23
+ return { ...rest, ...extra };
24
+ }
25
+
26
+ /**
27
+ * Serialize a tool response as pretty JSON.
28
+ *
29
+ * @param {Record<string, unknown>} value Response payload to serialize.
30
+ * @returns {string} Pretty JSON response for function-calling output.
31
+ */
32
+ function json(value) {
33
+ return JSON.stringify(value, null, 2);
34
+ }
35
+
36
+ /**
37
+ * Convert Mureka audio choices to compact durable references.
38
+ *
39
+ * @param {unknown} choices Possible Mureka choices array.
40
+ * @returns {Array<Record<string, unknown>>|undefined} Compact choice references, when present.
41
+ */
42
+ function summarizeChoices(choices) {
43
+ if (!Array.isArray(choices)) return undefined;
44
+ return choices.map((choice, index) => ({
45
+ index: choice?.index ?? index,
46
+ choice_id: choice?.id,
47
+ id: choice?.id,
48
+ url: choice?.url,
49
+ audio_url: choice?.url,
50
+ flac_url: choice?.flac_url,
51
+ wav_url: choice?.wav_url,
52
+ duration: choice?.duration,
53
+ local_path: choice?.local_path,
54
+ localPath: choice?.local_path,
55
+ local_flac_path: choice?.local_flac_path,
56
+ local_wav_path: choice?.local_wav_path
57
+ }));
58
+ }
59
+
60
+ /**
61
+ * Build a self-describing tool response that preserves durable Mureka IDs,
62
+ * URLs, local paths, and status fields so the assistant can repeat them in a
63
+ * normal message before old raw function-call transcripts are pruned.
64
+ *
65
+ * @param {string} tool Tool name.
66
+ * @param {Record<string, unknown>} result Raw wrapper result.
67
+ * @param {Record<string, unknown>} [context={}] Request context worth preserving.
68
+ * @param {string} note Assistant-facing instruction for normal response content.
69
+ * @returns {Record<string, unknown>} Self-describing tool response payload.
70
+ */
71
+ function murekaToolResponse(tool, result, context = {}, note) {
72
+ const choices = summarizeChoices(result?.choices);
73
+ const firstChoice = choices?.[0];
74
+ const localPaths = result?.local_paths || choices?.map(choice => choice.local_path).filter(Boolean);
75
+ const audioUrls = choices?.map(choice => choice.audio_url).filter(Boolean);
76
+
77
+ const songTools = new Set([
78
+ 'generate_song',
79
+ 'generate_instrumental',
80
+ 'generate_soundtrack',
81
+ 'extend_song',
82
+ 'stem_song',
83
+ 'region_edit_song',
84
+ 'generate_track',
85
+ 'remix_song',
86
+ 'generate_speech',
87
+ 'query_task'
88
+ ]);
89
+ const uploadId = tool === 'upload_file' ? result?.file_id || result?.id : result?.file_id;
90
+ const voiceId = tool === 'clone_voice' ? result?.voice_id || result?.vocal_id || result?.id : result?.voice_id || result?.vocal_id;
91
+
92
+ return {
93
+ tool,
94
+ success: true,
95
+ ...context,
96
+ id: result?.id,
97
+ song_id: songTools.has(tool) ? result?.id : undefined,
98
+ task_id: result?.task_id,
99
+ file_id: result?.file_id,
100
+ upload_audio_id: uploadId,
101
+ voice_id: voiceId,
102
+ vocal_id: voiceId,
103
+ status: result?.status,
104
+ model: result?.model,
105
+ trace_id: result?.trace_id,
106
+ local_path: result?.local_path || firstChoice?.local_path || localPaths?.[0],
107
+ localPath: result?.local_path || firstChoice?.local_path || localPaths?.[0],
108
+ local_paths: localPaths,
109
+ localPaths,
110
+ audio_url: result?.audio_url || result?.mp3_url || firstChoice?.audio_url || audioUrls?.[0],
111
+ mp3_url: result?.mp3_url || firstChoice?.audio_url || audioUrls?.[0],
112
+ audio_urls: audioUrls,
113
+ choices,
114
+ result,
115
+ note
116
+ };
117
+ }
118
+
119
+ /* ============================================================
120
+ SONG GENERATION
121
+ ============================================================ */
122
+
123
+ tools.add(
124
+ 'generate_song',
125
+ 'Generate a complete song with both lyrics and vocals. This is the main "text-to-song" tool.\n\n' +
126
+ 'Use this when you want a full vocal song. Provide a good `prompt` describing style/mood/genre. ' +
127
+ 'You can optionally provide structured `lyrics`. If you omit lyrics, the model will generate them.\n\n' +
128
+ 'You can also provide `reference_id`, `vocal_id`, or `motif_id` (obtained from upload_file or cloneVocal) ' +
129
+ 'to guide the generation with existing audio or voices. After success, include exact song_id/id, local_path/local_paths, audio_url, and status in your normal response so follow-up calls can reference them.',
130
+ {
131
+ type: 'object',
132
+ properties: {
133
+ prompt: {
134
+ type: 'string',
135
+ description: 'Description of the desired style, mood, genre, and scenario. ' +
136
+ 'Example: "Upbeat indie pop, energetic, summer road trip vibe, bright synths, driving drums". ' +
137
+ 'This is the most important parameter. Be descriptive.'
138
+ },
139
+ lyrics: {
140
+ type: 'string',
141
+ description: 'Structured song lyrics. Use section tags like [Verse], [Chorus], [Bridge], [Intro], [Outro]. ' +
142
+ 'Example: "[Verse]\\nWindows down, wind in my hair\\n[Chorus]\\nWe’re chasing the horizon". ' +
143
+ 'Optional — the model can generate lyrics from the prompt if omitted.'
144
+ },
145
+ model: {
146
+ type: 'string',
147
+ default: 'auto',
148
+ description: 'Model to use. Default "auto" lets Mureka choose the best model. ' +
149
+ 'Other values may be supported — check current documentation.'
150
+ },
151
+ reference_id: {
152
+ type: 'string',
153
+ description: 'File ID of a reference audio track (obtained via upload_file with purpose "reference"). ' +
154
+ 'Use this to make the new song sound similar in style or arrangement to the reference.'
155
+ },
156
+ vocal_id: {
157
+ type: 'string',
158
+ description: 'Voice ID from a previously cloned voice (obtained via cloneVocal). ' +
159
+ 'Use this if you want the song to be sung with a specific custom voice.'
160
+ },
161
+ motif_id: {
162
+ type: 'string',
163
+ description: 'Melody motif file ID. Use this to guide the melodic structure of the song.'
164
+ },
165
+ extra: {
166
+ type: 'object',
167
+ description: 'Additional advanced parameters passed directly to the API (rarely needed).'
168
+ }
169
+ },
170
+ required: ['prompt']
171
+ },
172
+ async (params) => {
173
+ const merged = mergeExtra(params);
174
+ const result = await mureka.generateSong(merged);
175
+ return json(murekaToolResponse('generate_song', result, { prompt: params.prompt, reference_id: params.reference_id, vocal_id: params.vocal_id, motif_id: params.motif_id }, 'Assistant: tell the user the exact song_id/id, status, local_path/local_paths, and audio_url/mp3_url. Use song_id for extend_song, region_edit_song, generate_track, remix_song, and query_task follow-up calls.'));
176
+ }
177
+ );
178
+
179
+ tools.add(
180
+ 'generate_instrumental',
181
+ 'Generate pure instrumental music with no vocals. ' +
182
+ 'Use this when you explicitly want music without singing (background music, cinematic tracks, etc.). After success, include exact song_id/id, local_path/local_paths, audio_url, and status in your normal response.',
183
+ {
184
+ type: 'object',
185
+ properties: {
186
+ prompt: {
187
+ type: 'string',
188
+ description: 'Description of the instrumental style, mood, instrumentation, and feel. ' +
189
+ 'Example: "Cinematic orchestral, epic brass, sweeping strings, building tension, 120 BPM".'
190
+ },
191
+ model: { type: 'string', default: 'auto', description: 'Model to use.' },
192
+ reference_id: {
193
+ type: 'string',
194
+ description: 'Reference audio file ID for style transfer (upload with purpose "reference" or "instrumental").'
195
+ },
196
+ extra: { type: 'object', description: 'Additional parameters.' }
197
+ },
198
+ required: ['prompt']
199
+ },
200
+ async (params) => {
201
+ const merged = mergeExtra(params);
202
+ const result = await mureka.generateInstrumental(merged);
203
+ return json(murekaToolResponse('generate_instrumental', result, { prompt: params.prompt, reference_id: params.reference_id }, 'Assistant: tell the user the exact song_id/id, status, local_path/local_paths, and audio_url/mp3_url for follow-up use.'));
204
+ }
205
+ );
206
+
207
+ tools.add(
208
+ 'generate_soundtrack',
209
+ 'Generate a musical soundtrack that matches the mood or content of an image or video. ' +
210
+ 'Perfect for social media clips, film scenes, or visual content. After success, include exact song_id/id, local_path/local_paths, audio_url, and status in your normal response.',
211
+ {
212
+ type: 'object',
213
+ properties: {
214
+ image: {
215
+ type: 'string',
216
+ description: 'URL or file_id of a reference image. Mutually exclusive with video.'
217
+ },
218
+ video: {
219
+ type: 'string',
220
+ description: 'URL or file_id of a reference video. Mutually exclusive with image.'
221
+ },
222
+ prompt: {
223
+ type: 'string',
224
+ description: 'Optional additional guidance for the soundtrack style or mood.'
225
+ },
226
+ extra: { type: 'object', description: 'Additional parameters.' }
227
+ }
228
+ },
229
+ async (params) => {
230
+ const merged = mergeExtra(params);
231
+ const result = await mureka.generateSoundtrack(merged);
232
+ return json(murekaToolResponse('generate_soundtrack', result, { image: params.image, video: params.video, prompt: params.prompt }, 'Assistant: tell the user the exact song_id/id, status, local_path/local_paths, and audio_url/mp3_url. Preserve the source image/video reference if useful.'));
233
+ }
234
+ );
235
+
236
+ /* ============================================================
237
+ SONG EDITING & ANALYSIS
238
+ ============================================================ */
239
+
240
+ tools.add(
241
+ 'describe_song',
242
+ 'Analyze an existing audio file and return a structured description (genre, mood, structure, timing, instruments, etc.). ' +
243
+ 'Useful before editing or remixing a song. After success, preserve exact structural timings, ids, URLs, and any recommended song_id references in your normal response if needed for follow-up.',
244
+ {
245
+ type: 'object',
246
+ properties: {
247
+ url: {
248
+ type: 'string',
249
+ description: 'Audio URL or base64 of the song you want to analyze. Required.'
250
+ }
251
+ },
252
+ required: ['url']
253
+ },
254
+ async (params) => {
255
+ const result = await mureka.describeSong(params);
256
+ return json(murekaToolResponse('describe_song', result, { source_audio_url: params.url, url: params.url }, 'Assistant: summarize the song description and preserve exact timings, ids, URLs, and recommended song_id references if present.'));
257
+ }
258
+ );
259
+
260
+ tools.add(
261
+ 'extend_song',
262
+ 'Extend an existing song by adding more sections. ' +
263
+ 'Requires the `song_id` returned by a previous generation call. After success, include the source song_id and the new returned song_id/id, local_path/local_paths, audio_url, and status in your normal response.',
264
+ {
265
+ type: 'object',
266
+ properties: {
267
+ song_id: {
268
+ type: 'string',
269
+ description: 'ID of the song you want to extend (from a previous generate_song call). Required.'
270
+ },
271
+ lyrics: {
272
+ type: 'string',
273
+ description: 'Additional lyrics for the new section(s).'
274
+ },
275
+ extra: { type: 'object', description: 'Additional parameters.' }
276
+ },
277
+ required: ['song_id']
278
+ },
279
+ async (params) => {
280
+ const merged = mergeExtra(params);
281
+ const result = await mureka.extendSong(merged);
282
+ return json(murekaToolResponse('extend_song', result, { source_song_id: params.song_id, song_id_input: params.song_id }, 'Assistant: tell the user the source_song_id and the new returned song_id/id exactly, plus status, local_path/local_paths, and audio_url/mp3_url. Use the new song_id for further operations.'));
283
+ }
284
+ );
285
+
286
+ tools.add(
287
+ 'stem_song',
288
+ 'Separate a song into individual stems (vocals, drums, bass, other, etc.).\n\n' +
289
+ 'Provide the audio via `url` (public URL or base64 data URL, max 10MB). Supported formats: mp3, m4a.\n\n' +
290
+ 'Optional `model` controls the separation quality and MIDI export support. After success, include exact stem ids, URLs, local_path/local_paths, and status in your normal response.',
291
+ {
292
+ type: 'object',
293
+ properties: {
294
+ url: {
295
+ type: 'string',
296
+ description: 'Audio URL or base64 data URL of the song to stem (required). Example: "https://...mp3" or "data:audio/mp3;base64,AAA...". Max 10MB for base64.'
297
+ },
298
+ model: {
299
+ type: 'string',
300
+ description: 'Stem separation model. "audio-separation-2" supports MIDI export; "audio-separation-1" does not.'
301
+ },
302
+ extra: { type: 'object', description: 'Additional parameters.' }
303
+ },
304
+ required: ['url']
305
+ },
306
+ async (params) => {
307
+ const merged = mergeExtra(params);
308
+ const result = await mureka.stemSong(merged);
309
+ return json(murekaToolResponse('stem_song', result, { source_audio_url: params.url, model: params.model }, 'Assistant: tell the user exact stem ids/URLs/local paths and status. Preserve local_path/local_paths for follow-up audio operations.'));
310
+ }
311
+ );
312
+
313
+ tools.add(
314
+ 'region_edit_song',
315
+ 'Edit only a specific time region of a song (replace lyrics or melody in a section). ' +
316
+ 'Useful for targeted changes without regenerating the entire track. After success, include the source song_id, edited region, new returned song_id/id, local_path/local_paths, audio_url, and status in your normal response.',
317
+ {
318
+ type: 'object',
319
+ properties: {
320
+ song_id: { type: 'string', description: 'ID of the song. Required.' },
321
+ start_milliseconds: { type: 'number', description: 'Start time of the region in milliseconds. Required.' },
322
+ end_milliseconds: { type: 'number', description: 'End time of the region in milliseconds. Required.' },
323
+ lyrics: { type: 'string', description: 'New lyrics for the edited region.' },
324
+ extra: { type: 'object', description: 'Additional parameters.' }
325
+ },
326
+ required: ['song_id', 'start_milliseconds', 'end_milliseconds']
327
+ },
328
+ async (params) => {
329
+ const merged = mergeExtra(params);
330
+ const result = await mureka.regionEditSong(merged);
331
+ return json(murekaToolResponse('region_edit_song', result, { source_song_id: params.song_id, start_milliseconds: params.start_milliseconds, end_milliseconds: params.end_milliseconds }, 'Assistant: tell the user the source_song_id, edited region, new returned song_id/id, status, local_path/local_paths, and audio_url/mp3_url. Use the new song_id for further operations.'));
332
+ }
333
+ );
334
+
335
+ /* ============================================================
336
+ LYRICS
337
+ ============================================================ */
338
+
339
+ tools.add(
340
+ 'generate_lyrics',
341
+ 'Generate brand new song lyrics from a theme or style prompt. ' +
342
+ 'Use this when you need lyrics but don’t have any yet. After success, include the generated lyrics or durable lyric id fields exactly in your normal response.',
343
+ {
344
+ type: 'object',
345
+ properties: {
346
+ prompt: {
347
+ type: 'string',
348
+ description: 'Theme, style, mood, or specific instructions for the lyrics. ' +
349
+ 'Example: "Write an emotional chorus about overcoming fear in the style of modern pop ballad". Required.'
350
+ },
351
+ extra: { type: 'object', description: 'Additional parameters.' }
352
+ },
353
+ required: ['prompt']
354
+ },
355
+ async (params) => {
356
+ const merged = mergeExtra(params);
357
+ const result = await mureka.generateLyrics(merged);
358
+ return json(murekaToolResponse('generate_lyrics', result, { prompt: params.prompt }, 'Assistant: include the generated lyrics exactly or preserve exact lyric ids/fields if returned.'));
359
+ }
360
+ );
361
+
362
+ tools.add(
363
+ 'extend_lyrics',
364
+ 'Extend or continue existing lyrics with new sections. ' +
365
+ 'Use this when you already have some lyrics and want to build upon them. After success, include the extended lyrics exactly in your normal response.',
366
+ {
367
+ type: 'object',
368
+ properties: {
369
+ lyrics: {
370
+ type: 'string',
371
+ description: 'Existing lyrics that you want to extend. Required.'
372
+ },
373
+ prompt: {
374
+ type: 'string',
375
+ description: 'Instructions for how to extend the lyrics (e.g. "Add a bridge and final chorus"). Required.'
376
+ },
377
+ extra: { type: 'object', description: 'Additional parameters.' }
378
+ },
379
+ required: ['lyrics', 'prompt']
380
+ },
381
+ async (params) => {
382
+ const merged = mergeExtra(params);
383
+ const result = await mureka.extendLyrics(merged);
384
+ return json(murekaToolResponse('extend_lyrics', result, { prompt: params.prompt }, 'Assistant: include the extended lyrics exactly or preserve exact lyric ids/fields if returned.'));
385
+ }
386
+ );
387
+
388
+ /* ============================================================
389
+ FILE UPLOADS (Critical for many workflows)
390
+ ============================================================ */
391
+
392
+ tools.add(
393
+ 'upload_file',
394
+ `Upload an audio or media file so it can be used as a reference in generation calls.
395
+
396
+ This is one of the most important tools. You must upload files before you can use \`reference_id\`, \`vocal_id\`, or \`motif_id\` in generate_song or oth
397
+ er tools.
398
+
399
+ **Supported purposes** (choose the most appropriate one):
400
+ - \`reference\`: Supported format (mp3, m4a). The supported audio duration range is [30,30] seconds, excess will be trimmed.
401
+ - \`vocal\`: Supported format (mp3, m4a). Utilizes vocal extracted from uploaded audio. The supported vocal duration range is [15,30] seconds, excess wil
402
+ l be trimmed.
403
+ - \`melody\`: Supported format (mp3, m4a, mid). Utilizes melody extracted from uploaded audio, uploading a MIDI file is recommended. The supported audio
404
+ duration range is [5,60] seconds, excess will be trimmed.
405
+ - \`instrumental\`: Supported format (mp3, m4a). The supported audio duration range is [30,30] seconds, excess will be trimmed.
406
+ - \`voice\`: Supported format (mp3, m4a). The supported audio duration range is [5,15] seconds, excess will be trimmed.
407
+ - \`audio\`: Supported format (mp3, m4a). A common audio file, used for song extension and similar purposes.
408
+ - \`remix\`: Supported format (mp3, m4a). A common audio file, used for remix purposes.
409
+ - \`soundtrack\`: Supports videos and images. Supported video format (.mp4, .mov, .avi, .mkv, .webm). Supported image format (.jpg, .jpeg, .png, .webp).
410
+ - \`lyrics-video\`: Supported format (.jpg, .jpeg, .png). A common image file, used for lyrics video background images.
411
+
412
+ After uploading, use the returned \`file_id\` in other tools. After success, include the exact file_id/upload_audio_id, original URL, and purpose in your normal response so follow-up calls can reference them.`,
413
+ {
414
+ type: 'object',
415
+ properties: {
416
+ url: {
417
+ type: 'string',
418
+ description: 'Public URL of the file you want to upload. Required.'
419
+ },
420
+ purpose: {
421
+ type: 'string',
422
+ description: 'Purpose of the upload. Must be one of the supported values listed above. Required.'
423
+ },
424
+ extra: { type: 'object', description: 'Additional parameters.' }
425
+ },
426
+ required: ['url', 'purpose']
427
+ },
428
+ async (params) => {
429
+ const merged = mergeExtra(params);
430
+ const result = await mureka.uploadFile(merged);
431
+ return json(murekaToolResponse('upload_file', result, { source_url: params.url, url: params.url, purpose: params.purpose }, 'Assistant: tell the user the exact file_id/upload_audio_id, source URL, and purpose. Use file_id/upload_audio_id for reference_id, vocal_id, motif_id, upload_audio_id, or other follow-up parameters as appropriate.'));
432
+ }
433
+ );
434
+
435
+ /* ============================================================
436
+ TRACK GENERATION (supports upload_audio_id from purpose=audio uploads)
437
+ ============================================================ */
438
+
439
+ tools.add(
440
+ 'generate_track',
441
+ 'Generate a specific track type (Vocals, Instrumental, Drums, Bass, etc.) from a song.\n\n' +
442
+ 'Supports either a previously generated `song_id` or an `upload_audio_id` (from upload_file with purpose="audio").\n\n' +
443
+ '**Required**: `type` (or `generate_type`) and `prompt`.\n' +
444
+ '`song_id` and `upload_audio_id` are mutually exclusive. After success, include exact source id, generated track id, local_path/local_paths, audio_url, and status in your normal response.',
445
+ {
446
+ type: 'object',
447
+ properties: {
448
+ song_id: {
449
+ type: 'string',
450
+ description: 'Song ID from a previous generate_song call (mutually exclusive with upload_audio_id). Only songs from the last 30 days are supported.'
451
+ },
452
+ upload_audio_id: {
453
+ type: 'string',
454
+ description: 'Upload ID returned by upload_file with purpose="audio" (mutually exclusive with song_id). Use this for generating tracks from your own uploaded audio.'
455
+ },
456
+ generate_type: {
457
+ type: 'string',
458
+ description: 'Type of track to generate (required). Valid values: Vocals, Instrumental, Drums, Bass, Guitar, Keyboard, Percussion, Strings, Synth, FX, Brass, Woodwinds. (Also accepts generate_type for backward compatibility)'
459
+ },
460
+ prompt: {
461
+ type: 'string',
462
+ description: 'Control prompt for track generation (required, max 1024 characters).'
463
+ },
464
+ generate_start: {
465
+ type: 'integer',
466
+ description: 'Start time of the input segment in milliseconds (optional).'
467
+ },
468
+ generate_end: {
469
+ type: 'integer',
470
+ description: 'End time of the input segment in milliseconds (optional).'
471
+ },
472
+ lyrics: {
473
+ type: 'string',
474
+ description: 'Lyrics for generated vocals (optional, max 3000 characters). Only relevant when type=Vocals.'
475
+ },
476
+ vocal_gender: {
477
+ type: 'string',
478
+ description: 'Gender of generated vocals ("male" or "female"). Only applicable when type=Vocals.'
479
+ },
480
+ extra: {
481
+ type: 'object',
482
+ description: 'Additional advanced parameters.'
483
+ }
484
+ },
485
+ required: ['generate_type', 'prompt']
486
+ },
487
+ async (params) => {
488
+ const merged = mergeExtra(params);
489
+ const result = await mureka.generateTrack(merged);
490
+ return json(murekaToolResponse('generate_track', result, { source_song_id: params.song_id, upload_audio_id_input: params.upload_audio_id, generate_type: params.generate_type, prompt: params.prompt }, 'Assistant: tell the user the source id, generated track song_id/id, status, local_path/local_paths, and audio_url/mp3_url exactly.'));
491
+ }
492
+ );
493
+
494
+ /* ============================================================
495
+ REMIX (supports upload_audio_id from purpose=remix uploads)
496
+ ============================================================ */
497
+
498
+ tools.add(
499
+ 'remix_song',
500
+ 'Create a remix of an existing song using either a previously generated song_id or an upload_audio_id (from upload_file with purpose="remix").\n\n' +
501
+ 'This is the official remix tool. Provide a strong `prompt` describing the desired style/arrangement changes and the full `lyrics` of the target song.\n\n' +
502
+ '**Important**: `song_id` and `upload_audio_id` are mutually exclusive. Use `upload_audio_id` when you have uploaded a song with purpose "remix". After success, include exact source id, remix song_id/id, local_path/local_paths, audio_url, and status in your normal response.',
503
+ {
504
+ type: 'object',
505
+ properties: {
506
+ song_id: {
507
+ type: 'string',
508
+ description: 'Song ID from a previous generate_song call (mutually exclusive with upload_audio_id). Only songs from the last 30 days are supported.'
509
+ },
510
+ upload_audio_id: {
511
+ type: 'string',
512
+ description: 'Upload ID returned by upload_file with purpose="remix" (mutually exclusive with song_id). Use this for remixing your own uploaded tracks.'
513
+ },
514
+ prompt: {
515
+ type: 'string',
516
+ description: 'Control prompt for the remix (required, max 1024 characters). Example: "Create a fresh, energetic 80s synth-pop remix...".'
517
+ },
518
+ lyrics: {
519
+ type: 'string',
520
+ description: 'Full lyrics for the remixed song (required, max 3000 characters). Must match the structure of the original.'
521
+ },
522
+ n: {
523
+ type: 'integer',
524
+ default: 2,
525
+ description: 'Number of remix variants to generate (1-3). You are charged per variant.'
526
+ },
527
+ model: {
528
+ type: 'string',
529
+ default: 'auto',
530
+ description: 'Model to use. Default "auto".'
531
+ },
532
+ extra: {
533
+ type: 'object',
534
+ description: 'Additional advanced parameters.'
535
+ }
536
+ },
537
+ required: ['prompt', 'lyrics']
538
+ },
539
+ async (params) => {
540
+ const merged = mergeExtra(params);
541
+ const result = await mureka.remixSong(merged);
542
+ return json(murekaToolResponse('remix_song', result, { source_song_id: params.song_id, upload_audio_id_input: params.upload_audio_id, prompt: params.prompt }, 'Assistant: tell the user the source id and new remix song_id/id exactly, plus status, local_path/local_paths, and audio_url/mp3_url. Use the new song_id for further operations.'));
543
+ }
544
+ );
545
+
546
+ /* ============================================================
547
+ VOICE & TTS
548
+ ============================================================ */
549
+
550
+ tools.add(
551
+ 'clone_voice',
552
+ 'Create a custom voice clone from a short vocal sample. ' +
553
+ 'The resulting `voice_id` can be used in generate_song (as vocal_id) or generate_speech. After success, include the exact voice_id/vocal_id in your normal response.',
554
+ {
555
+ type: 'object',
556
+ properties: {
557
+ file: {
558
+ type: 'string',
559
+ description: 'URL or base64 of the vocal sample. Best results with 5–15 seconds of clear singing or speech. Required.'
560
+ },
561
+ name: {
562
+ type: 'string',
563
+ description: 'Optional friendly name for the cloned voice.'
564
+ },
565
+ extra: { type: 'object', description: 'Additional parameters.' }
566
+ },
567
+ required: ['file']
568
+ },
569
+ async (params) => {
570
+ const merged = mergeExtra(params);
571
+ const result = await mureka.cloneVocal(merged);
572
+ return json(murekaToolResponse('clone_voice', result, { source_file: params.file, name: params.name }, 'Assistant: tell the user the exact voice_id/vocal_id. Use it as vocal_id in generate_song or voice_id in generate_speech.'));
573
+ }
574
+ );
575
+
576
+ tools.add(
577
+ 'generate_speech',
578
+ 'Convert text into natural-sounding speech. Supports both single-speaker TTS and multi-speaker podcasts. After success, include exact speech id, local_path/local_paths, audio_url, and status in your normal response.',
579
+ {
580
+ type: 'object',
581
+ properties: {
582
+ text: {
583
+ type: 'string',
584
+ description: 'Text to convert to speech (for single-speaker mode). Mutually exclusive with script.'
585
+ },
586
+ script: {
587
+ type: 'array',
588
+ description: 'Array of objects for podcast mode: [{ speaker: "Host", text: "..." }]. Mutually exclusive with text.'
589
+ },
590
+ voice_id: {
591
+ type: 'string',
592
+ description: 'Voice ID to use (from clone_voice or default voices). Required for single-speaker.'
593
+ },
594
+ voices: {
595
+ type: 'object',
596
+ description: 'Map of speaker names to voice_ids for podcast mode. Example: { "Host": "voice_123" }'
597
+ },
598
+ speed: { type: 'number', default: 1.0, description: 'Speech speed multiplier (0.5 – 2.0).' },
599
+ pitch: { type: 'number', default: 0, description: 'Pitch shift in semitones.' },
600
+ extra: { type: 'object', description: 'Additional parameters.' }
601
+ }
602
+ },
603
+ async (params) => {
604
+ const merged = mergeExtra(params);
605
+ const result = await mureka.generateTTS(merged);
606
+ return json(murekaToolResponse('generate_speech', result, { voice_id_input: params.voice_id, voices: params.voices }, 'Assistant: tell the user the exact speech id, status, local_path/local_paths, and audio_url/mp3_url. Preserve voice_id references used.'));
607
+ }
608
+ );
609
+
610
+ /* ============================================================
611
+ ACCOUNT & TASKS
612
+ ============================================================ */
613
+
614
+ tools.add(
615
+ 'get_billing',
616
+ 'Retrieve current account billing information (balance, credits, usage). ' +
617
+ 'Useful before starting large generation jobs.',
618
+ {
619
+ type: 'object',
620
+ properties: {}
621
+ },
622
+ async () => {
623
+ const result = await mureka.getBilling();
624
+ return json(murekaToolResponse('get_billing', result, {}, 'Assistant: report exact remaining balance/credits and any relevant limits from the billing result.'));
625
+ }
626
+ );
627
+
628
+ tools.add(
629
+ 'query_task',
630
+ 'Manually check the status of an async task. ' +
631
+ 'Most tools now auto-wait, so this is mainly useful for manual control or debugging. After success, include exact task_id, status, local_path/local_paths, audio_url, and any final song_id/id in your normal response.',
632
+ {
633
+ type: 'object',
634
+ properties: {
635
+ task_id: { type: 'string', description: 'Task ID to query. Required.' },
636
+ type: { type: 'string', default: 'song', description: 'Task type (song, instrumental, tts, etc.).' }
637
+ },
638
+ required: ['task_id']
639
+ },
640
+ async (params) => {
641
+ const result = await mureka.queryTask(params.task_id, params.type || 'song');
642
+ return json(murekaToolResponse('query_task', result, { task_id_input: params.task_id, task_type: params.type || 'song' }, 'Assistant: tell the user the exact task_id, status, and any final song_id/id, local_path/local_paths, or audio_url/mp3_url returned.'));
643
+ }
644
+ );
645
+
646
+ export default tools;
@@ -0,0 +1,41 @@
1
+ # Mureka Music API Wrapper
2
+
3
+ **`lib/API/mureka/music.js`** — A thin, production-ready JavaScript wrapper for the official Mureka AI Music API.
4
+
5
+ ## Important Notice
6
+
7
+ **All local documentation has been removed.**
8
+
9
+ This project now **only references the official online documentation**.
10
+
11
+ **Official Documentation**: https://platform.mureka.ai/docs/
12
+
13
+ Please refer to the official site for:
14
+
15
+ - Complete API reference
16
+ - All endpoint parameters and return values
17
+ - Authentication, rate limits, and best practices
18
+ - Supported models and features
19
+
20
+ ---
21
+
22
+ ## Quick Start
23
+
24
+ ```js
25
+ import * as mureka from './lib/API/mureka/music.js';
26
+
27
+ process.env.MUREKA_API_KEY = 'your_key_here';
28
+
29
+ const result = await mureka.generateSong({
30
+ prompt: "Upbeat indie pop, energetic, summer road trip vibe"
31
+ });
32
+
33
+ console.log(result);
34
+ ```
35
+
36
+ For full usage examples and parameter details, see the official documentation linked above.
37
+
38
+ ---
39
+
40
+ **Source**: `lib/API/mureka/music.js`
41
+ **ToolSet**: `lib/API/mureka/MusicToolset.js` (for AI agents)