@elizaos/plugin-suno 1.0.6-alpha.4 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/auto-enable.ts +18 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +242 -437
- package/dist/index.js.map +1 -1
- package/package.json +62 -35
- package/biome.json +0 -41
- package/src/actions/customGenerate.ts +0 -186
- package/src/actions/extend.ts +0 -164
- package/src/actions/generate.ts +0 -175
- package/src/index.ts +0 -22
- package/src/providers/suno.ts +0 -78
- package/src/types/index.ts +0 -34
- package/tsconfig.json +0 -24
- package/tsup.config.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// src/providers/suno.ts
|
|
2
|
+
import {
|
|
3
|
+
recordLlmCall
|
|
4
|
+
} from "@elizaos/core";
|
|
2
5
|
var SunoProvider = class _SunoProvider {
|
|
3
6
|
apiKey;
|
|
4
7
|
baseUrl;
|
|
5
8
|
static async get(runtime, _message, _state) {
|
|
6
9
|
const apiKey = runtime.getSetting("SUNO_API_KEY");
|
|
7
|
-
if (!apiKey) {
|
|
10
|
+
if (typeof apiKey !== "string" || !apiKey) {
|
|
8
11
|
throw new Error("SUNO_API_KEY is required");
|
|
9
12
|
}
|
|
10
13
|
return new _SunoProvider({ apiKey });
|
|
@@ -16,491 +19,293 @@ var SunoProvider = class _SunoProvider {
|
|
|
16
19
|
async get(_runtime, _message, _state) {
|
|
17
20
|
return { status: "ready" };
|
|
18
21
|
}
|
|
19
|
-
async request(endpoint, options = {}) {
|
|
22
|
+
async request(runtime, endpoint, options = {}) {
|
|
20
23
|
const url = `${this.baseUrl}${endpoint}`;
|
|
21
24
|
const headers = {
|
|
22
|
-
|
|
25
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
23
26
|
"Content-Type": "application/json",
|
|
24
27
|
...options.headers
|
|
25
28
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const body = typeof options.body === "string" ? options.body : "";
|
|
30
|
+
const details = {
|
|
31
|
+
model: "suno",
|
|
32
|
+
modelVersion: "api-v1",
|
|
33
|
+
systemPrompt: "Suno music generation API request",
|
|
34
|
+
userPrompt: body,
|
|
35
|
+
temperature: readTemperature(body),
|
|
36
|
+
maxTokens: 0,
|
|
37
|
+
purpose: "action",
|
|
38
|
+
actionType: `suno.fetch${endpoint}`
|
|
39
|
+
};
|
|
40
|
+
return recordLlmCall(runtime, details, async () => {
|
|
41
|
+
const response = await fetch(url, {
|
|
42
|
+
...options,
|
|
43
|
+
headers
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`Suno API error: ${response.statusText}`);
|
|
47
|
+
}
|
|
48
|
+
const data = await response.json();
|
|
49
|
+
details.response = JSON.stringify({ suno_response: data });
|
|
50
|
+
return data;
|
|
29
51
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
function readTemperature(body) {
|
|
55
|
+
if (!body) return 0;
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(body);
|
|
58
|
+
return typeof parsed.temperature === "number" ? parsed.temperature : 0;
|
|
59
|
+
} catch {
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
var sunoStatusProvider = {
|
|
64
|
+
name: "SUNO_STATUS",
|
|
65
|
+
description: "Suno music generation status",
|
|
66
|
+
descriptionCompressed: "Suno generation availability.",
|
|
67
|
+
contexts: ["media"],
|
|
68
|
+
contextGate: { anyOf: ["media"] },
|
|
69
|
+
cacheStable: false,
|
|
70
|
+
cacheScope: "turn",
|
|
71
|
+
get: async (runtime) => {
|
|
72
|
+
const configured = Boolean(runtime.getSetting("SUNO_API_KEY"));
|
|
73
|
+
return {
|
|
74
|
+
text: JSON.stringify(
|
|
75
|
+
{
|
|
76
|
+
suno: {
|
|
77
|
+
configured,
|
|
78
|
+
status: configured ? "ready" : "missing_api_key",
|
|
79
|
+
action: "MUSIC_GENERATION",
|
|
80
|
+
subactions: ["generate", "custom", "extend"]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
null,
|
|
84
|
+
2
|
|
85
|
+
),
|
|
86
|
+
data: { configured },
|
|
87
|
+
values: { sunoConfigured: configured }
|
|
88
|
+
};
|
|
34
89
|
}
|
|
35
90
|
};
|
|
36
91
|
|
|
37
|
-
// src/actions/
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
92
|
+
// src/actions/musicGeneration.ts
|
|
93
|
+
var SUNO_ACTION_TIMEOUT_MS = 3e4;
|
|
94
|
+
var MAX_SUNO_RESPONSE_BYTES = 4e3;
|
|
95
|
+
function paramsFromMessageAndOptions(message, options) {
|
|
96
|
+
const content = message.content && typeof message.content === "object" ? message.content : {};
|
|
97
|
+
const parameters = (options == null ? void 0 : options.parameters) && typeof options.parameters === "object" ? options.parameters : {};
|
|
98
|
+
return { ...content, ...options, ...parameters };
|
|
99
|
+
}
|
|
100
|
+
function normalizeSubaction(value) {
|
|
101
|
+
const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
102
|
+
if (normalized === "generate" || normalized === "custom" || normalized === "extend") {
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
105
|
+
if (normalized === "custom_generate" || normalized === "custom-generate") return "custom";
|
|
106
|
+
if (normalized === "extend_audio" || normalized === "extend-audio") return "extend";
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function inferSubaction(message, params) {
|
|
110
|
+
var _a;
|
|
111
|
+
const explicit = normalizeSubaction(params.action ?? params.subaction ?? params.operation);
|
|
112
|
+
if (explicit) return explicit;
|
|
113
|
+
const text = (((_a = message.content) == null ? void 0 : _a.text) ?? "").toLowerCase();
|
|
114
|
+
if (params.audio_id || /\b(extend|lengthen|longer|add \d+.*seconds?)\b/.test(text)) {
|
|
115
|
+
return "extend";
|
|
116
|
+
}
|
|
117
|
+
if (params.reference_audio || params.style || params.bpm || params.key || params.mode || /\b(custom|style|bpm|key|mode|reference)\b/.test(text)) {
|
|
118
|
+
return "custom";
|
|
119
|
+
}
|
|
120
|
+
return "generate";
|
|
121
|
+
}
|
|
122
|
+
function promptFromParams(message, params) {
|
|
123
|
+
var _a;
|
|
124
|
+
const prompt = typeof params.prompt === "string" ? params.prompt.trim() : "";
|
|
125
|
+
if (prompt) return prompt;
|
|
126
|
+
return (((_a = message.content) == null ? void 0 : _a.text) ?? "").trim();
|
|
127
|
+
}
|
|
128
|
+
function numberOrDefault(value, fallback) {
|
|
129
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
130
|
+
}
|
|
131
|
+
function generationBody(params, prompt) {
|
|
132
|
+
return {
|
|
133
|
+
prompt,
|
|
134
|
+
duration: numberOrDefault(params.duration, 30),
|
|
135
|
+
temperature: numberOrDefault(params.temperature, 1),
|
|
136
|
+
top_k: numberOrDefault(params.topK, 250),
|
|
137
|
+
top_p: numberOrDefault(params.topP, 0.95),
|
|
138
|
+
classifier_free_guidance: numberOrDefault(params.classifier_free_guidance, 3)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
var musicGeneration = {
|
|
142
|
+
name: "MUSIC_GENERATION",
|
|
143
|
+
contexts: ["media"],
|
|
144
|
+
contextGate: { anyOf: ["media"] },
|
|
145
|
+
roleGate: { minRole: "USER" },
|
|
146
|
+
description: "Generate music through Suno. Use action generate for a simple prompt, custom for style/BPM/key/reference parameters, or extend for an existing audio_id and duration.",
|
|
147
|
+
descriptionCompressed: "Suno music generation router action: generate, custom, extend.",
|
|
41
148
|
similes: [
|
|
149
|
+
"GENERATE_MUSIC",
|
|
42
150
|
"CREATE_MUSIC",
|
|
43
151
|
"MAKE_MUSIC",
|
|
44
152
|
"COMPOSE_MUSIC",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"MAKE_SONG"
|
|
153
|
+
"CUSTOM_GENERATE_MUSIC",
|
|
154
|
+
"EXTEND_AUDIO"
|
|
48
155
|
],
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throw new Error("Missing required parameter: prompt");
|
|
80
|
-
}
|
|
81
|
-
const response = await provider.request("/generate", {
|
|
82
|
-
method: "POST",
|
|
83
|
-
body: JSON.stringify({
|
|
84
|
-
prompt: content.prompt,
|
|
85
|
-
duration: content.duration || 30,
|
|
86
|
-
temperature: content.temperature || 1,
|
|
87
|
-
top_k: content.topK || 250,
|
|
88
|
-
top_p: content.topP || 0.95,
|
|
89
|
-
classifier_free_guidance: content.classifier_free_guidance || 3
|
|
90
|
-
})
|
|
91
|
-
});
|
|
92
|
-
if (callback) {
|
|
93
|
-
callback({
|
|
94
|
-
text: "Successfully generated music based on your prompt",
|
|
95
|
-
content: response
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return true;
|
|
99
|
-
} catch (error) {
|
|
100
|
-
if (callback) {
|
|
101
|
-
callback({
|
|
102
|
-
text: `Failed to extend audio: ${error.message}`,
|
|
103
|
-
error
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
return false;
|
|
156
|
+
parameters: [
|
|
157
|
+
{
|
|
158
|
+
name: "action",
|
|
159
|
+
description: "Suno operation: generate, custom, or extend.",
|
|
160
|
+
required: false,
|
|
161
|
+
schema: { type: "string", enum: ["generate", "custom", "extend"] }
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "subaction",
|
|
165
|
+
description: "Legacy alias for action.",
|
|
166
|
+
required: false,
|
|
167
|
+
schema: { type: "string" }
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: "prompt",
|
|
171
|
+
description: "Music prompt for generate/custom.",
|
|
172
|
+
required: false,
|
|
173
|
+
schema: { type: "string" }
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "audio_id",
|
|
177
|
+
description: "Existing Suno audio id for extend.",
|
|
178
|
+
required: false,
|
|
179
|
+
schema: { type: "string" }
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "duration",
|
|
183
|
+
description: "Generation duration or extension seconds.",
|
|
184
|
+
required: false,
|
|
185
|
+
schema: { type: "number", default: 30 }
|
|
107
186
|
}
|
|
108
|
-
},
|
|
109
|
-
examples: [
|
|
110
|
-
[
|
|
111
|
-
{
|
|
112
|
-
user: "{{user1}}",
|
|
113
|
-
content: {
|
|
114
|
-
text: "Create a happy and energetic song",
|
|
115
|
-
prompt: "A cheerful and energetic melody with upbeat rhythm",
|
|
116
|
-
duration: 30,
|
|
117
|
-
temperature: 1
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
user: "{{agent}}",
|
|
122
|
-
content: {
|
|
123
|
-
text: "I'll generate a happy and energetic song for you.",
|
|
124
|
-
action: "generate-music"
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
user: "{{agent}}",
|
|
129
|
-
content: {
|
|
130
|
-
text: "Successfully generated your upbeat and energetic song."
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
],
|
|
134
|
-
[
|
|
135
|
-
{
|
|
136
|
-
user: "{{user1}}",
|
|
137
|
-
content: {
|
|
138
|
-
text: "Generate a relaxing ambient track",
|
|
139
|
-
prompt: "A peaceful ambient soundscape with gentle waves and soft pads",
|
|
140
|
-
duration: 45,
|
|
141
|
-
temperature: 0.8,
|
|
142
|
-
classifier_free_guidance: 4
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
user: "{{agent}}",
|
|
147
|
-
content: {
|
|
148
|
-
text: "I'll create a calming ambient piece for you.",
|
|
149
|
-
action: "generate-music"
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
user: "{{agent}}",
|
|
154
|
-
content: {
|
|
155
|
-
text: "Successfully generated your relaxing ambient soundscape."
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
],
|
|
159
|
-
[
|
|
160
|
-
{
|
|
161
|
-
user: "{{user1}}",
|
|
162
|
-
content: {
|
|
163
|
-
text: "Make a short jingle for my podcast",
|
|
164
|
-
prompt: "A catchy and professional podcast intro jingle",
|
|
165
|
-
duration: 15,
|
|
166
|
-
temperature: 1.2,
|
|
167
|
-
top_k: 300
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
user: "{{agent}}",
|
|
172
|
-
content: {
|
|
173
|
-
text: "I'll generate a podcast jingle for you.",
|
|
174
|
-
action: "generate-music"
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
user: "{{agent}}",
|
|
179
|
-
content: {
|
|
180
|
-
text: "Successfully generated your podcast jingle."
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
]
|
|
184
|
-
]
|
|
185
|
-
};
|
|
186
|
-
var generate_default = generateMusic;
|
|
187
|
-
|
|
188
|
-
// src/actions/customGenerate.ts
|
|
189
|
-
var customGenerateMusic = {
|
|
190
|
-
name: "custom-generate-music",
|
|
191
|
-
description: "Generate music with custom parameters using Suno AI",
|
|
192
|
-
similes: [
|
|
193
|
-
"CREATE_CUSTOM_MUSIC",
|
|
194
|
-
"GENERATE_CUSTOM_AUDIO",
|
|
195
|
-
"MAKE_CUSTOM_MUSIC",
|
|
196
|
-
"COMPOSE_CUSTOM_MUSIC",
|
|
197
|
-
"COMPOSE_MUSIC",
|
|
198
|
-
"CREATE_MUSIC",
|
|
199
|
-
"GENERATE_MUSIC"
|
|
200
187
|
],
|
|
201
|
-
validate: async (runtime, message
|
|
202
|
-
var _a
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((word) => word.length > 0 && __avText.includes(word));
|
|
207
|
-
const __avRegex = new RegExp("\\b(?:custom|generate|music)\\b", "i");
|
|
208
|
-
const __avRegexOk = __avRegex.test(__avText);
|
|
209
|
-
const __avSource = String(((_b = message == null ? void 0 : message.content) == null ? void 0 : _b.source) ?? (message == null ? void 0 : message.source) ?? "");
|
|
210
|
-
const __avExpectedSource = "";
|
|
211
|
-
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || (runtime == null ? void 0 : runtime.agentId) || (runtime == null ? void 0 : runtime.getService) || (runtime == null ? void 0 : runtime.getSetting));
|
|
212
|
-
const __avOptions = options && typeof options === "object" ? options : {};
|
|
213
|
-
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean((message == null ? void 0 : message.content) && typeof message.content === "object");
|
|
214
|
-
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
const __avLegacyValidate = async (runtime2, _message) => {
|
|
218
|
-
return !!runtime2.getSetting("SUNO_API_KEY");
|
|
219
|
-
};
|
|
220
|
-
try {
|
|
221
|
-
return Boolean(await __avLegacyValidate(runtime, message, state, options));
|
|
222
|
-
} catch {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
188
|
+
validate: async (runtime, message) => {
|
|
189
|
+
var _a;
|
|
190
|
+
if (!runtime.getSetting("SUNO_API_KEY")) return false;
|
|
191
|
+
const text = (((_a = message.content) == null ? void 0 : _a.text) ?? "").toLowerCase();
|
|
192
|
+
return /\b(generate|create|make|compose|extend|music|song|audio|track)\b/.test(text);
|
|
225
193
|
},
|
|
226
|
-
handler: async (runtime, message, state,
|
|
194
|
+
handler: async (runtime, message, state, options, callback) => {
|
|
227
195
|
try {
|
|
196
|
+
const params = paramsFromMessageAndOptions(message, options);
|
|
197
|
+
const subaction = inferSubaction(message, params);
|
|
228
198
|
const provider = await SunoProvider.get(runtime, message, state);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
method: "POST",
|
|
235
|
-
body: JSON.stringify({
|
|
236
|
-
prompt: content.prompt,
|
|
237
|
-
duration: content.duration || 30,
|
|
238
|
-
temperature: content.temperature || 1,
|
|
239
|
-
top_k: content.topK || 250,
|
|
240
|
-
top_p: content.topP || 0.95,
|
|
241
|
-
classifier_free_guidance: content.classifier_free_guidance || 3,
|
|
242
|
-
reference_audio: content.reference_audio,
|
|
243
|
-
style: content.style,
|
|
244
|
-
bpm: content.bpm,
|
|
245
|
-
key: content.key,
|
|
246
|
-
mode: content.mode
|
|
247
|
-
})
|
|
248
|
-
});
|
|
249
|
-
if (callback) {
|
|
250
|
-
callback({
|
|
251
|
-
text: "Successfully generated custom music",
|
|
252
|
-
content: response
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
return true;
|
|
256
|
-
} catch (error) {
|
|
257
|
-
if (callback) {
|
|
258
|
-
callback({
|
|
259
|
-
text: `Failed to generate custom music: ${error.message}`,
|
|
260
|
-
error
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
examples: [
|
|
267
|
-
[
|
|
268
|
-
{
|
|
269
|
-
user: "{{user1}}",
|
|
270
|
-
content: {
|
|
271
|
-
text: "Create an upbeat electronic dance track with heavy bass",
|
|
272
|
-
prompt: "An upbeat electronic dance track with heavy bass and energetic synths",
|
|
273
|
-
duration: 60,
|
|
274
|
-
style: "electronic",
|
|
275
|
-
bpm: 128
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
{
|
|
279
|
-
user: "{{agent}}",
|
|
280
|
-
content: {
|
|
281
|
-
text: "I'll generate an energetic EDM track for you.",
|
|
282
|
-
action: "custom-generate-music"
|
|
283
|
-
}
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
user: "{{agent}}",
|
|
287
|
-
content: {
|
|
288
|
-
text: "Successfully generated your EDM track with heavy bass and synths."
|
|
199
|
+
let endpoint = "/generate";
|
|
200
|
+
let body;
|
|
201
|
+
if (subaction === "extend") {
|
|
202
|
+
if (!params.audio_id || !params.duration) {
|
|
203
|
+
throw new Error("Missing required parameters: audio_id and duration");
|
|
289
204
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
style: "classical",
|
|
300
|
-
key: "C",
|
|
301
|
-
mode: "major",
|
|
302
|
-
temperature: 0.8
|
|
205
|
+
endpoint = "/extend";
|
|
206
|
+
body = {
|
|
207
|
+
audio_id: params.audio_id,
|
|
208
|
+
duration: params.duration
|
|
209
|
+
};
|
|
210
|
+
} else {
|
|
211
|
+
const prompt = promptFromParams(message, params);
|
|
212
|
+
if (!prompt) {
|
|
213
|
+
throw new Error("Missing required parameter: prompt");
|
|
303
214
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
text: "Successfully generated your peaceful piano melody in C major."
|
|
215
|
+
body = generationBody(params, prompt);
|
|
216
|
+
if (subaction === "custom") {
|
|
217
|
+
endpoint = "/custom-generate";
|
|
218
|
+
body = {
|
|
219
|
+
...body,
|
|
220
|
+
reference_audio: params.reference_audio,
|
|
221
|
+
style: params.style,
|
|
222
|
+
bpm: params.bpm,
|
|
223
|
+
key: params.key,
|
|
224
|
+
mode: params.mode
|
|
225
|
+
};
|
|
316
226
|
}
|
|
317
227
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
{
|
|
321
|
-
user: "{{user1}}",
|
|
322
|
-
content: {
|
|
323
|
-
text: "Make a rock song with guitar solos",
|
|
324
|
-
prompt: "A rock song with powerful electric guitar solos and driving drums",
|
|
325
|
-
duration: 90,
|
|
326
|
-
style: "rock",
|
|
327
|
-
bpm: 120,
|
|
328
|
-
classifier_free_guidance: 4
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
{
|
|
332
|
-
user: "{{agent}}",
|
|
333
|
-
content: {
|
|
334
|
-
text: "I'll generate a rock track with guitar solos for you.",
|
|
335
|
-
action: "custom-generate-music"
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
user: "{{agent}}",
|
|
340
|
-
content: {
|
|
341
|
-
text: "Successfully generated your rock song with guitar solos."
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
]
|
|
345
|
-
]
|
|
346
|
-
};
|
|
347
|
-
var customGenerate_default = customGenerateMusic;
|
|
348
|
-
|
|
349
|
-
// src/actions/extend.ts
|
|
350
|
-
var extendAudio = {
|
|
351
|
-
name: "extend-audio",
|
|
352
|
-
description: "Extend the duration of an existing audio generation",
|
|
353
|
-
similes: [
|
|
354
|
-
"LENGTHEN_AUDIO",
|
|
355
|
-
"PROLONG_AUDIO",
|
|
356
|
-
"INCREASE_DURATION",
|
|
357
|
-
"MAKE_AUDIO_LONGER"
|
|
358
|
-
],
|
|
359
|
-
validate: async (runtime, message, state, options) => {
|
|
360
|
-
var _a, _b;
|
|
361
|
-
const __avTextRaw = typeof ((_a = message == null ? void 0 : message.content) == null ? void 0 : _a.text) === "string" ? message.content.text : "";
|
|
362
|
-
const __avText = __avTextRaw.toLowerCase();
|
|
363
|
-
const __avKeywords = ["extend", "audio"];
|
|
364
|
-
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((word) => word.length > 0 && __avText.includes(word));
|
|
365
|
-
const __avRegex = new RegExp("\\b(?:extend|audio)\\b", "i");
|
|
366
|
-
const __avRegexOk = __avRegex.test(__avText);
|
|
367
|
-
const __avSource = String(((_b = message == null ? void 0 : message.content) == null ? void 0 : _b.source) ?? (message == null ? void 0 : message.source) ?? "");
|
|
368
|
-
const __avExpectedSource = "";
|
|
369
|
-
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || (runtime == null ? void 0 : runtime.agentId) || (runtime == null ? void 0 : runtime.getService) || (runtime == null ? void 0 : runtime.getSetting));
|
|
370
|
-
const __avOptions = options && typeof options === "object" ? options : {};
|
|
371
|
-
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean((message == null ? void 0 : message.content) && typeof message.content === "object");
|
|
372
|
-
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
373
|
-
return false;
|
|
374
|
-
}
|
|
375
|
-
const __avLegacyValidate = async (runtime2, _message) => {
|
|
376
|
-
return !!runtime2.getSetting("SUNO_API_KEY");
|
|
377
|
-
};
|
|
378
|
-
try {
|
|
379
|
-
return Boolean(await __avLegacyValidate(runtime, message, state, options));
|
|
380
|
-
} catch {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
},
|
|
384
|
-
handler: async (runtime, message, state, _options, callback) => {
|
|
385
|
-
try {
|
|
386
|
-
const provider = await SunoProvider.get(runtime, message, state);
|
|
387
|
-
const content = message.content;
|
|
388
|
-
if (!content.audio_id || !content.duration) {
|
|
389
|
-
throw new Error("Missing required parameters: audio_id and duration");
|
|
390
|
-
}
|
|
391
|
-
const response = await provider.request("/extend", {
|
|
228
|
+
const controller = new AbortController();
|
|
229
|
+
const timeout = setTimeout(() => controller.abort(), SUNO_ACTION_TIMEOUT_MS);
|
|
230
|
+
const response = await provider.request(runtime, endpoint, {
|
|
392
231
|
method: "POST",
|
|
393
|
-
body: JSON.stringify(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
return
|
|
232
|
+
body: JSON.stringify(body),
|
|
233
|
+
signal: controller.signal
|
|
234
|
+
}).finally(() => clearTimeout(timeout));
|
|
235
|
+
const cappedResponse = JSON.stringify(response).length > MAX_SUNO_RESPONSE_BYTES ? {
|
|
236
|
+
truncated: true,
|
|
237
|
+
preview: JSON.stringify(response).slice(0, MAX_SUNO_RESPONSE_BYTES)
|
|
238
|
+
} : response;
|
|
239
|
+
await (callback == null ? void 0 : callback({
|
|
240
|
+
text: subaction === "extend" ? `Successfully extended audio ${params.audio_id}` : `Successfully submitted ${subaction} music generation`,
|
|
241
|
+
content: cappedResponse
|
|
242
|
+
}));
|
|
243
|
+
return {
|
|
244
|
+
success: true,
|
|
245
|
+
text: subaction === "extend" ? `Successfully extended audio ${params.audio_id}` : `Successfully submitted ${subaction} music generation`,
|
|
246
|
+
data: { subaction, response: cappedResponse }
|
|
247
|
+
};
|
|
405
248
|
} catch (error) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
return false;
|
|
249
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
250
|
+
const text = `Music generation failed: ${errorMessage}`;
|
|
251
|
+
await (callback == null ? void 0 : callback({
|
|
252
|
+
text,
|
|
253
|
+
error
|
|
254
|
+
}));
|
|
255
|
+
return { success: false, text, error: errorMessage };
|
|
413
256
|
}
|
|
414
257
|
},
|
|
415
258
|
examples: [
|
|
416
259
|
[
|
|
417
260
|
{
|
|
418
|
-
|
|
419
|
-
content: {
|
|
420
|
-
text: "Make this song longer by 30 seconds",
|
|
421
|
-
audio_id: "abc123",
|
|
422
|
-
duration: 30
|
|
423
|
-
}
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
user: "{{agent}}",
|
|
427
|
-
content: {
|
|
428
|
-
text: "I'll extend your song by 30 seconds.",
|
|
429
|
-
action: "extend-audio"
|
|
430
|
-
}
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
user: "{{agent}}",
|
|
434
|
-
content: {
|
|
435
|
-
text: "Successfully extended your song by 30 seconds."
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
],
|
|
439
|
-
[
|
|
440
|
-
{
|
|
441
|
-
user: "{{user1}}",
|
|
261
|
+
name: "{{user1}}",
|
|
442
262
|
content: {
|
|
443
|
-
text: "
|
|
444
|
-
|
|
445
|
-
duration:
|
|
446
|
-
}
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
user: "{{agent}}",
|
|
450
|
-
content: {
|
|
451
|
-
text: "I'll double the duration of your track.",
|
|
452
|
-
action: "extend-audio"
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
user: "{{agent}}",
|
|
457
|
-
content: {
|
|
458
|
-
text: "Successfully doubled the length of your track to 60 seconds."
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
],
|
|
462
|
-
[
|
|
463
|
-
{
|
|
464
|
-
user: "{{user1}}",
|
|
465
|
-
content: {
|
|
466
|
-
text: "Add 15 more seconds to this melody",
|
|
467
|
-
audio_id: "def456",
|
|
468
|
-
duration: 15
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
{
|
|
472
|
-
user: "{{agent}}",
|
|
473
|
-
content: {
|
|
474
|
-
text: "I'll add 15 seconds to your melody.",
|
|
475
|
-
action: "extend-audio"
|
|
263
|
+
text: "Generate a relaxing ambient track",
|
|
264
|
+
prompt: "A peaceful ambient soundscape with gentle waves and soft pads",
|
|
265
|
+
duration: 45
|
|
476
266
|
}
|
|
477
267
|
},
|
|
478
268
|
{
|
|
479
|
-
|
|
269
|
+
name: "{{agent}}",
|
|
480
270
|
content: {
|
|
481
|
-
text: "
|
|
271
|
+
text: "I'll generate a calming ambient piece.",
|
|
272
|
+
action: "MUSIC_GENERATION"
|
|
482
273
|
}
|
|
483
274
|
}
|
|
484
275
|
]
|
|
485
276
|
]
|
|
486
277
|
};
|
|
487
|
-
var
|
|
278
|
+
var musicGeneration_default = musicGeneration;
|
|
488
279
|
|
|
489
280
|
// src/index.ts
|
|
490
281
|
var sunoPlugin = {
|
|
491
282
|
name: "suno",
|
|
492
283
|
description: "Suno AI Music Generation Plugin for Eliza",
|
|
493
|
-
actions: [
|
|
494
|
-
|
|
495
|
-
|
|
284
|
+
actions: [musicGeneration_default],
|
|
285
|
+
providers: [sunoStatusProvider],
|
|
286
|
+
// Self-declared auto-enable: activate when SUNO_API_KEY is set OR when
|
|
287
|
+
// media.audio is configured to use the suno provider with own-key mode.
|
|
288
|
+
autoEnable: {
|
|
289
|
+
shouldEnable: (env, config) => {
|
|
290
|
+
const key = env.SUNO_API_KEY;
|
|
291
|
+
if (typeof key === "string" && key.trim() !== "") return true;
|
|
292
|
+
const media = config == null ? void 0 : config.media;
|
|
293
|
+
const audio = media == null ? void 0 : media.audio;
|
|
294
|
+
return Boolean(
|
|
295
|
+
audio && audio.enabled !== false && audio.mode === "own-key" && audio.provider === "suno"
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
496
299
|
};
|
|
497
300
|
var index_default = sunoPlugin;
|
|
498
301
|
export {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
302
|
+
musicGeneration_default as CustomGenerateMusic,
|
|
303
|
+
musicGeneration_default as ExtendAudio,
|
|
304
|
+
musicGeneration_default as GenerateMusic,
|
|
305
|
+
musicGeneration_default as MusicGeneration,
|
|
502
306
|
SunoProvider,
|
|
503
307
|
index_default as default,
|
|
504
|
-
sunoPlugin
|
|
308
|
+
sunoPlugin,
|
|
309
|
+
sunoStatusProvider
|
|
505
310
|
};
|
|
506
311
|
//# sourceMappingURL=index.js.map
|