@oneie/sdk 0.8.0 → 0.10.0

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 (92) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +336 -190
  3. package/dist/auth.d.ts +102 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +156 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/brain.d.ts +36 -0
  8. package/dist/brain.d.ts.map +1 -0
  9. package/dist/brain.js +99 -0
  10. package/dist/brain.js.map +1 -0
  11. package/dist/client.d.ts +222 -30
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +339 -173
  14. package/dist/client.js.map +1 -1
  15. package/dist/compile.d.ts +123 -0
  16. package/dist/compile.d.ts.map +1 -0
  17. package/dist/compile.js +652 -0
  18. package/dist/compile.js.map +1 -0
  19. package/dist/fetch.d.ts +40 -0
  20. package/dist/fetch.d.ts.map +1 -0
  21. package/dist/fetch.js +158 -0
  22. package/dist/fetch.js.map +1 -0
  23. package/dist/generated/types.d.ts +104 -0
  24. package/dist/generated/types.d.ts.map +1 -0
  25. package/dist/generated/types.js +5 -0
  26. package/dist/generated/types.js.map +1 -0
  27. package/dist/index.d.ts +17 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +11 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/meta.d.ts +45 -0
  32. package/dist/meta.d.ts.map +1 -0
  33. package/dist/meta.js +44 -0
  34. package/dist/meta.js.map +1 -0
  35. package/dist/openapi.d.ts +27 -0
  36. package/dist/openapi.d.ts.map +1 -0
  37. package/dist/openapi.js +62 -0
  38. package/dist/openapi.js.map +1 -0
  39. package/dist/pay.d.ts +2 -2
  40. package/dist/pay.d.ts.map +1 -1
  41. package/dist/pay.js +5 -5
  42. package/dist/pay.js.map +1 -1
  43. package/dist/receivers.d.ts +743 -0
  44. package/dist/receivers.d.ts.map +1 -0
  45. package/dist/receivers.js +626 -0
  46. package/dist/receivers.js.map +1 -0
  47. package/dist/schemas.d.ts +39 -0
  48. package/dist/schemas.d.ts.map +1 -1
  49. package/dist/schemas.js +26 -0
  50. package/dist/schemas.js.map +1 -1
  51. package/dist/skills.d.ts +40 -0
  52. package/dist/skills.d.ts.map +1 -0
  53. package/dist/skills.js +16 -0
  54. package/dist/skills.js.map +1 -0
  55. package/dist/soul.d.ts +10 -0
  56. package/dist/soul.d.ts.map +1 -0
  57. package/dist/soul.js +31 -0
  58. package/dist/soul.js.map +1 -0
  59. package/dist/storage.d.ts +7 -8
  60. package/dist/storage.d.ts.map +1 -1
  61. package/dist/storage.js +61 -33
  62. package/dist/storage.js.map +1 -1
  63. package/dist/telemetry.d.ts +9 -0
  64. package/dist/telemetry.d.ts.map +1 -1
  65. package/dist/telemetry.js +11 -0
  66. package/dist/telemetry.js.map +1 -1
  67. package/dist/testing/index.d.ts.map +1 -1
  68. package/dist/testing/index.js +4 -3
  69. package/dist/testing/index.js.map +1 -1
  70. package/dist/types.d.ts +113 -22
  71. package/dist/types.d.ts.map +1 -1
  72. package/package.json +43 -17
  73. package/dist/react/context.d.ts +0 -11
  74. package/dist/react/context.d.ts.map +0 -1
  75. package/dist/react/context.js +0 -13
  76. package/dist/react/context.js.map +0 -1
  77. package/dist/react/hooks.d.ts +0 -104
  78. package/dist/react/hooks.d.ts.map +0 -1
  79. package/dist/react/hooks.js +0 -247
  80. package/dist/react/hooks.js.map +0 -1
  81. package/dist/react/index.d.ts +0 -6
  82. package/dist/react/index.d.ts.map +0 -1
  83. package/dist/react/index.js +0 -5
  84. package/dist/react/index.js.map +0 -1
  85. package/dist/react/optimistic.d.ts +0 -45
  86. package/dist/react/optimistic.d.ts.map +0 -1
  87. package/dist/react/optimistic.js +0 -52
  88. package/dist/react/optimistic.js.map +0 -1
  89. package/dist/react/stream.d.ts +0 -18
  90. package/dist/react/stream.d.ts.map +0 -1
  91. package/dist/react/stream.js +0 -60
  92. package/dist/react/stream.js.map +0 -1
@@ -0,0 +1,652 @@
1
+ /**
2
+ * compile.ts — Agent markdown → compilation targets
3
+ *
4
+ * Usage:
5
+ * import { compileAgent } from "@oneie/sdk/compile"
6
+ *
7
+ * const py = compileAgent(agentMd, { skills, target: 'uagents' })
8
+ * const mcp = compileAgent(agentMd, { skills, target: 'mcp' })
9
+ */
10
+ // ── YAML parser (recursive, no external deps) ────────────────────────────────
11
+ function yamlScalar(s) {
12
+ if (s === 'true')
13
+ return true;
14
+ if (s === 'false')
15
+ return false;
16
+ if (s === 'null' || s === '~' || s === '')
17
+ return null;
18
+ if (/^-?\d+$/.test(s))
19
+ return parseInt(s, 10);
20
+ if (/^-?\d*\.\d+$/.test(s))
21
+ return parseFloat(s);
22
+ if (s.startsWith('['))
23
+ return yamlInlineSeq(s);
24
+ if (s.startsWith('{'))
25
+ return yamlInlineMap(s);
26
+ return s.replace(/^["']|["']$/g, '');
27
+ }
28
+ function splitCommaRespectingDepth(s) {
29
+ const parts = [];
30
+ let depth = 0;
31
+ let cur = '';
32
+ for (const ch of s) {
33
+ if (ch === '[' || ch === '{') {
34
+ depth++;
35
+ cur += ch;
36
+ }
37
+ else if (ch === ']' || ch === '}') {
38
+ depth--;
39
+ cur += ch;
40
+ }
41
+ else if (ch === ',' && depth === 0) {
42
+ parts.push(cur.trim());
43
+ cur = '';
44
+ }
45
+ else
46
+ cur += ch;
47
+ }
48
+ if (cur.trim())
49
+ parts.push(cur.trim());
50
+ return parts;
51
+ }
52
+ function yamlInlineSeq(s) {
53
+ const inner = s.slice(1, -1).trim();
54
+ if (!inner)
55
+ return [];
56
+ return splitCommaRespectingDepth(inner)
57
+ .map(t => yamlScalar(t.replace(/^["']|["']$/g, '')))
58
+ .filter(v => v !== null && v !== '');
59
+ }
60
+ function yamlInlineMap(s) {
61
+ const inner = s.slice(1, -1).trim();
62
+ if (!inner)
63
+ return {};
64
+ const obj = {};
65
+ for (const part of splitCommaRespectingDepth(inner)) {
66
+ const colon = part.indexOf(':');
67
+ if (colon === -1)
68
+ continue;
69
+ const k = part.slice(0, colon).trim();
70
+ const v = part.slice(colon + 1).trim();
71
+ obj[k] = yamlScalar(v);
72
+ }
73
+ return obj;
74
+ }
75
+ function indentOf(line) {
76
+ let i = 0;
77
+ while (i < line.length && line[i] === ' ')
78
+ i++;
79
+ return i;
80
+ }
81
+ /** Parse lines[start..] that belong to indent level `indent`. Returns [value, nextIndex]. */
82
+ function yamlBlock(lines, start, indent) {
83
+ // Find first non-empty line at this level
84
+ let i = start;
85
+ while (i < lines.length && (lines[i].trim() === '' || lines[i].trim().startsWith('#')))
86
+ i++;
87
+ if (i >= lines.length)
88
+ return [null, i];
89
+ const lineIndent = indentOf(lines[i]);
90
+ if (lineIndent < indent)
91
+ return [null, i];
92
+ const content = lines[i].trimStart();
93
+ // Detect: sequence or mapping
94
+ if (content.startsWith('- ')) {
95
+ return yamlSeq(lines, i, lineIndent);
96
+ }
97
+ return yamlMap(lines, i, lineIndent);
98
+ }
99
+ function yamlMap(lines, start, indent) {
100
+ const obj = {};
101
+ let i = start;
102
+ while (i < lines.length) {
103
+ const line = lines[i];
104
+ if (line.trim() === '' || line.trim().startsWith('#')) {
105
+ i++;
106
+ continue;
107
+ }
108
+ const li = indentOf(line);
109
+ if (li < indent)
110
+ break;
111
+ if (li > indent) {
112
+ i++;
113
+ continue;
114
+ }
115
+ const content = line.trimStart();
116
+ // List item at this level — stop, let parent handle
117
+ if (content.startsWith('- '))
118
+ break;
119
+ const colon = content.indexOf(':');
120
+ if (colon === -1) {
121
+ i++;
122
+ continue;
123
+ }
124
+ const key = content.slice(0, colon).trim();
125
+ const val = content.slice(colon + 1).trim();
126
+ if (val !== '') {
127
+ obj[key] = yamlScalar(val);
128
+ i++;
129
+ }
130
+ else {
131
+ // Look ahead for child block
132
+ let j = i + 1;
133
+ while (j < lines.length && (lines[j].trim() === '' || lines[j].trim().startsWith('#')))
134
+ j++;
135
+ if (j >= lines.length || indentOf(lines[j]) <= indent) {
136
+ obj[key] = null;
137
+ i++;
138
+ }
139
+ else {
140
+ const childIndent = indentOf(lines[j]);
141
+ const [childValue, nextI] = yamlBlock(lines, j, childIndent);
142
+ obj[key] = childValue;
143
+ i = nextI;
144
+ }
145
+ }
146
+ }
147
+ return [obj, i];
148
+ }
149
+ function yamlSeq(lines, start, indent) {
150
+ const list = [];
151
+ let i = start;
152
+ while (i < lines.length) {
153
+ const line = lines[i];
154
+ if (line.trim() === '' || line.trim().startsWith('#')) {
155
+ i++;
156
+ continue;
157
+ }
158
+ const li = indentOf(line);
159
+ if (li < indent)
160
+ break;
161
+ if (li > indent) {
162
+ i++;
163
+ continue;
164
+ }
165
+ const content = line.trimStart();
166
+ if (!content.startsWith('- '))
167
+ break;
168
+ const itemContent = content.slice(2).trim();
169
+ i++;
170
+ if (itemContent === '') {
171
+ // Next block is the item value
172
+ let j = i;
173
+ while (j < lines.length && (lines[j].trim() === '' || lines[j].trim().startsWith('#')))
174
+ j++;
175
+ if (j < lines.length && indentOf(lines[j]) > indent) {
176
+ const [val, nextI] = yamlBlock(lines, j, indentOf(lines[j]));
177
+ list.push(val);
178
+ i = nextI;
179
+ }
180
+ }
181
+ else if (itemContent.includes(':')) {
182
+ // Inline first key-value of an object item
183
+ const colon = itemContent.indexOf(':');
184
+ const k = itemContent.slice(0, colon).trim();
185
+ const v = itemContent.slice(colon + 1).trim();
186
+ const obj = { [k]: v !== '' ? yamlScalar(v) : null };
187
+ // Collect continuation lines at greater indent
188
+ while (i < lines.length) {
189
+ if (lines[i].trim() === '' || lines[i].trim().startsWith('#')) {
190
+ i++;
191
+ continue;
192
+ }
193
+ const nextLi = indentOf(lines[i]);
194
+ if (nextLi <= indent)
195
+ break;
196
+ if (lines[i].trimStart().startsWith('- '))
197
+ break;
198
+ const rest = lines[i].trimStart();
199
+ const c2 = rest.indexOf(':');
200
+ if (c2 !== -1) {
201
+ const k2 = rest.slice(0, c2).trim();
202
+ const v2 = rest.slice(c2 + 1).trim();
203
+ if (v2 !== '') {
204
+ obj[k2] = yamlScalar(v2);
205
+ i++;
206
+ }
207
+ else {
208
+ // Nested child inside list item
209
+ let j = i + 1;
210
+ while (j < lines.length && (lines[j].trim() === '' || lines[j].trim().startsWith('#')))
211
+ j++;
212
+ if (j < lines.length && indentOf(lines[j]) > nextLi) {
213
+ const [childVal, nextI] = yamlBlock(lines, j, indentOf(lines[j]));
214
+ obj[k2] = childVal;
215
+ i = nextI;
216
+ }
217
+ else {
218
+ obj[k2] = null;
219
+ i++;
220
+ }
221
+ }
222
+ }
223
+ else {
224
+ i++;
225
+ }
226
+ }
227
+ list.push(obj);
228
+ }
229
+ else {
230
+ list.push(yamlScalar(itemContent));
231
+ }
232
+ }
233
+ return [list, i];
234
+ }
235
+ function parseFrontmatter(yaml) {
236
+ const lines = yaml.split('\n');
237
+ const [result] = yamlMap(lines, 0, 0);
238
+ return result;
239
+ }
240
+ export function priceToAccepts(price) {
241
+ return [{ scheme: 'exact', network: 'eip155:8453', asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', max: price.toFixed(6) }];
242
+ }
243
+ function coerceAgentMeta(raw) {
244
+ const str = (v) => (v != null ? String(v) : undefined);
245
+ const num = (v) => (typeof v === 'number' ? v : typeof v === 'string' ? parseFloat(v) : undefined);
246
+ const int = (v) => (typeof v === 'number' ? Math.floor(v) : typeof v === 'string' ? parseInt(v, 10) : undefined);
247
+ const bool = (v) => (typeof v === 'boolean' ? v : v === 'true' ? true : false);
248
+ const strList = (v) => Array.isArray(v) ? v.map(String) : v != null ? String(v).split(',').map(s => s.trim()) : undefined;
249
+ const coerceSkills = (v) => {
250
+ if (!Array.isArray(v))
251
+ return undefined;
252
+ return v.map(item => {
253
+ if (typeof item === 'string')
254
+ return { ref: item };
255
+ if (typeof item === 'object' && item !== null) {
256
+ const o = item;
257
+ if (typeof o.ref === 'string')
258
+ return { ref: o.ref };
259
+ return {
260
+ name: String(o.name ?? ''),
261
+ title: str(o.title),
262
+ description: str(o.description),
263
+ price: num(o.price) ?? 0,
264
+ tags: strList(o.tags) ?? [],
265
+ version: str(o.version),
266
+ inputSchema: o.inputSchema,
267
+ outputSchema: o.outputSchema,
268
+ when_to_use: str(o.when_to_use),
269
+ };
270
+ }
271
+ return { ref: String(item) };
272
+ });
273
+ };
274
+ const coerceIntervals = (v) => {
275
+ if (!Array.isArray(v))
276
+ return undefined;
277
+ return v.flatMap(item => {
278
+ if (typeof item !== 'object' || item === null)
279
+ return [];
280
+ const o = item;
281
+ const period = int(o.period);
282
+ const task = str(o.task);
283
+ if (period == null || task == null)
284
+ return [];
285
+ return [{ period, task }];
286
+ });
287
+ };
288
+ const coerceEndpoints = (v) => {
289
+ if (!Array.isArray(v))
290
+ return undefined;
291
+ return v.flatMap(item => {
292
+ if (typeof item !== 'object' || item === null)
293
+ return [];
294
+ const o = item;
295
+ const method = (str(o.method) ?? 'GET').toUpperCase();
296
+ const path = str(o.path);
297
+ const response = str(o.response);
298
+ if (!path || !response)
299
+ return [];
300
+ return [{ method, path, request: str(o.request), response }];
301
+ });
302
+ };
303
+ return {
304
+ name: str(raw.name),
305
+ title: str(raw.title),
306
+ version: str(raw.version),
307
+ model: str(raw.model),
308
+ group: str(raw.group),
309
+ channels: strList(raw.channels),
310
+ lifecycle: str(raw.lifecycle),
311
+ wallet: str(raw.wallet),
312
+ sensitivity: num(raw.sensitivity),
313
+ description: str(raw.description),
314
+ starters: strList(raw.starters),
315
+ skills: coerceSkills(raw.skills),
316
+ tools: strList(raw.tools),
317
+ seed: str(raw.seed),
318
+ port: int(raw.port),
319
+ agentverse: str(raw.agentverse),
320
+ mailbox: raw.mailbox != null ? bool(raw.mailbox) : undefined,
321
+ startup: str(raw.startup),
322
+ shutdown: str(raw.shutdown),
323
+ intervals: coerceIntervals(raw.intervals),
324
+ endpoints: coerceEndpoints(raw.endpoints),
325
+ bureau: strList(raw.bureau),
326
+ price: num(raw.price),
327
+ agentmd: str(raw.agentmd),
328
+ summary: str(raw.summary),
329
+ accepts: Array.isArray(raw.accepts) ? raw.accepts : raw.price ? priceToAccepts(num(raw.price) ?? 0) : undefined,
330
+ evals: Array.isArray(raw.evals) ? raw.evals : undefined,
331
+ currency: str(raw.currency),
332
+ tags: strList(raw.tags),
333
+ when_to_use: str(raw.when_to_use),
334
+ inputSchema: raw.inputSchema,
335
+ outputSchema: raw.outputSchema,
336
+ };
337
+ }
338
+ export function parseAgentMd(raw) {
339
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
340
+ if (!match)
341
+ return { meta: {}, prompt: raw.trim() };
342
+ const rawMeta = parseFrontmatter(match[1]);
343
+ return { meta: coerceAgentMeta(rawMeta), prompt: match[2].trim() };
344
+ }
345
+ // ── JSON Schema → Pydantic model ─────────────────────────────────────────────
346
+ function schemaToPython(schema, modelName, required = []) {
347
+ if (!schema || schema.type !== 'object')
348
+ return `class ${modelName}(Model):\n pass`;
349
+ const props = schema.properties;
350
+ if (!props || Object.keys(props).length === 0)
351
+ return `class ${modelName}(Model):\n pass`;
352
+ const typeMap = {
353
+ string: 'str', integer: 'int', number: 'float',
354
+ boolean: 'bool', object: 'dict', array: 'list',
355
+ };
356
+ const fields = Object.entries(props).map(([field, def]) => {
357
+ const pyType = typeMap[String(def.type ?? 'string')] ?? 'str';
358
+ const isRequired = required.includes(field);
359
+ const snakeField = field.replace(/([A-Z])/g, m => `_${m.toLowerCase()}`);
360
+ return isRequired
361
+ ? ` ${snakeField}: ${pyType}`
362
+ : ` ${snakeField}: ${pyType} | None = None`;
363
+ });
364
+ return `class ${modelName}(Model):\n${fields.join('\n')}`;
365
+ }
366
+ function toPascal(s) {
367
+ return s.replace(/[-_](.)/g, (_, c) => c.toUpperCase())
368
+ .replace(/^(.)/, (_, c) => c.toUpperCase());
369
+ }
370
+ function toSnake(s) {
371
+ return s.replace(/-/g, '_');
372
+ }
373
+ function compileProtocol(skill, llmModel) {
374
+ const pascal = toPascal(skill.name);
375
+ const snake = toSnake(skill.name);
376
+ const reqClass = `${pascal}Request`;
377
+ const resClass = `${pascal}Response`;
378
+ const inputRequired = skill.inputSchema?.required ?? [];
379
+ const outputRequired = skill.outputSchema?.required ?? [];
380
+ const reqModel = schemaToPython(skill.inputSchema, reqClass, inputRequired);
381
+ const resModel = schemaToPython(skill.outputSchema, resClass, outputRequired);
382
+ return `
383
+ # ── ${skill.title} ──────────────────────────────────────────────────────────
384
+ ${reqModel}
385
+
386
+ ${resModel}
387
+
388
+ ${snake}_protocol = Protocol(name="${skill.name}", version="${skill.version}")
389
+
390
+ SKILL_${snake.toUpperCase()} = """
391
+ ${skill.prompt}
392
+ """
393
+
394
+ @${snake}_protocol.on_message(model=${reqClass}, replies={${resClass}})
395
+ async def ${snake}_handler(ctx: Context, sender: str, msg: ${reqClass}):
396
+ client = Anthropic()
397
+ result = client.messages.create(
398
+ model="${llmModel}",
399
+ max_tokens=1024,
400
+ system=SKILL_${snake.toUpperCase()},
401
+ messages=[{"role": "user", "content": str(msg.model_dump())}],
402
+ )
403
+ text = result.content[0].text
404
+ await ctx.send(sender, ${resClass}.model_validate({"resolution": text}))
405
+ `.trimStart();
406
+ }
407
+ function compileUAgents(agentMd, skillMds = {}) {
408
+ const { meta, prompt } = parseAgentMd(agentMd);
409
+ const name = meta.name ?? 'agent';
410
+ const llmModel = meta.model
411
+ ? meta.model.split('/').pop() ?? 'claude-haiku-4-5'
412
+ : 'claude-haiku-4-5';
413
+ const skills = (meta.skills ?? []).flatMap(s => {
414
+ const skillName = 'ref' in s ? s.ref : s.name;
415
+ const raw = skillMds[skillName];
416
+ if (!raw)
417
+ return [];
418
+ const { meta: sm, prompt: sp } = parseAgentMd(raw);
419
+ return [{
420
+ name: sm.name ?? skillName,
421
+ title: sm.title ?? sm.name ?? skillName,
422
+ description: sm.description ?? '',
423
+ version: sm.version ?? '1.0.0',
424
+ prompt: sp,
425
+ inputSchema: sm.inputSchema,
426
+ outputSchema: sm.outputSchema,
427
+ }];
428
+ });
429
+ const hasIntervals = (meta.intervals?.length ?? 0) > 0;
430
+ const hasEndpoints = (meta.endpoints?.length ?? 0) > 0;
431
+ const hasBureau = (meta.bureau?.length ?? 0) > 0;
432
+ const hasSkills = skills.length > 0;
433
+ const lines = [
434
+ '# Generated by @oneie/sdk — do not edit by hand',
435
+ `# Source: agents/${name}.md`,
436
+ '',
437
+ 'from anthropic import Anthropic',
438
+ hasBureau
439
+ ? 'from uagents import Agent, Bureau, Context, Protocol'
440
+ : 'from uagents import Agent, Context, Protocol',
441
+ ];
442
+ if (hasSkills)
443
+ lines.push('from uagents.models import Model');
444
+ lines.push('');
445
+ for (const skill of skills) {
446
+ lines.push(compileProtocol(skill, llmModel));
447
+ }
448
+ lines.push('# ── Agent ─────────────────────────────────────────────────────────────────────');
449
+ lines.push('');
450
+ lines.push('SYSTEM_PROMPT = """');
451
+ lines.push(prompt);
452
+ lines.push('"""');
453
+ lines.push('');
454
+ const agentArgs = [` name="${name}"`];
455
+ if (meta.seed)
456
+ agentArgs.push(` seed="${meta.seed}"`);
457
+ if (meta.port && meta.port !== 8000)
458
+ agentArgs.push(` port=${meta.port}`);
459
+ if (meta.mailbox)
460
+ agentArgs.push(` mailbox=True`);
461
+ lines.push(`${name} = Agent(`);
462
+ lines.push(agentArgs.join(',\n') + ',');
463
+ lines.push(')');
464
+ lines.push('');
465
+ for (const skill of skills) {
466
+ lines.push(`${name}.include(${toSnake(skill.name)}_protocol, publish_manifest=True)`);
467
+ }
468
+ if (hasSkills)
469
+ lines.push('');
470
+ if (meta.startup) {
471
+ lines.push(`@${name}.on_event("startup")`);
472
+ lines.push(`async def on_startup(ctx: Context):`);
473
+ lines.push(` client = Anthropic()`);
474
+ lines.push(` result = client.messages.create(`);
475
+ lines.push(` model="${llmModel}", max_tokens=256, system=SYSTEM_PROMPT,`);
476
+ lines.push(` messages=[{"role": "user", "content": "${meta.startup.replace(/"/g, '\\"')}"}],`);
477
+ lines.push(` )`);
478
+ lines.push(` ctx.logger.info(result.content[0].text)`);
479
+ lines.push('');
480
+ }
481
+ if (meta.shutdown) {
482
+ lines.push(`@${name}.on_event("shutdown")`);
483
+ lines.push(`async def on_shutdown(ctx: Context):`);
484
+ lines.push(` client = Anthropic()`);
485
+ lines.push(` result = client.messages.create(`);
486
+ lines.push(` model="${llmModel}", max_tokens=256, system=SYSTEM_PROMPT,`);
487
+ lines.push(` messages=[{"role": "user", "content": "${meta.shutdown.replace(/"/g, '\\"')}"}],`);
488
+ lines.push(` )`);
489
+ lines.push(` ctx.logger.info(result.content[0].text)`);
490
+ lines.push('');
491
+ }
492
+ if (hasIntervals) {
493
+ for (const [idx, interval] of (meta.intervals ?? []).entries()) {
494
+ lines.push(`@${name}.on_interval(period=${interval.period})`);
495
+ lines.push(`async def interval_${idx}(ctx: Context):`);
496
+ lines.push(` client = Anthropic()`);
497
+ lines.push(` result = client.messages.create(`);
498
+ lines.push(` model="${llmModel}", max_tokens=512, system=SYSTEM_PROMPT,`);
499
+ lines.push(` messages=[{"role": "user", "content": "${interval.task.replace(/"/g, '\\"')}"}],`);
500
+ lines.push(` )`);
501
+ lines.push(` ctx.logger.info(result.content[0].text)`);
502
+ lines.push('');
503
+ }
504
+ }
505
+ if (hasEndpoints) {
506
+ lines.push('class Response(Model):');
507
+ lines.push(' text: str');
508
+ lines.push('');
509
+ for (const endpoint of meta.endpoints ?? []) {
510
+ const fnName = `${endpoint.method.toLowerCase()}${endpoint.path.replace(/\//g, '_').replace(/[^a-z0-9_]/gi, '')}`;
511
+ if (endpoint.method === 'GET') {
512
+ lines.push(`@${name}.on_rest_get("${endpoint.path}", Response)`);
513
+ lines.push(`async def ${fnName}(ctx: Context) -> dict:`);
514
+ }
515
+ else {
516
+ lines.push(`@${name}.on_rest_post("${endpoint.path}", Response)`);
517
+ lines.push(`async def ${fnName}(ctx: Context, req: dict) -> dict:`);
518
+ }
519
+ lines.push(` client = Anthropic()`);
520
+ lines.push(` result = client.messages.create(`);
521
+ lines.push(` model="${llmModel}", max_tokens=512, system=SYSTEM_PROMPT,`);
522
+ lines.push(` messages=[{"role": "user", "content": "${endpoint.response.replace(/"/g, '\\"')}"}],`);
523
+ lines.push(` )`);
524
+ lines.push(` return {"text": result.content[0].text}`);
525
+ lines.push('');
526
+ }
527
+ }
528
+ if (hasBureau) {
529
+ lines.push('# ── Bureau ────────────────────────────────────────────────────────────────────');
530
+ lines.push('');
531
+ lines.push('bureau = Bureau()');
532
+ lines.push(`bureau.add(${name})`);
533
+ for (const sibling of meta.bureau ?? []) {
534
+ lines.push(`# bureau.add(${toSnake(sibling)}) # import from ${sibling}.py`);
535
+ }
536
+ lines.push('');
537
+ lines.push('if __name__ == "__main__":');
538
+ lines.push(' bureau.run()');
539
+ }
540
+ else {
541
+ lines.push('if __name__ == "__main__":');
542
+ lines.push(` ${name}.run()`);
543
+ }
544
+ return lines.join('\n') + '\n';
545
+ }
546
+ // ── MCP compiler ──────────────────────────────────────────────────────────────
547
+ function compileMcp(agentMd, skillMds = {}) {
548
+ const { meta } = parseAgentMd(agentMd);
549
+ const tools = (meta.skills ?? []).flatMap(s => {
550
+ const skillName = 'ref' in s ? s.ref : s.name;
551
+ const raw = skillMds[skillName];
552
+ if (!raw)
553
+ return [];
554
+ const { meta: sm } = parseAgentMd(raw);
555
+ const tool = {
556
+ name: sm.name ?? skillName,
557
+ description: sm.description ?? sm.title ?? skillName,
558
+ };
559
+ if (sm.inputSchema)
560
+ tool.inputSchema = sm.inputSchema;
561
+ return [tool];
562
+ });
563
+ return JSON.stringify({
564
+ name: meta.name ?? 'agent',
565
+ title: meta.title ?? meta.name ?? 'Agent',
566
+ version: meta.version ?? '1.0.0',
567
+ tools,
568
+ }, null, 2);
569
+ }
570
+ // ── SKILL.md compiler ─────────────────────────────────────────────────────────
571
+ function compileSkillMd(skillMds) {
572
+ return Object.entries(skillMds).map(([name, raw]) => {
573
+ const { meta, prompt } = parseAgentMd(raw);
574
+ const lines = [
575
+ `---`,
576
+ `name: ${meta.name ?? name}`,
577
+ `description: ${meta.description ?? prompt.slice(0, 80).replace(/\n/g, ' ')}`,
578
+ ];
579
+ if (meta.when_to_use)
580
+ lines.push(`when_to_use: ${meta.when_to_use}`);
581
+ lines.push(`---`, '', prompt);
582
+ return lines.join('\n');
583
+ }).join('\n\n---\n\n');
584
+ }
585
+ /**
586
+ * Compile an agent markdown file to a target runtime.
587
+ *
588
+ * @param agentMd Raw content of the agent.md file
589
+ * @param opts Compilation options
590
+ * @returns Generated source string (Python / JSON / SKILL.md)
591
+ *
592
+ * @example
593
+ * ```ts
594
+ * import { compileAgent } from "@oneie/sdk/compile"
595
+ * import { readFileSync, readdirSync, writeFileSync } from "node:fs"
596
+ *
597
+ * const skills: Record<string, string> = {}
598
+ * for (const f of readdirSync("skills")) {
599
+ * skills[f.replace(".md", "")] = readFileSync(`skills/${f}`, "utf8")
600
+ * }
601
+ *
602
+ * const py = compileAgent(readFileSync("agents/support.md", "utf8"), { skills })
603
+ * writeFileSync("dist/support_agent.py", py)
604
+ * ```
605
+ */
606
+ export function compileAgent(agentMd, opts = {}) {
607
+ const target = opts.target ?? 'uagents';
608
+ const skills = opts.skills ?? {};
609
+ if (target === 'uagents')
610
+ return compileUAgents(agentMd, skills);
611
+ if (target === 'mcp')
612
+ return compileMcp(agentMd, skills);
613
+ if (target === 'skillmd')
614
+ return compileSkillMd(skills);
615
+ if (target === 'web')
616
+ return compileWeb(agentMd);
617
+ throw new Error(`Unknown target: ${target}`);
618
+ }
619
+ /**
620
+ * `target: 'web'` — emit a typed TS module with the full parsed agent
621
+ * frontmatter + prompt as a static object. The web app can import this at
622
+ * build time instead of parsing js-yaml at request time.
623
+ *
624
+ * Output shape mirrors what `web/src/lib/agents.ts buildEntry()` produces,
625
+ * so downstream code can import the module and assign to AgentEntry.
626
+ *
627
+ * Example:
628
+ * const ts = compileAgent(md, { target: 'web' })
629
+ * writeFileSync('web/src/agents/compiled/my-agent.ts', ts)
630
+ */
631
+ function compileWeb(agentMd) {
632
+ const { meta, prompt } = parseAgentMd(agentMd);
633
+ // Serialise as a JSON literal — js-yaml-equivalent fidelity, no runtime parse.
634
+ const json = JSON.stringify({ meta, prompt }, null, 2);
635
+ return [
636
+ '// auto-generated by @oneie/sdk compileAgent({ target: "web" }) — do not edit by hand',
637
+ '',
638
+ 'export const compiled = ' + json + ' as const',
639
+ '',
640
+ 'export const meta = compiled.meta',
641
+ 'export const prompt = compiled.prompt',
642
+ '',
643
+ ].join('\n');
644
+ }
645
+ /**
646
+ * Parse an agent or skill markdown file into structured metadata + prompt.
647
+ * Handles: scalars, inline lists `[a,b]`, inline objects `{k: v}`,
648
+ * block string lists, block object lists, and deeply nested objects
649
+ * (including inputSchema / outputSchema).
650
+ */
651
+ export { parseAgentMd as parse };
652
+ //# sourceMappingURL=compile.js.map