@elizaos/prompts 2.0.0-alpha
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/LICENSE +21 -0
- package/README.md +142 -0
- package/dist/python/__init__.py +2 -0
- package/dist/python/prompts.py +601 -0
- package/dist/rust/mod.rs +3 -0
- package/dist/rust/prompts.rs +575 -0
- package/dist/typescript/index.d.ts +42 -0
- package/dist/typescript/index.ts +615 -0
- package/package.json +47 -0
- package/prompts/autonomy_continuous_continue.txt +15 -0
- package/prompts/autonomy_continuous_first.txt +13 -0
- package/prompts/autonomy_task_continue.txt +17 -0
- package/prompts/autonomy_task_first.txt +14 -0
- package/prompts/choose_option.txt +25 -0
- package/prompts/image_description.txt +31 -0
- package/prompts/image_generation.txt +25 -0
- package/prompts/message_handler.txt +100 -0
- package/prompts/multi_step_decision.txt +52 -0
- package/prompts/multi_step_summary.txt +44 -0
- package/prompts/option_extraction.txt +31 -0
- package/prompts/post_creation.txt +52 -0
- package/prompts/reflection.txt +31 -0
- package/prompts/reflection_evaluator.txt +64 -0
- package/prompts/reply.txt +31 -0
- package/prompts/should_respond.txt +40 -0
- package/prompts/update_entity.txt +31 -0
- package/prompts/update_settings.txt +30 -0
- package/scripts/check-secrets.js +187 -0
- package/scripts/generate-action-docs.js +912 -0
- package/scripts/generate-plugin-action-spec.js +647 -0
- package/scripts/generate-plugin-prompts.js +306 -0
- package/scripts/generate.js +279 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate plugin action docs spec (best-effort).
|
|
4
|
+
*
|
|
5
|
+
* Scans plugins/** TypeScript action definitions and emits a merged spec file:
|
|
6
|
+
* packages/prompts/specs/actions/plugins.generated.json
|
|
7
|
+
*
|
|
8
|
+
* This is intentionally dependency-free and uses a small brace-aware extractor to
|
|
9
|
+
* locate `export const X: Action = { ... }` blocks.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
|
|
19
|
+
const REPO_ROOT = path.resolve(__dirname, "../../..");
|
|
20
|
+
const PROMPTS_ROOT = path.resolve(__dirname, "..");
|
|
21
|
+
|
|
22
|
+
const CORE_ACTIONS_SPEC_PATH = path.join(
|
|
23
|
+
PROMPTS_ROOT,
|
|
24
|
+
"specs",
|
|
25
|
+
"actions",
|
|
26
|
+
"core.json",
|
|
27
|
+
);
|
|
28
|
+
const PLUGINS_ROOT = path.join(REPO_ROOT, "plugins");
|
|
29
|
+
const OUTPUT_PATH = path.join(
|
|
30
|
+
PROMPTS_ROOT,
|
|
31
|
+
"specs",
|
|
32
|
+
"actions",
|
|
33
|
+
"plugins.generated.json",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
function readText(filePath) {
|
|
37
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readJson(filePath) {
|
|
41
|
+
return JSON.parse(readText(filePath));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ensureDir(dir) {
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function listTsFiles(rootDir) {
|
|
49
|
+
const out = [];
|
|
50
|
+
const stack = [rootDir];
|
|
51
|
+
while (stack.length > 0) {
|
|
52
|
+
const dir = stack.pop();
|
|
53
|
+
if (!dir) break;
|
|
54
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
55
|
+
const full = path.join(dir, ent.name);
|
|
56
|
+
if (ent.isDirectory()) {
|
|
57
|
+
// ignore generated + dist trees
|
|
58
|
+
if (
|
|
59
|
+
ent.name === "dist" ||
|
|
60
|
+
ent.name === "generated" ||
|
|
61
|
+
ent.name === "node_modules"
|
|
62
|
+
) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
stack.push(full);
|
|
66
|
+
} else if (ent.isFile() && ent.name.endsWith(".ts")) {
|
|
67
|
+
if (full.includes(`${path.sep}__tests__${path.sep}`)) continue;
|
|
68
|
+
if (full.endsWith(".test.ts")) continue;
|
|
69
|
+
out.push(full);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Extract object literal source for `export const X: Action = { ... }`.
|
|
78
|
+
* Returns array of `{ filePath, objectText }`.
|
|
79
|
+
*/
|
|
80
|
+
function extractActionObjects(filePath, src) {
|
|
81
|
+
const results = [];
|
|
82
|
+
const re = /:\s*Action\s*=\s*\{/gm;
|
|
83
|
+
for (;;) {
|
|
84
|
+
const m = re.exec(src);
|
|
85
|
+
if (m === null) break;
|
|
86
|
+
const braceStart = m.index + m[0].lastIndexOf("{");
|
|
87
|
+
|
|
88
|
+
// Parse balanced braces, skipping strings and comments.
|
|
89
|
+
let depth = 0;
|
|
90
|
+
let j = braceStart;
|
|
91
|
+
let inSingle = false;
|
|
92
|
+
let inDouble = false;
|
|
93
|
+
let inTemplate = false;
|
|
94
|
+
let inLineComment = false;
|
|
95
|
+
let inBlockComment = false;
|
|
96
|
+
let escaped = false;
|
|
97
|
+
|
|
98
|
+
while (j < src.length) {
|
|
99
|
+
const ch = src[j];
|
|
100
|
+
const next = j + 1 < src.length ? src[j + 1] : "";
|
|
101
|
+
|
|
102
|
+
if (inLineComment) {
|
|
103
|
+
if (ch === "\n") inLineComment = false;
|
|
104
|
+
j++;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (inBlockComment) {
|
|
108
|
+
if (ch === "*" && next === "/") {
|
|
109
|
+
inBlockComment = false;
|
|
110
|
+
j += 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
j++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!inSingle && !inDouble && !inTemplate) {
|
|
118
|
+
if (ch === "/" && next === "/") {
|
|
119
|
+
inLineComment = true;
|
|
120
|
+
j += 2;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (ch === "/" && next === "*") {
|
|
124
|
+
inBlockComment = true;
|
|
125
|
+
j += 2;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (inSingle) {
|
|
131
|
+
if (!escaped && ch === "'") inSingle = false;
|
|
132
|
+
escaped = !escaped && ch === "\\";
|
|
133
|
+
j++;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (inDouble) {
|
|
137
|
+
if (!escaped && ch === '"') inDouble = false;
|
|
138
|
+
escaped = !escaped && ch === "\\";
|
|
139
|
+
j++;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (inTemplate) {
|
|
143
|
+
if (!escaped && ch === "`") {
|
|
144
|
+
inTemplate = false;
|
|
145
|
+
j++;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
escaped = !escaped && ch === "\\";
|
|
149
|
+
j++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (ch === "'") {
|
|
154
|
+
inSingle = true;
|
|
155
|
+
j++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (ch === '"') {
|
|
159
|
+
inDouble = true;
|
|
160
|
+
j++;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (ch === "`") {
|
|
164
|
+
inTemplate = true;
|
|
165
|
+
j++;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (ch === "{") depth++;
|
|
170
|
+
if (ch === "}") {
|
|
171
|
+
depth--;
|
|
172
|
+
if (depth === 0) {
|
|
173
|
+
const objectText = src.slice(braceStart, j + 1);
|
|
174
|
+
results.push({ filePath, objectText });
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
j++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function unquoteStringLiteral(s) {
|
|
187
|
+
const trimmed = s.trim();
|
|
188
|
+
if (
|
|
189
|
+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
190
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
191
|
+
) {
|
|
192
|
+
// Best-effort unescape: handle common escapes.
|
|
193
|
+
const inner = trimmed.slice(1, -1);
|
|
194
|
+
return inner
|
|
195
|
+
.replaceAll("\\n", "\n")
|
|
196
|
+
.replaceAll("\\t", "\t")
|
|
197
|
+
.replaceAll('\\"', '"')
|
|
198
|
+
.replaceAll("\\'", "'")
|
|
199
|
+
.replaceAll("\\\\", "\\");
|
|
200
|
+
}
|
|
201
|
+
if (trimmed.startsWith("`") && trimmed.endsWith("`")) {
|
|
202
|
+
return trimmed.slice(1, -1);
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function isWs(ch) {
|
|
208
|
+
return ch === " " || ch === "\t" || ch === "\n" || ch === "\r";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function scanTopLevelPropertyValue(objText, propName) {
|
|
212
|
+
// objText is `{ ... }`
|
|
213
|
+
let i = 0;
|
|
214
|
+
let braceDepth = 0;
|
|
215
|
+
let bracketDepth = 0;
|
|
216
|
+
let inSingle = false;
|
|
217
|
+
let inDouble = false;
|
|
218
|
+
let inTemplate = false;
|
|
219
|
+
let inLineComment = false;
|
|
220
|
+
let inBlockComment = false;
|
|
221
|
+
let escaped = false;
|
|
222
|
+
|
|
223
|
+
while (i < objText.length) {
|
|
224
|
+
const ch = objText[i];
|
|
225
|
+
const next = i + 1 < objText.length ? objText[i + 1] : "";
|
|
226
|
+
|
|
227
|
+
if (inLineComment) {
|
|
228
|
+
if (ch === "\n") inLineComment = false;
|
|
229
|
+
i++;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (inBlockComment) {
|
|
233
|
+
if (ch === "*" && next === "/") {
|
|
234
|
+
inBlockComment = false;
|
|
235
|
+
i += 2;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
i++;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!inSingle && !inDouble && !inTemplate) {
|
|
243
|
+
if (ch === "/" && next === "/") {
|
|
244
|
+
inLineComment = true;
|
|
245
|
+
i += 2;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (ch === "/" && next === "*") {
|
|
249
|
+
inBlockComment = true;
|
|
250
|
+
i += 2;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (inSingle) {
|
|
256
|
+
if (!escaped && ch === "'") inSingle = false;
|
|
257
|
+
escaped = !escaped && ch === "\\";
|
|
258
|
+
i++;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (inDouble) {
|
|
262
|
+
if (!escaped && ch === '"') inDouble = false;
|
|
263
|
+
escaped = !escaped && ch === "\\";
|
|
264
|
+
i++;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (inTemplate) {
|
|
268
|
+
if (!escaped && ch === "`") inTemplate = false;
|
|
269
|
+
escaped = !escaped && ch === "\\";
|
|
270
|
+
i++;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (ch === "'") {
|
|
275
|
+
inSingle = true;
|
|
276
|
+
i++;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (ch === '"') {
|
|
280
|
+
inDouble = true;
|
|
281
|
+
i++;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (ch === "`") {
|
|
285
|
+
inTemplate = true;
|
|
286
|
+
i++;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (ch === "{") braceDepth++;
|
|
291
|
+
if (ch === "}") braceDepth--;
|
|
292
|
+
if (ch === "[") bracketDepth++;
|
|
293
|
+
if (ch === "]") bracketDepth--;
|
|
294
|
+
|
|
295
|
+
// Top-level inside the object: braceDepth === 1
|
|
296
|
+
if (braceDepth === 1 && bracketDepth === 0) {
|
|
297
|
+
// Look for `<propName>:` starting at identifier boundary.
|
|
298
|
+
if (objText.startsWith(propName, i)) {
|
|
299
|
+
const before = i > 0 ? objText[i - 1] : "";
|
|
300
|
+
const after =
|
|
301
|
+
i + propName.length < objText.length
|
|
302
|
+
? objText[i + propName.length]
|
|
303
|
+
: "";
|
|
304
|
+
const beforeOk = before === "" || !/[A-Za-z0-9_$]/.test(before);
|
|
305
|
+
const afterOk = after === "" || isWs(after) || after === ":";
|
|
306
|
+
if (beforeOk && afterOk) {
|
|
307
|
+
let j = i + propName.length;
|
|
308
|
+
while (j < objText.length && isWs(objText[j])) j++;
|
|
309
|
+
if (objText[j] !== ":") {
|
|
310
|
+
i++;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
j++;
|
|
314
|
+
while (j < objText.length && isWs(objText[j])) j++;
|
|
315
|
+
return objText.slice(j);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
i++;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function extractTopLevelStringProp(objText, propName) {
|
|
327
|
+
const tail = scanTopLevelPropertyValue(objText, propName);
|
|
328
|
+
if (!tail) return null;
|
|
329
|
+
// Parse a single string literal token.
|
|
330
|
+
const first = tail.trimStart();
|
|
331
|
+
if (
|
|
332
|
+
!(first.startsWith('"') || first.startsWith("'") || first.startsWith("`"))
|
|
333
|
+
) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Grab up to the end of the literal (best-effort, supports escaped quotes).
|
|
338
|
+
const quote = first[0];
|
|
339
|
+
let i = 1;
|
|
340
|
+
let escaped = false;
|
|
341
|
+
while (i < first.length) {
|
|
342
|
+
const ch = first[i];
|
|
343
|
+
if (!escaped && ch === quote) break;
|
|
344
|
+
escaped = !escaped && ch === "\\";
|
|
345
|
+
i++;
|
|
346
|
+
}
|
|
347
|
+
if (i >= first.length) return null;
|
|
348
|
+
return unquoteStringLiteral(first.slice(0, i + 1));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function extractTopLevelStringArrayProp(objText, propName) {
|
|
352
|
+
const tail = scanTopLevelPropertyValue(objText, propName);
|
|
353
|
+
if (!tail) return [];
|
|
354
|
+
const first = tail.trimStart();
|
|
355
|
+
if (!first.startsWith("[")) return [];
|
|
356
|
+
let depth = 0;
|
|
357
|
+
let i = 0;
|
|
358
|
+
let inSingle = false;
|
|
359
|
+
let inDouble = false;
|
|
360
|
+
let inTemplate = false;
|
|
361
|
+
let escaped = false;
|
|
362
|
+
while (i < first.length) {
|
|
363
|
+
const ch = first[i];
|
|
364
|
+
if (inSingle) {
|
|
365
|
+
if (!escaped && ch === "'") inSingle = false;
|
|
366
|
+
escaped = !escaped && ch === "\\";
|
|
367
|
+
i++;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (inDouble) {
|
|
371
|
+
if (!escaped && ch === '"') inDouble = false;
|
|
372
|
+
escaped = !escaped && ch === "\\";
|
|
373
|
+
i++;
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (inTemplate) {
|
|
377
|
+
if (!escaped && ch === "`") inTemplate = false;
|
|
378
|
+
escaped = !escaped && ch === "\\";
|
|
379
|
+
i++;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (ch === "'") {
|
|
384
|
+
inSingle = true;
|
|
385
|
+
i++;
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
if (ch === '"') {
|
|
389
|
+
inDouble = true;
|
|
390
|
+
i++;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (ch === "`") {
|
|
394
|
+
inTemplate = true;
|
|
395
|
+
i++;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (ch === "[") depth++;
|
|
400
|
+
if (ch === "]") {
|
|
401
|
+
depth--;
|
|
402
|
+
if (depth === 0) break;
|
|
403
|
+
}
|
|
404
|
+
i++;
|
|
405
|
+
}
|
|
406
|
+
if (depth !== 0) return [];
|
|
407
|
+
const inner = first.slice(1, i);
|
|
408
|
+
const vals = [];
|
|
409
|
+
const strRe = /(["'`])((?:\\.|(?!\1).)*)\1/gm;
|
|
410
|
+
for (;;) {
|
|
411
|
+
const m = strRe.exec(inner);
|
|
412
|
+
if (m === null) break;
|
|
413
|
+
const quote = m[1];
|
|
414
|
+
const raw = quote + m[2] + quote;
|
|
415
|
+
const unq = unquoteStringLiteral(raw);
|
|
416
|
+
if (typeof unq === "string") vals.push(unq);
|
|
417
|
+
}
|
|
418
|
+
return vals;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function main() {
|
|
422
|
+
const core = readJson(CORE_ACTIONS_SPEC_PATH);
|
|
423
|
+
const version = typeof core.version === "string" ? core.version : "1.0.0";
|
|
424
|
+
const coreActionNames = new Set(
|
|
425
|
+
Array.isArray(core.actions)
|
|
426
|
+
? core.actions
|
|
427
|
+
.map((a) => (a && typeof a === "object" ? a.name : null))
|
|
428
|
+
.filter((n) => typeof n === "string")
|
|
429
|
+
: [],
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
const commonParamDocs = new Map([
|
|
433
|
+
[
|
|
434
|
+
"url",
|
|
435
|
+
{
|
|
436
|
+
description: "The URL to navigate to.",
|
|
437
|
+
example: "https://example.com",
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
[
|
|
441
|
+
"owner",
|
|
442
|
+
{ description: "Repository owner or organization.", example: "octocat" },
|
|
443
|
+
],
|
|
444
|
+
["repo", { description: "Repository name.", example: "my-repo" }],
|
|
445
|
+
["branch", { description: "Branch name.", example: "main" }],
|
|
446
|
+
["base", { description: "Base branch to merge into.", example: "main" }],
|
|
447
|
+
[
|
|
448
|
+
"head",
|
|
449
|
+
{
|
|
450
|
+
description: "Head branch to merge from.",
|
|
451
|
+
example: "feature/dark-mode",
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
[
|
|
455
|
+
"title",
|
|
456
|
+
{
|
|
457
|
+
description: "Title for the operation.",
|
|
458
|
+
example: "Add dark mode support",
|
|
459
|
+
},
|
|
460
|
+
],
|
|
461
|
+
[
|
|
462
|
+
"body",
|
|
463
|
+
{
|
|
464
|
+
description: "Body text for the operation.",
|
|
465
|
+
example: "Implements dark mode and updates docs.",
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
["draft", { description: "Whether to create as draft.", example: false }],
|
|
469
|
+
[
|
|
470
|
+
"channelId",
|
|
471
|
+
{
|
|
472
|
+
description: "Target channel identifier.",
|
|
473
|
+
example: "123456789012345678",
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
[
|
|
477
|
+
"userId",
|
|
478
|
+
{ description: "Target user identifier.", example: "123456789012345678" },
|
|
479
|
+
],
|
|
480
|
+
[
|
|
481
|
+
"message",
|
|
482
|
+
{
|
|
483
|
+
description: "Message text to send.",
|
|
484
|
+
example: "Hello! How can I help?",
|
|
485
|
+
},
|
|
486
|
+
],
|
|
487
|
+
["amount", { description: "Amount to use (as a string).", example: "0.1" }],
|
|
488
|
+
[
|
|
489
|
+
"fromToken",
|
|
490
|
+
{
|
|
491
|
+
description: "Source token address or symbol.",
|
|
492
|
+
example: "0x0000000000000000000000000000000000000000",
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
[
|
|
496
|
+
"toToken",
|
|
497
|
+
{
|
|
498
|
+
description: "Destination token address or symbol.",
|
|
499
|
+
example: "0x0000000000000000000000000000000000000000",
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
[
|
|
503
|
+
"chain",
|
|
504
|
+
{ description: "Chain identifier or name.", example: "ethereum" },
|
|
505
|
+
],
|
|
506
|
+
["slippage", { description: "Max slippage percentage.", example: 1 }],
|
|
507
|
+
]);
|
|
508
|
+
|
|
509
|
+
function humanizeKey(key) {
|
|
510
|
+
return key
|
|
511
|
+
.replaceAll(/[_-]+/g, " ")
|
|
512
|
+
.replaceAll(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
513
|
+
.toLowerCase();
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function inferParamType(objText, key) {
|
|
517
|
+
const re = new RegExp(`state\\?\\.${key}\\s+as\\s+([A-Za-z0-9_]+)`, "g");
|
|
518
|
+
const m = re.exec(objText);
|
|
519
|
+
const t = m?.[1];
|
|
520
|
+
if (t === "boolean") return "boolean";
|
|
521
|
+
if (t === "number") return "number";
|
|
522
|
+
return "string";
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function inferParameters(objText) {
|
|
526
|
+
const keys = new Set();
|
|
527
|
+
const keyRe = /state\?\.\s*([A-Za-z0-9_]+)/g;
|
|
528
|
+
for (;;) {
|
|
529
|
+
const m = keyRe.exec(objText);
|
|
530
|
+
if (m === null) break;
|
|
531
|
+
keys.add(m[1]);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const params = [];
|
|
535
|
+
for (const key of Array.from(keys).sort((a, b) => a.localeCompare(b))) {
|
|
536
|
+
const type = inferParamType(objText, key);
|
|
537
|
+
const known = commonParamDocs.get(key);
|
|
538
|
+
const description =
|
|
539
|
+
known?.description ?? `The ${humanizeKey(key)} to use.`;
|
|
540
|
+
const example =
|
|
541
|
+
known?.example ??
|
|
542
|
+
(type === "boolean" ? false : type === "number" ? 1 : "example");
|
|
543
|
+
params.push({
|
|
544
|
+
name: key,
|
|
545
|
+
description,
|
|
546
|
+
required: false,
|
|
547
|
+
schema: { type },
|
|
548
|
+
examples: [example],
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return params;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function buildExampleCallForAction(actionName, params) {
|
|
556
|
+
if (!params || params.length === 0) {
|
|
557
|
+
return [];
|
|
558
|
+
}
|
|
559
|
+
/** @type {Record<string, string | number | boolean | null>} */
|
|
560
|
+
const sampleParams = {};
|
|
561
|
+
for (const p of params) {
|
|
562
|
+
const ex =
|
|
563
|
+
Array.isArray(p.examples) && p.examples.length > 0
|
|
564
|
+
? p.examples[0]
|
|
565
|
+
: null;
|
|
566
|
+
sampleParams[p.name] =
|
|
567
|
+
typeof ex === "string" ||
|
|
568
|
+
typeof ex === "number" ||
|
|
569
|
+
typeof ex === "boolean" ||
|
|
570
|
+
ex === null
|
|
571
|
+
? ex
|
|
572
|
+
: "example";
|
|
573
|
+
}
|
|
574
|
+
return [
|
|
575
|
+
{
|
|
576
|
+
user: `Use ${actionName} with the provided parameters.`,
|
|
577
|
+
actions: [actionName],
|
|
578
|
+
params: {
|
|
579
|
+
[actionName]: sampleParams,
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
];
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const tsFiles = listTsFiles(PLUGINS_ROOT);
|
|
586
|
+
const actionDocsByName = new Map();
|
|
587
|
+
|
|
588
|
+
for (const filePath of tsFiles) {
|
|
589
|
+
// Only consider files that look like they might define actions.
|
|
590
|
+
if (
|
|
591
|
+
!filePath.includes(`${path.sep}actions${path.sep}`) &&
|
|
592
|
+
!filePath.endsWith(`${path.sep}actions.ts`)
|
|
593
|
+
) {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
const src = readText(filePath);
|
|
597
|
+
if (!src.includes(": Action")) continue;
|
|
598
|
+
|
|
599
|
+
const objects = extractActionObjects(filePath, src);
|
|
600
|
+
for (const obj of objects) {
|
|
601
|
+
const name = extractTopLevelStringProp(obj.objectText, "name");
|
|
602
|
+
if (!name) continue;
|
|
603
|
+
if (coreActionNames.has(name)) continue;
|
|
604
|
+
const description =
|
|
605
|
+
extractTopLevelStringProp(obj.objectText, "description") ?? "";
|
|
606
|
+
const similes = extractTopLevelStringArrayProp(obj.objectText, "similes");
|
|
607
|
+
const parameters = inferParameters(obj.objectText);
|
|
608
|
+
const exampleCalls = buildExampleCallForAction(name, parameters);
|
|
609
|
+
|
|
610
|
+
// Do not overwrite existing entries; prefer the first seen (stable ordering).
|
|
611
|
+
if (!actionDocsByName.has(name)) {
|
|
612
|
+
actionDocsByName.set(name, {
|
|
613
|
+
name,
|
|
614
|
+
description,
|
|
615
|
+
similes: similes.length > 0 ? similes : undefined,
|
|
616
|
+
parameters,
|
|
617
|
+
exampleCalls,
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const actions = Array.from(actionDocsByName.values())
|
|
624
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
625
|
+
.map((a) => {
|
|
626
|
+
const out = {
|
|
627
|
+
name: a.name,
|
|
628
|
+
description: a.description,
|
|
629
|
+
parameters: a.parameters,
|
|
630
|
+
};
|
|
631
|
+
if (a.similes) out.similes = a.similes;
|
|
632
|
+
if (a.exampleCalls && a.exampleCalls.length > 0) {
|
|
633
|
+
out.exampleCalls = a.exampleCalls;
|
|
634
|
+
}
|
|
635
|
+
return out;
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
const outRoot = { version, actions };
|
|
639
|
+
|
|
640
|
+
ensureDir(path.dirname(OUTPUT_PATH));
|
|
641
|
+
fs.writeFileSync(OUTPUT_PATH, `${JSON.stringify(outRoot, null, 2)}\n`);
|
|
642
|
+
console.log(
|
|
643
|
+
`Wrote ${actions.length} plugin actions to ${path.relative(REPO_ROOT, OUTPUT_PATH)}`,
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
main();
|