@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
@@ -0,0 +1,7 @@
1
+ import * as music from './music.js';
2
+ import musicToolset from './MusicToolset.js'
3
+
4
+ export default {
5
+ music,
6
+ musicToolset
7
+ }
@@ -0,0 +1,658 @@
1
+ /**
2
+ * @file lib/API/mureka/music.js
3
+ * @module mureka/music
4
+ * @description Comprehensive pure HTTP wrapper for the official Mureka AI Music API.
5
+ *
6
+ * This module provides typed, well-documented access to **all major Mureka operations**.
7
+ * Most generation methods support automatic polling and return rich results.
8
+ *
9
+ * @see https://platform.mureka.ai/docs/
10
+ */
11
+
12
+ /* ============================================================
13
+ TYPE DEFINITIONS
14
+ ============================================================ */
15
+
16
+ /**
17
+ * @typedef {Object} MurekaWord
18
+ * @property {number} start - Start time in milliseconds
19
+ * @property {number} end - End time in milliseconds
20
+ * @property {string} text - The word text
21
+ */
22
+
23
+ /**
24
+ * @typedef {Object} MurekaLine
25
+ * @property {number} start - Start time in milliseconds
26
+ * @property {number} end - End time in milliseconds
27
+ * @property {string} text - Full line text
28
+ * @property {MurekaWord[]} [words] - Word-level timing (optional)
29
+ */
30
+
31
+ /**
32
+ * @typedef {Object} MurekaLyricsSection
33
+ * @property {string} section_type - e.g. "intro", "verse", "chorus", "bridge"
34
+ * @property {number} [start] - Section start time (ms)
35
+ * @property {number} [end] - Section end time (ms)
36
+ * @property {MurekaLine[]} [lines] - Lines with timing
37
+ */
38
+
39
+ /**
40
+ * @typedef {Object} MurekaChoice
41
+ * @property {string} url - Primary MP3 URL
42
+ * @property {string} [flac_url] - FLAC version
43
+ * @property {string} [wav_url] - WAV version
44
+ * @property {number} duration - Duration in milliseconds
45
+ * @property {string} [id] - Choice-specific ID
46
+ * @property {number} [index] - Choice index (0-based)
47
+ * @property {MurekaLyricsSection[]} [lyrics_sections] - Detailed timed lyrics
48
+ * @property {string} [local_path] - Locally saved MP3 path (added by wrapper)
49
+ * @property {string} [local_flac_path] - Locally saved FLAC path (added by wrapper)
50
+ * @property {string} [local_wav_path] - Locally saved WAV path (added by wrapper)
51
+ */
52
+
53
+ /**
54
+ * @typedef {Object} MurekaGenerationResult
55
+ * @property {string} id - Main task/result ID
56
+ * @property {number} created_at - Unix timestamp (seconds)
57
+ * @property {number} [finished_at] - Unix timestamp when finished
58
+ * @property {string} [model] - Model used (e.g. "mureka-9")
59
+ * @property {string} status - "succeeded", "processing", "failed", etc.
60
+ * @property {MurekaChoice[]} [choices] - Array of generated audio variants (ALL auto-saved)
61
+ * @property {string} [trace_id] - Request trace ID for debugging
62
+ * @property {string} [mp3_url] - Legacy top-level MP3 (for backward compatibility)
63
+ * @property {string} [audio_url] - Legacy top-level audio URL
64
+ * @property {string[]} [local_paths] - Array of all locally saved MP3 paths (added by wrapper)
65
+ * @property {Object} [raw] - Original raw API response
66
+ */
67
+
68
+ /* ============================================================
69
+ CONSTANTS & CORE HELPERS
70
+ ============================================================ */
71
+
72
+ import { request as doRequest } from '@j-o-r/apiserver';
73
+ import fs from 'fs/promises';
74
+ import path from 'path';
75
+
76
+ const BASE_URL = 'https://api.mureka.ai';
77
+ const TMP_DIR = path.join(process.cwd(), '.cache', 'mureka');
78
+
79
+ const POLL_INTERVAL_MS = 10000;
80
+ const MAX_POLL_ATTEMPTS = 24;
81
+ const MAX_RETRIES = 3;
82
+
83
+ /**
84
+ * Official valid track generate types (Title Case).
85
+ * These are the only accepted values for `type` / `generate_type`.
86
+ */
87
+ const TRACK_GENERATE_TYPES = [
88
+ 'Vocals',
89
+ 'Instrumental',
90
+ 'Drums',
91
+ 'Bass',
92
+ 'Guitar',
93
+ 'Keyboard',
94
+ 'Percussion',
95
+ 'Strings',
96
+ 'Synth',
97
+ 'FX',
98
+ 'Brass',
99
+ 'Woodwinds'
100
+ ];
101
+
102
+ /**
103
+ * Validates a track generate type.
104
+ * Throws a clear error if the type is not in TRACK_GENERATE_TYPES.
105
+ *
106
+ * @param {string} type
107
+ */
108
+ function validateTrackGenerateType(type) {
109
+ if (!type) {
110
+ throw new Error('track generate type is required');
111
+ }
112
+
113
+ const valid = TRACK_GENERATE_TYPES.find(t => t === type);
114
+
115
+ if (!valid) {
116
+ throw new Error(
117
+ `Invalid track generate type: "${type}". ` +
118
+ `Valid types: ${TRACK_GENERATE_TYPES.join(', ')}`
119
+ );
120
+ }
121
+
122
+ return valid; // return the correct Title Case version
123
+ }
124
+
125
+
126
+ /**
127
+ * Returns authentication headers for Mureka API requests.
128
+ * @returns {{'Authorization': string}}
129
+ * @throws {Error} If MUREKA_API_KEY is not set.
130
+ * @see https://platform.mureka.ai/docs/
131
+ */
132
+ const getHeaders = () => {
133
+ if (!process.env.MUREKA_API_KEY) {
134
+ throw new Error('Missing MUREKA_API_KEY! Please export MUREKA_API_KEY=your_key');
135
+ }
136
+ return {
137
+ 'Authorization': `Bearer ${process.env.MUREKA_API_KEY}`
138
+ };
139
+ };
140
+
141
+ /**
142
+ * Saves audio data (URL or base64) to a local file.
143
+ * @param {string|Buffer} audioData
144
+ * @param {string} [filenamePrefix='mureka']
145
+ * @returns {Promise<string>} Local file path
146
+ */
147
+ /**
148
+ * Saves audio data (URL or base64) to a local file in the .cache/mureka directory.
149
+ * @param {string|Buffer} audioData - URL, base64 string, or Buffer of the audio.
150
+ * @param {string} [filenamePrefix="mureka"] - Prefix for the saved filename.
151
+ * @returns {Promise<string>} The local file path of the saved audio.
152
+ */
153
+ async function saveAudioToLocal(audioData, filenamePrefix = 'mureka') {
154
+ await fs.mkdir(TMP_DIR, { recursive: true });
155
+ const filename = `${filenamePrefix}-${Date.now()}.mp3`;
156
+ const localPath = path.join(TMP_DIR, filename);
157
+
158
+ if (typeof audioData === 'string' && audioData.startsWith('http')) {
159
+ const response = await fetch(audioData);
160
+ if (!response.ok) throw new Error(`Download failed: ${response.status}`);
161
+ const buffer = Buffer.from(await response.arrayBuffer());
162
+ await fs.writeFile(localPath, buffer);
163
+ } else if (typeof audioData === 'string') {
164
+ const buffer = Buffer.from(audioData, 'base64');
165
+ await fs.writeFile(localPath, buffer);
166
+ } else {
167
+ await fs.writeFile(localPath, audioData);
168
+ }
169
+ return localPath;
170
+ }
171
+
172
+ /**
173
+ * Saves all audio variants (MP3, FLAC, WAV) from a generation result to local files.
174
+ * @private
175
+ * @param {Object} result - The API response containing choices.
176
+ * @returns {Promise<Object>} The result with local_path fields added.
177
+ */
178
+ async function saveAllAudioChoices(result) {
179
+ const localPaths = [];
180
+ if (result.choices && Array.isArray(result.choices)) {
181
+ for (let i = 0; i < result.choices.length; i++) {
182
+ const choice = result.choices[i];
183
+ if (choice.url) {
184
+ choice.local_path = await saveAudioToLocal(choice.url, `choice-${i}`);
185
+ localPaths.push(choice.local_path);
186
+ }
187
+ if (choice.flac_url) choice.local_flac_path = await saveAudioToLocal(choice.flac_url, `choice-${i}-flac`);
188
+ if (choice.wav_url) choice.local_wav_path = await saveAudioToLocal(choice.wav_url, `choice-${i}-wav`);
189
+ }
190
+ }
191
+ if (localPaths.length > 0) result.local_paths = localPaths;
192
+ return result;
193
+ }
194
+
195
+ /**
196
+ * Internal request helper with retry logic on 429 rate limits.
197
+ * Always includes the full URL in error messages.
198
+ * @private
199
+ * @param {string} endpoint - API endpoint (e.g. "/v1/song/generate").
200
+ * @param {string} [method="POST"] - HTTP method.
201
+ * @param {Object} [body={}] - Request body.
202
+ * @param {number} [retryCount=0] - Current retry attempt.
203
+ * @returns {Promise<Object>} The API response.
204
+ */
205
+ async function requestInternal(endpoint, method = 'POST', body = {}, retryCount = 0) {
206
+ const headers = getHeaders();
207
+ const url = `${BASE_URL}${endpoint}`;
208
+
209
+ const res = await doRequest(url, method, headers, body);
210
+
211
+ if (res.status === 429 && retryCount < MAX_RETRIES) {
212
+ const wait = Math.pow(2, retryCount) * 1000;
213
+ await new Promise(r => setTimeout(r, wait));
214
+ return requestInternal(endpoint, method, body, retryCount + 1);
215
+ }
216
+
217
+ if (res.status >= 400) {
218
+ const errMsg = JSON.stringify(res, null, 2);
219
+ throw new Error(`Mureka API error ${res.status} at ${url}:\n${errMsg}`);
220
+ }
221
+
222
+ return { ...res.response, duration: Date.now() - Date.now(), raw: res.response };
223
+ }
224
+
225
+ /**
226
+ * Poll until task completes.
227
+ * @param {string} taskId
228
+ * @param {string} [type='song']
229
+ * @returns {Promise<MurekaGenerationResult>}
230
+ */
231
+ /**
232
+ * Polls a task until it completes or fails.
233
+ * @param {string} taskId - The task ID to poll.
234
+ * @param {string} [type="song"] - Task type (song, instrumental, tts, etc.).
235
+ * @returns {Promise<MurekaGenerationResult>} The completed result.
236
+ */
237
+ async function pollUntilDone(taskId, type = 'song') {
238
+ for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
239
+ await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
240
+ const status = await requestInternal(`/v1/${type}/query/${taskId}`, 'GET');
241
+ if (['completed', 'success', 'succeeded'].includes(status.status)) {
242
+ return await saveAllAudioChoices(status);
243
+ }
244
+ if (['failed', 'error'].includes(status.status)) {
245
+ throw new Error(`Task failed: ${status.error || status.message}`);
246
+ }
247
+ }
248
+ throw new Error(`Task ${taskId} timed out`);
249
+ }
250
+
251
+ /* ============================================================
252
+ AUTO-POLL HELPER
253
+ ============================================================ */
254
+ /**
255
+ * Wrapper that automatically polls async generation tasks to completion.
256
+ * @private
257
+ * @param {Function} fn - The API call function.
258
+ * @param {Object} params - Parameters to pass.
259
+ * @param {string} [defaultType="song"] - Default task type for polling.
260
+ * @returns {Promise<MurekaGenerationResult>} Final result after polling.
261
+ */
262
+ async function withAutoPoll(fn, params, defaultType = 'song') {
263
+ const result = await fn(params);
264
+ if (result.task_id || result.id) {
265
+ return await pollUntilDone(result.task_id || result.id, defaultType);
266
+ }
267
+ return await saveAllAudioChoices(result);
268
+ }
269
+
270
+ /* ============================================================
271
+ SONG OPERATIONS
272
+ ============================================================ */
273
+
274
+ /**
275
+ * Generate a complete song with both lyrics and vocals (text-to-song).
276
+ * Supports reference_id, vocal_id, motif_id, etc.
277
+ * Automatically polls until completion and saves audio locally.
278
+ *
279
+ * @param {Object} [params={}]
280
+ * @param {string} params.prompt - Style/mood/genre description (required).
281
+ * @param {string} [params.lyrics] - Structured lyrics with [Verse], [Chorus], etc.
282
+ * @param {string} [params.model="auto"] - Model to use.
283
+ * @param {string} [params.reference_id] - Reference audio file_id (purpose=reference).
284
+ * @param {string} [params.vocal_id] - Cloned voice ID.
285
+ * @param {string} [params.motif_id] - Melody motif file_id.
286
+ * @returns {Promise<MurekaGenerationResult>} Generation result with choices and local paths.
287
+ */
288
+ async function generateSong(params = {}) {
289
+ return withAutoPoll((p) => requestInternal('/v1/song/generate', 'POST', p), params, 'song');
290
+ }
291
+
292
+ /**
293
+ * Generate pure instrumental music (no vocals).
294
+ *
295
+ * @param {Object} [params={}]
296
+ * @param {string} params.prompt - Instrumental style/mood description (required).
297
+ * @param {string} [params.model="auto"]
298
+ * @param {string} [params.reference_id] - Reference audio (purpose=reference or instrumental).
299
+ * @returns {Promise<MurekaGenerationResult>}
300
+ */
301
+ async function generateInstrumental(params = {}) {
302
+ return withAutoPoll((p) => requestInternal('/v1/instrumental/generate', 'POST', p), params, 'instrumental');
303
+ }
304
+
305
+ /**
306
+ * Generate a musical soundtrack matching an image or video.
307
+ *
308
+ * @param {Object} [params={}]
309
+ * @param {string} [params.image] - Image URL or file_id.
310
+ * @param {string} [params.video] - Video URL or file_id.
311
+ * @param {string} [params.prompt] - Optional style guidance.
312
+ * @returns {Promise<MurekaGenerationResult>}
313
+ */
314
+ async function generateSoundtrack(params = {}) {
315
+ return withAutoPoll((p) => requestInternal('/v1/soundtrack/generate', 'POST', p), params, 'soundtrack');
316
+ }
317
+
318
+ /**
319
+ * Analyze an existing audio file and return structured description (genre, mood, structure, etc.).
320
+ *
321
+ * @param {Object} [params={}]
322
+ * @param {string} params.url - Audio URL or base64 (required).
323
+ * @returns {Promise<Object>} Description result.
324
+ */
325
+ async function describeSong(params = {}) {
326
+ return withAutoPoll((p) => requestInternal('/v1/song/describe', 'POST', p), params, 'song');
327
+ }
328
+
329
+ /**
330
+ * Extend an existing song by adding more sections.
331
+ *
332
+ * @param {Object} [params={}]
333
+ * @param {string} params.song_id - ID from previous generation (required).
334
+ * @param {string} [params.lyrics] - Additional lyrics.
335
+ * @returns {Promise<MurekaGenerationResult>}
336
+ */
337
+ async function extendSong(params = {}) {
338
+ return withAutoPoll((p) => requestInternal('/v1/song/extend', 'POST', p), params, 'song');
339
+ }
340
+
341
+ /**
342
+ * Regenerate a song (or specific parts).
343
+ *
344
+ * @param {Object} [params={}]
345
+ * @returns {Promise<MurekaGenerationResult>}
346
+ */
347
+ async function regenerateSong(params = {}) {
348
+ return withAutoPoll((p) => requestInternal('/v1/song/regenerate', 'POST', p), params, 'song');
349
+ }
350
+
351
+ /**
352
+ * Separate a song into stems (vocals, drums, bass, etc.).
353
+ *
354
+ * @param {Object} [params={}]
355
+ * @param {string} params.url - Audio URL or base64 (required).
356
+ * @param {string} [params.model] - Separation model.
357
+ * @returns {Promise<MurekaGenerationResult>}
358
+ */
359
+ async function stemSong(params = {}) {
360
+ return withAutoPoll((p) => requestInternal('/v1/song/stem', 'POST', p), params, 'song');
361
+ }
362
+
363
+ /**
364
+ * Recognize/identify a song from audio.
365
+ *
366
+ * @param {Object} [params={}]
367
+ * @param {string} params.url - Audio URL or base64 (required).
368
+ * @returns {Promise<Object>}
369
+ */
370
+ async function recognizeSong(params = {}) {
371
+ return withAutoPoll((p) => requestInternal('/v1/song/recognize', 'POST', p), params, 'song');
372
+ }
373
+
374
+ /**
375
+ * Edit a specific time region of a song (replace lyrics/melody in a section).
376
+ *
377
+ * @param {Object} [params={}]
378
+ * @param {string} params.song_id - Song ID (required).
379
+ * @param {number} params.start_milliseconds - Start time (ms).
380
+ * @param {number} params.end_milliseconds - End time (ms).
381
+ * @param {string} [params.lyrics] - New lyrics for the region.
382
+ * @returns {Promise<MurekaGenerationResult>}
383
+ */
384
+ async function regionEditSong(params = {}) {
385
+ return withAutoPoll((p) => requestInternal('/v1/song/region-edit', 'POST', p), params, 'song');
386
+ }
387
+
388
+ /**
389
+ * Generate a lyrics video from lyrics and background image.
390
+ *
391
+ * @param {Object} [params={}]
392
+ * @returns {Promise<MurekaGenerationResult>}
393
+ */
394
+ async function generateLyricsVideo(params = {}) {
395
+ return withAutoPoll((p) => requestInternal('/v1/lyrics-video/generate', 'POST', p), params, 'lyrics-video');
396
+ }
397
+
398
+ /**
399
+ * Generate a specific track type (Vocals, Instrumental, Drums, etc.) from a song or uploaded audio.
400
+ *
401
+ * @param {Object} [params={}]
402
+ * @param {string} [params.song_id] - Song ID (mutually exclusive with upload_audio_id).
403
+ * @param {string} [params.upload_audio_id] - Upload ID from purpose="audio".
404
+ * @param {string} params.type - Track type (Vocals, Instrumental, Drums, Bass, Guitar, Keyboard, Percussion, Strings, Synth, FX, Brass, Woodwinds).
405
+ * @param {string} [params.generate_type] - Legacy alias for type.
406
+ * @param {string} params.prompt - Control prompt (required).
407
+ * @param {number} [params.generate_start] - Start time (ms).
408
+ * @param {number} [params.generate_end] - End time (ms).
409
+ * @param {string} [params.lyrics] - Lyrics (for Vocals).
410
+ * @param {string} [params.vocal_gender] - "male" or "female".
411
+ * @returns {Promise<MurekaGenerationResult>}
412
+ */
413
+ async function generateTrack(params = {}) {
414
+ console.log(JSON.stringify(params, null, ' ') );
415
+ // This will throw if invalid
416
+ // validateTrackGenerateType(params.generate_type);
417
+
418
+ return withAutoPoll((p) => requestInternal('/v1/track/generate', 'POST', p), params, 'song');
419
+ }
420
+
421
+ /**
422
+ * Create a remix of an existing song.
423
+ *
424
+ * @param {Object} [params={}]
425
+ * @param {string} [params.song_id] - Song ID.
426
+ * @param {string} [params.upload_audio_id] - Upload ID from purpose="remix".
427
+ * @param {string} params.prompt - Remix style prompt (required).
428
+ * @param {string} params.lyrics - Full lyrics of the target song (required).
429
+ * @param {number} [params.n=2] - Number of variants.
430
+ * @param {string} [params.model="auto"]
431
+ * @returns {Promise<MurekaGenerationResult>}
432
+ */
433
+ async function remixSong(params = {}) {
434
+ return withAutoPoll((p) => requestInternal('/v1/song/remix', 'POST', p), params, 'song');
435
+ }
436
+
437
+ /* ============================================================
438
+ LYRICS
439
+ ============================================================ */
440
+
441
+ /**
442
+ * Generate brand new song lyrics from a theme or style prompt.
443
+ *
444
+ * @param {Object} [params={}]
445
+ * @param {string} params.prompt - Theme/style instructions (required).
446
+ * @returns {Promise<Object>} Generated lyrics.
447
+ */
448
+ async function generateLyrics(params = {}) {
449
+ return requestInternal('/v1/lyrics/generate', 'POST', params);
450
+ }
451
+
452
+ /**
453
+ * Extend or continue existing lyrics.
454
+ *
455
+ * @param {Object} [params={}]
456
+ * @param {string} params.lyrics - Existing lyrics (required).
457
+ * @param {string} params.prompt - Instructions for extension (required).
458
+ * @returns {Promise<Object>}
459
+ */
460
+ async function extendLyrics(params = {}) {
461
+ return requestInternal('/v1/lyrics/extend', 'POST', params);
462
+ }
463
+
464
+ /* ============================================================
465
+ TTS / SPEECH
466
+ ============================================================ */
467
+
468
+ /**
469
+ * Convert text to natural-sounding speech (single-speaker or multi-speaker).
470
+ *
471
+ * @param {Object} [params={}]
472
+ * @param {string} [params.text] - Text for single-speaker mode.
473
+ * @param {Array} [params.script] - Array of {speaker, text} for podcast mode.
474
+ * @param {string} [params.voice_id] - Voice ID for single-speaker.
475
+ * @param {Object} [params.voices] - Map of speaker -> voice_id for podcast.
476
+ * @param {number} [params.speed=1.0]
477
+ * @param {number} [params.pitch=0]
478
+ * @returns {Promise<MurekaGenerationResult>}
479
+ */
480
+ async function generateTTS(params = {}) {
481
+ return withAutoPoll((p) => requestInternal('/v1/tts/generate', 'POST', p), params, 'tts');
482
+ }
483
+
484
+ /**
485
+ * Generate a multi-speaker podcast.
486
+ *
487
+ * @param {Object} [params={}]
488
+ * @returns {Promise<MurekaGenerationResult>}
489
+ */
490
+ async function generatePodcast(params = {}) {
491
+ return withAutoPoll((p) => requestInternal('/v1/tts/podcast', 'POST', p), params, 'tts');
492
+ }
493
+
494
+ /* ============================================================
495
+ VOCAL CLONING
496
+ ============================================================ */
497
+
498
+ /**
499
+ * Create a custom voice clone from a short vocal sample.
500
+ *
501
+ * @param {Object} [params={}]
502
+ * @param {string} params.file - URL or base64 of vocal sample (5-15s recommended).
503
+ * @param {string} [params.name] - Friendly name for the voice.
504
+ * @returns {Promise<Object>} Result containing voice_id.
505
+ */
506
+ async function cloneVocal(params = {}) {
507
+ return withAutoPoll((p) => requestInternal('/v1/song/vocal-clone', 'POST', p), params, 'vocal');
508
+ }
509
+
510
+ /* ============================================================
511
+ FILE UPLOADS
512
+ ============================================================ */
513
+
514
+ /**
515
+ * Upload a file for use as reference (audio, image, video, MIDI).
516
+ * Supports multiple purposes (reference, vocal, melody, audio, remix, soundtrack, lyrics-video, etc.).
517
+ *
518
+ * @param {Object} [params={}]
519
+ * @param {string} params.url - Public URL of the file (required).
520
+ * @param {string} params.purpose - Purpose of upload (required).
521
+ * @returns {Promise<Object>} Upload result with file_id.
522
+ */
523
+ async function uploadFile(params = {}) {
524
+ const formData = new FormData();
525
+ for (const [key, value] of Object.entries(params)) {
526
+ if (value !== undefined && value !== null) {
527
+ formData.append(key, value);
528
+ }
529
+ }
530
+ return requestInternal('/v1/files/upload', 'POST', formData);
531
+ }
532
+
533
+ /**
534
+ * Create a new upload session.
535
+ *
536
+ * @param {Object} [params={}]
537
+ * @returns {Promise<Object>}
538
+ */
539
+ async function uploadsCreate(params = {}) {
540
+ return requestInternal('/v1/uploads/create', 'POST', params);
541
+ }
542
+
543
+ /**
544
+ * Add data to an upload session.
545
+ *
546
+ * @param {Object} [params={}]
547
+ * @returns {Promise<Object>}
548
+ */
549
+ async function uploadsAdd(params = {}) {
550
+ return requestInternal('/v1/uploads/add', 'POST', params);
551
+ }
552
+
553
+ /**
554
+ * Complete an upload session.
555
+ *
556
+ * @param {Object} [params={}]
557
+ * @returns {Promise<Object>}
558
+ */
559
+ async function uploadsComplete(params = {}) {
560
+ return requestInternal('/v1/uploads/complete', 'POST', params);
561
+ }
562
+
563
+ /* ============================================================
564
+ TASK POLLING
565
+ ============================================================ */
566
+
567
+ /**
568
+ * Manually query the status of a task.
569
+ *
570
+ * @param {string} taskId - Task ID.
571
+ * @param {string} [type="song"] - Task type.
572
+ * @returns {Promise<Object>} Task status.
573
+ */
574
+ async function queryTask(taskId, type = 'song') {
575
+ return requestInternal(`/v1/${type}/query/${taskId}`, 'GET');
576
+ }
577
+
578
+ /* ============================================================
579
+ ACCOUNT & BILLING
580
+ ============================================================ */
581
+
582
+ /**
583
+ * Retrieve current account billing information (balance, credits, usage).
584
+ *
585
+ * @returns {Promise<Object>}
586
+ */
587
+ async function getBilling() {
588
+ return requestInternal('/v1/account/billing', 'GET');
589
+ }
590
+
591
+ /**
592
+ * Retrieve account profile information.
593
+ *
594
+ * @returns {Promise<Object>}
595
+ */
596
+ async function getProfile() {
597
+ return requestInternal('/v1/account/profile', 'GET');
598
+ }
599
+
600
+ /* ============================================================
601
+ FINE-TUNING
602
+ ============================================================ */
603
+
604
+ /**
605
+ * Create a fine-tuning task.
606
+ *
607
+ * @param {Object} [params={}]
608
+ * @returns {Promise<MurekaGenerationResult>}
609
+ */
610
+ async function createFineTune(params = {}) {
611
+ return withAutoPoll((p) => requestInternal('/v1/finetuning/create', 'POST', p), params, 'finetuning');
612
+ }
613
+
614
+ /**
615
+ * Query the status of a fine-tuning task.
616
+ *
617
+ * @param {string} taskId - Fine-tune task ID.
618
+ * @returns {Promise<Object>}
619
+ */
620
+ async function queryFineTune(taskId) {
621
+ return requestInternal(`/v1/finetuning/query/${taskId}`, 'GET');
622
+ }
623
+
624
+ /* ============================================================
625
+ EXPORTS
626
+ ============================================================ */
627
+
628
+ export {
629
+ getHeaders,
630
+ saveAudioToLocal,
631
+ pollUntilDone,
632
+ generateSong,
633
+ generateInstrumental,
634
+ generateSoundtrack,
635
+ describeSong,
636
+ extendSong,
637
+ regenerateSong,
638
+ stemSong,
639
+ recognizeSong,
640
+ regionEditSong,
641
+ generateLyricsVideo,
642
+ generateTrack,
643
+ remixSong,
644
+ generateLyrics,
645
+ extendLyrics,
646
+ generateTTS,
647
+ generatePodcast,
648
+ cloneVocal,
649
+ uploadFile,
650
+ uploadsCreate,
651
+ uploadsAdd,
652
+ uploadsComplete,
653
+ queryTask,
654
+ getBilling,
655
+ getProfile,
656
+ createFineTune,
657
+ queryFineTune
658
+ };
@@ -0,0 +1,7 @@
1
+ import * as video from './video.js';
2
+ import videoToolset from './videoToolset.js'
3
+
4
+ export default {
5
+ video,
6
+ videoToolset
7
+ }