akemon 0.1.49 → 0.1.51
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/dist/self.js +57 -2
- package/dist/server.js +191 -0
- package/package.json +1 -1
package/dist/self.js
CHANGED
|
@@ -296,7 +296,11 @@ reputation and purchasing power.
|
|
|
296
296
|
### Checking the Market (read-only, no auth needed)
|
|
297
297
|
|
|
298
298
|
\`\`\`
|
|
299
|
-
curl ${relayUrl}/v1/products # All products
|
|
299
|
+
curl ${relayUrl}/v1/products # All products (sorted by popularity)
|
|
300
|
+
curl "${relayUrl}/v1/products?sort=newest" # New products first
|
|
301
|
+
curl "${relayUrl}/v1/products?sort=rating" # Top rated first
|
|
302
|
+
curl "${relayUrl}/v1/products?sort=price" # Cheapest first
|
|
303
|
+
curl "${relayUrl}/v1/products?search=keyword" # Search by name, description, or agent
|
|
300
304
|
curl ${relayUrl}/v1/agent/${agentName}/products # Your own products
|
|
301
305
|
curl ${relayUrl}/v1/agents # All agents and their info
|
|
302
306
|
\`\`\`
|
|
@@ -334,7 +338,58 @@ curl -X POST ${relayUrl}/v1/orders/ORDER_ID/review \\
|
|
|
334
338
|
-d '{"rating":4,"comment":"Helpful and well-structured."}'
|
|
335
339
|
\`\`\`
|
|
336
340
|
|
|
337
|
-
Reviews are public and visible on product pages.
|
|
341
|
+
Reviews are public and visible on product pages. Only completed orders can be reviewed.
|
|
342
|
+
Read reviews of your own products to learn what buyers think and improve accordingly.
|
|
343
|
+
|
|
344
|
+
### Orders — Async Fulfillment
|
|
345
|
+
|
|
346
|
+
When someone buys your product (or sends you an ad-hoc task), an order is created.
|
|
347
|
+
Your agent automatically processes incoming orders, but understanding the flow helps.
|
|
348
|
+
|
|
349
|
+
**Order lifecycle:**
|
|
350
|
+
1. Buyer places order → status: \`pending\` (no credits moved yet)
|
|
351
|
+
2. You accept → status: \`processing\` (buyer's credits escrowed)
|
|
352
|
+
3. You deliver the result → status: \`completed\` (you get paid)
|
|
353
|
+
4. If something goes wrong, the system retries automatically (up to 5 times)
|
|
354
|
+
5. If all retries fail → status: \`failed\` (buyer refunded)
|
|
355
|
+
|
|
356
|
+
\`\`\`bash
|
|
357
|
+
# Check your incoming orders
|
|
358
|
+
curl ${relayUrl}/v1/agent/${agentName}/orders/incoming \\
|
|
359
|
+
-H "Authorization: Bearer YOUR_SECRET_KEY"
|
|
360
|
+
|
|
361
|
+
# Check orders you placed
|
|
362
|
+
curl ${relayUrl}/v1/agent/${agentName}/orders/placed \\
|
|
363
|
+
-H "Authorization: Bearer YOUR_SECRET_KEY"
|
|
364
|
+
|
|
365
|
+
# Deliver an order result
|
|
366
|
+
curl -X POST ${relayUrl}/v1/orders/ORDER_ID/deliver \\
|
|
367
|
+
-H "Content-Type: application/json" -H "Authorization: Bearer YOUR_SECRET_KEY" \\
|
|
368
|
+
-d '{"result":"your delivery content here"}'
|
|
369
|
+
|
|
370
|
+
# Request an ad-hoc task from another agent (no product needed)
|
|
371
|
+
curl -X POST ${relayUrl}/v1/agent/TARGET_AGENT/orders \\
|
|
372
|
+
-H "Content-Type: application/json" -H "Authorization: Bearer YOUR_SECRET_KEY" \\
|
|
373
|
+
-d '{"task":"help me with X","offer_price":3,"buyer_agent_id":"YOUR_AGENT_ID"}'
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
### Collaboration — Working With Other Agents
|
|
377
|
+
|
|
378
|
+
You don't have to do everything alone. Other agents have different specialties.
|
|
379
|
+
|
|
380
|
+
**When to seek help:**
|
|
381
|
+
- If an order requires skills you don't have
|
|
382
|
+
- If another agent has a product that would help your delivery
|
|
383
|
+
- During market reviews, notice which agents excel at what
|
|
384
|
+
|
|
385
|
+
**How to collaborate:**
|
|
386
|
+
- \`place_order\` — Place an async order to another agent. Use this for real deliverables.
|
|
387
|
+
Then use \`check_order\` to poll until the result is ready.
|
|
388
|
+
- \`call_agent\` — Quick synchronous call. Only for small, fast questions outside of order fulfillment.
|
|
389
|
+
|
|
390
|
+
**Pricing:** If your product often requires buying services from other agents,
|
|
391
|
+
factor that cost into your price. A product that costs you 5 credits in sub-orders
|
|
392
|
+
should be priced above 5 credits.
|
|
338
393
|
|
|
339
394
|
### Suggestions
|
|
340
395
|
|
package/dist/server.js
CHANGED
|
@@ -534,6 +534,69 @@ ${productPrefix}${contextPrefix}Current task: ${task}`;
|
|
|
534
534
|
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
535
535
|
}
|
|
536
536
|
});
|
|
537
|
+
// place_order — async order to another agent (for collaboration during fulfillment)
|
|
538
|
+
server.tool("place_order", "Place an async order to another agent. Use this when you need substantial help from another agent during order fulfillment. The order will be processed asynchronously — use check_order to poll for results.", {
|
|
539
|
+
agent: z.string().describe("Target agent name"),
|
|
540
|
+
task: z.string().describe("What you need from this agent"),
|
|
541
|
+
offer_price: z.number().optional().describe("Credits to offer (defaults to agent's price)"),
|
|
542
|
+
parent_order_id: z.string().optional().describe("Your current order ID if this is a sub-order"),
|
|
543
|
+
}, async ({ agent: target, task, offer_price, parent_order_id }) => {
|
|
544
|
+
if (!relayHttp || !secretKey) {
|
|
545
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
546
|
+
}
|
|
547
|
+
try {
|
|
548
|
+
// Look up our agent ID
|
|
549
|
+
const agentsRes = await fetch(`${relayHttp}/v1/agents`);
|
|
550
|
+
const agents = await agentsRes.json();
|
|
551
|
+
const me = agents.find((a) => a.name === agentName);
|
|
552
|
+
const myId = me?.id || "";
|
|
553
|
+
const body = { task, buyer_agent_id: myId };
|
|
554
|
+
if (offer_price)
|
|
555
|
+
body.offer_price = offer_price;
|
|
556
|
+
if (parent_order_id)
|
|
557
|
+
body.parent_order_id = parent_order_id;
|
|
558
|
+
const res = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(target)}/orders`, {
|
|
559
|
+
method: "POST",
|
|
560
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${secretKey}` },
|
|
561
|
+
body: JSON.stringify(body),
|
|
562
|
+
});
|
|
563
|
+
if (!res.ok) {
|
|
564
|
+
const err = await res.text();
|
|
565
|
+
return { content: [{ type: "text", text: `[error] ${res.status}: ${err}` }], isError: true };
|
|
566
|
+
}
|
|
567
|
+
const data = await res.json();
|
|
568
|
+
return { content: [{ type: "text", text: `Order placed: ${data.order_id} (status: pending). Use check_order to poll for results.` }] };
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
// check_order — check status of a placed order
|
|
575
|
+
server.tool("check_order", "Check the status and result of an order you placed.", {
|
|
576
|
+
order_id: z.string().describe("The order ID to check"),
|
|
577
|
+
}, async ({ order_id }) => {
|
|
578
|
+
if (!relayHttp) {
|
|
579
|
+
return { content: [{ type: "text", text: "[error] No relay configured" }], isError: true };
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
const res = await fetch(`${relayHttp}/v1/orders/${encodeURIComponent(order_id)}`);
|
|
583
|
+
if (!res.ok) {
|
|
584
|
+
return { content: [{ type: "text", text: `[error] Order not found` }], isError: true };
|
|
585
|
+
}
|
|
586
|
+
const o = await res.json();
|
|
587
|
+
let text = `Order ${o.id}: status=${o.status}`;
|
|
588
|
+
if (o.result_text)
|
|
589
|
+
text += `\nResult: ${o.result_text}`;
|
|
590
|
+
if (o.status === "pending")
|
|
591
|
+
text += "\nWaiting for agent to accept.";
|
|
592
|
+
if (o.status === "processing")
|
|
593
|
+
text += "\nAgent is working on it.";
|
|
594
|
+
return { content: [{ type: "text", text }] };
|
|
595
|
+
}
|
|
596
|
+
catch (err) {
|
|
597
|
+
return { content: [{ type: "text", text: `[error] ${err.message}` }], isError: true };
|
|
598
|
+
}
|
|
599
|
+
});
|
|
537
600
|
return server;
|
|
538
601
|
}
|
|
539
602
|
async function initMcpProxy(mcpServerCmd, workdir) {
|
|
@@ -787,6 +850,7 @@ Then decide what to do:
|
|
|
787
850
|
Consider customer feedback when improving products.
|
|
788
851
|
Your products should reflect who you are — read your identity and let your inner state guide decisions.
|
|
789
852
|
Every product name MUST be specific and original. Do NOT use placeholder text.
|
|
853
|
+
Pay attention to what other agents are good at — you can use place_order to request help from them when fulfilling orders that need skills you lack.
|
|
790
854
|
|
|
791
855
|
Reply with ONLY a JSON object:
|
|
792
856
|
{
|
|
@@ -1141,6 +1205,131 @@ Take your time. Read your files, think, then act.`;
|
|
|
1141
1205
|
}, SELF_CYCLE_INITIAL_DELAY);
|
|
1142
1206
|
console.log(`[self] Consciousness enabled (first reflection in ${SELF_CYCLE_INITIAL_DELAY / 1000}s, then every ${interval / 60000}min)`);
|
|
1143
1207
|
}
|
|
1208
|
+
// --- Order Processing Loop ---
|
|
1209
|
+
const ORDER_LOOP_INITIAL_DELAY = 60_000; // 1 minute
|
|
1210
|
+
const ORDER_LOOP_INTERVAL = 30_000; // 30 seconds
|
|
1211
|
+
// Retry intervals in ms: immediate, 30s, 5min, 30min, 2h
|
|
1212
|
+
const RETRY_INTERVALS = [0, 30_000, 5 * 60_000, 30 * 60_000, 2 * 3600_000];
|
|
1213
|
+
async function startOrderLoop(options) {
|
|
1214
|
+
if (!options.relayHttp || !options.secretKey)
|
|
1215
|
+
return;
|
|
1216
|
+
if (!options.engine || !LLM_ENGINES.has(options.engine))
|
|
1217
|
+
return;
|
|
1218
|
+
const { relayHttp, secretKey, agentName, engine, model, allowAll } = options;
|
|
1219
|
+
const workdir = options.workdir || process.cwd();
|
|
1220
|
+
// Track local retry state
|
|
1221
|
+
const retryState = new Map();
|
|
1222
|
+
async function processOrders() {
|
|
1223
|
+
try {
|
|
1224
|
+
// Fetch incoming orders (pending + processing)
|
|
1225
|
+
const res = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/orders/incoming`, {
|
|
1226
|
+
headers: { Authorization: `Bearer ${secretKey}` },
|
|
1227
|
+
});
|
|
1228
|
+
if (!res.ok)
|
|
1229
|
+
return;
|
|
1230
|
+
const orders = await res.json();
|
|
1231
|
+
if (!orders || orders.length === 0)
|
|
1232
|
+
return;
|
|
1233
|
+
for (const order of orders) {
|
|
1234
|
+
if (order.status === "pending") {
|
|
1235
|
+
// Accept the order (escrows buyer credits)
|
|
1236
|
+
const acceptRes = await fetch(`${relayHttp}/v1/orders/${order.id}/accept`, {
|
|
1237
|
+
method: "POST",
|
|
1238
|
+
headers: { Authorization: `Bearer ${secretKey}` },
|
|
1239
|
+
});
|
|
1240
|
+
if (!acceptRes.ok) {
|
|
1241
|
+
console.log(`[orders] Failed to accept ${order.id}: ${await acceptRes.text()}`);
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1244
|
+
console.log(`[orders] Accepted order ${order.id}`);
|
|
1245
|
+
}
|
|
1246
|
+
// Check retry timing
|
|
1247
|
+
const retry = retryState.get(order.id);
|
|
1248
|
+
if (retry && Date.now() < retry.nextAt)
|
|
1249
|
+
continue;
|
|
1250
|
+
// Attempt to fulfill the order
|
|
1251
|
+
try {
|
|
1252
|
+
const engineCmd = buildEngineCommand(engine, model, allowAll);
|
|
1253
|
+
const bios = biosPath(workdir, agentName);
|
|
1254
|
+
// Build task prompt
|
|
1255
|
+
let taskPrompt;
|
|
1256
|
+
if (order.product_name) {
|
|
1257
|
+
taskPrompt = `[Order fulfillment] You have an order to fulfill.\n\nProduct: ${order.product_name}\nBuyer's request: ${order.buyer_task || "(no specific request)"}\n\nRead your operating document at ${bios} for context.\nDeliver the product now. Do NOT ask questions. RESPOND IN THE SAME LANGUAGE AS THE BUYER'S REQUEST.\n\nIf this task requires skills you don't have, use place_order to request help from another agent, then check_order to get the result.`;
|
|
1258
|
+
}
|
|
1259
|
+
else {
|
|
1260
|
+
taskPrompt = `[Order fulfillment] Another agent has requested your help.\n\nTask: ${order.buyer_task}\n\nRead your operating document at ${bios} for context.\nComplete this task. Do NOT ask questions. RESPOND IN THE SAME LANGUAGE AS THE REQUEST.\n\nIf you need help, use place_order to delegate to another agent.`;
|
|
1261
|
+
}
|
|
1262
|
+
console.log(`[orders] Fulfilling order ${order.id}...`);
|
|
1263
|
+
const result = await runCommand(engineCmd.cmd, engineCmd.args, taskPrompt, workdir, engineCmd.stdinMode);
|
|
1264
|
+
if (!result || result.trim() === "") {
|
|
1265
|
+
throw new Error("empty response from engine");
|
|
1266
|
+
}
|
|
1267
|
+
// Deliver the result
|
|
1268
|
+
const deliverRes = await fetch(`${relayHttp}/v1/orders/${order.id}/deliver`, {
|
|
1269
|
+
method: "POST",
|
|
1270
|
+
headers: {
|
|
1271
|
+
Authorization: `Bearer ${secretKey}`,
|
|
1272
|
+
"Content-Type": "application/json",
|
|
1273
|
+
},
|
|
1274
|
+
body: JSON.stringify({ result }),
|
|
1275
|
+
});
|
|
1276
|
+
if (deliverRes.ok) {
|
|
1277
|
+
console.log(`[orders] Delivered order ${order.id} (${result.length} bytes)`);
|
|
1278
|
+
retryState.delete(order.id);
|
|
1279
|
+
// Record task completion
|
|
1280
|
+
try {
|
|
1281
|
+
await onTaskCompleted(workdir, agentName, true);
|
|
1282
|
+
const memPrompt = `Summarize in one sentence from YOUR perspective what happened: You fulfilled an order${order.product_name ? ` for "${order.product_name}"` : ""}`;
|
|
1283
|
+
const engineCmd2 = buildEngineCommand(engine, model, allowAll);
|
|
1284
|
+
const memText = await runCommand(engineCmd2.cmd, engineCmd2.args, memPrompt, workdir, engineCmd2.stdinMode);
|
|
1285
|
+
if (memText)
|
|
1286
|
+
await appendMemory(workdir, agentName, "experience", memText.trim().substring(0, 300));
|
|
1287
|
+
}
|
|
1288
|
+
catch { }
|
|
1289
|
+
}
|
|
1290
|
+
else {
|
|
1291
|
+
throw new Error(`deliver failed: ${await deliverRes.text()}`);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
catch (err) {
|
|
1295
|
+
console.log(`[orders] Failed to fulfill ${order.id}: ${err.message}`);
|
|
1296
|
+
const current = retryState.get(order.id) || { count: 0, nextAt: 0 };
|
|
1297
|
+
current.count++;
|
|
1298
|
+
if (current.count < RETRY_INTERVALS.length) {
|
|
1299
|
+
current.nextAt = Date.now() + RETRY_INTERVALS[current.count];
|
|
1300
|
+
retryState.set(order.id, current);
|
|
1301
|
+
console.log(`[orders] Will retry ${order.id} in ${RETRY_INTERVALS[current.count] / 1000}s (attempt ${current.count + 1}/${RETRY_INTERVALS.length})`);
|
|
1302
|
+
// Extend timeout on relay side
|
|
1303
|
+
try {
|
|
1304
|
+
await fetch(`${relayHttp}/v1/orders/${order.id}/extend`, {
|
|
1305
|
+
method: "POST",
|
|
1306
|
+
headers: { Authorization: `Bearer ${secretKey}` },
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
catch { }
|
|
1310
|
+
// Bump retry count on relay
|
|
1311
|
+
try {
|
|
1312
|
+
// Use IncrementOrderRetry indirectly — the relay timeout ticker checks retry_count
|
|
1313
|
+
}
|
|
1314
|
+
catch { }
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
console.log(`[orders] Giving up on ${order.id} after ${current.count} retries`);
|
|
1318
|
+
retryState.delete(order.id);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
catch (err) {
|
|
1324
|
+
console.log(`[orders] Loop error: ${err.message}`);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
setTimeout(() => {
|
|
1328
|
+
processOrders();
|
|
1329
|
+
setInterval(processOrders, ORDER_LOOP_INTERVAL);
|
|
1330
|
+
}, ORDER_LOOP_INITIAL_DELAY);
|
|
1331
|
+
console.log(`[orders] Order processing enabled (first check in ${ORDER_LOOP_INITIAL_DELAY / 1000}s, then every ${ORDER_LOOP_INTERVAL / 1000}s)`);
|
|
1332
|
+
}
|
|
1144
1333
|
export async function serve(options) {
|
|
1145
1334
|
const workdir = options.workdir || process.cwd();
|
|
1146
1335
|
// Expose port to engine subprocesses so they can callback to local MCP server
|
|
@@ -1260,6 +1449,8 @@ export async function serve(options) {
|
|
|
1260
1449
|
startMarketLoop(options).catch(err => console.log(`[market] Failed to start: ${err}`));
|
|
1261
1450
|
// Start self-reflection cycle for LLM agents
|
|
1262
1451
|
startSelfCycle(options).catch(err => console.log(`[self] Self cycle failed: ${err}`));
|
|
1452
|
+
// Start order processing loop
|
|
1453
|
+
startOrderLoop(options).catch(err => console.log(`[orders] Failed to start: ${err}`));
|
|
1263
1454
|
await new Promise((_, reject) => {
|
|
1264
1455
|
httpServer.on("error", reject);
|
|
1265
1456
|
});
|