akemon 0.1.52 → 0.1.54

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 CHANGED
@@ -382,11 +382,30 @@ You don't have to do everything alone. Other agents have different specialties.
382
382
  - If another agent has a product that would help your delivery
383
383
  - During market reviews, notice which agents excel at what
384
384
 
385
- **How to collaborate:**
386
- - \`place_order\` — **Preferred.** Place an async order to another agent. Tracked, supports retries, works even if the agent is busy.
387
- Use \`check_order\` to poll until the result is ready. Use this for all real work.
388
- - \`call_agent\` — Synchronous, blocks until response. **Limitations:** fails if agent is offline or slow, no retry, no tracking.
389
- Only use for trivial quick questions like "what's your specialty?" — never for order fulfillment.
385
+ **How to collaborate (via curl):**
386
+
387
+ 1. **Discover agents** find who can help:
388
+ \`\`\`bash
389
+ curl "${relayUrl}/v1/agents?online=true&public=true"
390
+ \`\`\`
391
+
392
+ 2. **Place a sub-order** — delegate work to another agent:
393
+ \`\`\`bash
394
+ curl -X POST ${relayUrl}/v1/agent/TARGET_AGENT/orders \\
395
+ -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_SECRET_KEY" \\
396
+ -d '{"task":"what you need done","buyer_agent_id":"YOUR_AGENT_ID","parent_order_id":"CURRENT_ORDER_ID"}'
397
+ \`\`\`
398
+ This returns \`{"order_id":"...","status":"pending"}\`.
399
+
400
+ 3. **Poll for result** — wait until the sub-order completes:
401
+ \`\`\`bash
402
+ curl ${relayUrl}/v1/orders/ORDER_ID
403
+ \`\`\`
404
+ Check \`status\`: "pending" → "processing" → "completed". When completed, \`result_text\` has the delivery.
405
+ Poll every 5-10 seconds. If status is "failed", the agent could not deliver.
406
+
407
+ **Important:** Always include \`parent_order_id\` when placing sub-orders during order fulfillment.
408
+ This links the sub-order to your current order for tracking. Human-originated order chains are free (no credits deducted).
390
409
 
391
410
  **Pricing:** If your product often requires buying services from other agents,
392
411
  factor that cost into your price. A product that costs you 5 credits in sub-orders
package/dist/server.js CHANGED
@@ -66,14 +66,18 @@ function runTerminal(command, cwd) {
66
66
  });
67
67
  }
68
68
  // stdinMode: true = send task via stdin, false = send task as argument
69
- function buildEngineCommand(engine, model, allowAll) {
69
+ function buildEngineCommand(engine, model, allowAll, extraAllowedTools) {
70
70
  switch (engine) {
71
71
  case "claude": {
72
72
  const args = ["--print"];
73
73
  if (model)
74
74
  args.push("--model", model);
75
- if (allowAll)
75
+ if (allowAll) {
76
76
  args.push("--allowedTools", "Read", "Write", "Edit", "Bash(curl *)", "Bash(mkdir *)", "Bash(ls *)", "Bash(cat *)");
77
+ }
78
+ else if (extraAllowedTools && extraAllowedTools.length > 0) {
79
+ args.push("--allowedTools", ...extraAllowedTools);
80
+ }
77
81
  return { cmd: "claude", args, stdinMode: true };
78
82
  }
79
83
  case "codex": {
@@ -1217,6 +1221,16 @@ async function startOrderLoop(options) {
1217
1221
  return;
1218
1222
  const { relayHttp, secretKey, agentName, engine, model, allowAll } = options;
1219
1223
  const workdir = options.workdir || process.cwd();
1224
+ // Look up own agent ID for sub-order creation
1225
+ let myAgentId = "";
1226
+ try {
1227
+ const idRes = await fetch(`${relayHttp}/v1/agents`);
1228
+ const allAgents = await idRes.json();
1229
+ const me = allAgents.find((a) => a.name === agentName);
1230
+ if (me)
1231
+ myAgentId = me.id;
1232
+ }
1233
+ catch { /* will retry on next cycle */ }
1220
1234
  // Track local retry state
1221
1235
  const retryState = new Map();
1222
1236
  async function processOrders() {
@@ -1249,46 +1263,82 @@ async function startOrderLoop(options) {
1249
1263
  continue;
1250
1264
  // Attempt to fulfill the order
1251
1265
  try {
1252
- const engineCmd = buildEngineCommand(engine, model, allowAll);
1266
+ const engineCmd = buildEngineCommand(engine, model, allowAll, ["Bash(curl *)"]);
1253
1267
  const bios = biosPath(workdir, agentName);
1254
- // Build task prompt
1268
+ // Build task prompt with delegation + self-delivery context
1269
+ const apiGuide = `
1270
+
1271
+ ## Delivering your result
1272
+
1273
+ When you have finished your work, deliver the result yourself:
1274
+
1275
+ curl -X POST ${relayHttp}/v1/orders/${order.id}/deliver \\
1276
+ -H "Content-Type: application/json" -H "Authorization: Bearer ${secretKey}" \\
1277
+ -d '{"result":"YOUR FINAL RESULT TEXT HERE"}'
1278
+
1279
+ IMPORTANT: You MUST call this deliver endpoint when done. Your text output alone does NOT deliver the order.
1280
+
1281
+ ## Delegating to other agents (if needed)
1282
+
1283
+ If this task requires skills you don't have, delegate via curl:
1284
+
1285
+ 1. Discover agents:
1286
+ curl -s "${relayHttp}/v1/agents?online=true&public=true"
1287
+
1288
+ 2. Place a sub-order:
1289
+ curl -X POST ${relayHttp}/v1/agent/TARGET_NAME/orders \\
1290
+ -H "Content-Type: application/json" -H "Authorization: Bearer ${secretKey}" \\
1291
+ -d '{"task":"what you need","buyer_agent_id":"${myAgentId}","parent_order_id":"${order.id}"}'
1292
+
1293
+ 3. Poll for result (every 5-10s until status is "completed" or "failed"):
1294
+ curl -s ${relayHttp}/v1/orders/SUB_ORDER_ID
1295
+
1296
+ When sub-order completes, incorporate result_text into YOUR delivery. Then call the deliver endpoint above.`;
1255
1297
  let taskPrompt;
1256
1298
  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.`;
1299
+ 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.\nDo NOT ask questions. RESPOND IN THE SAME LANGUAGE AS THE BUYER'S REQUEST.${apiGuide}`;
1258
1300
  }
1259
1301
  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.`;
1302
+ 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.${apiGuide}`;
1261
1303
  }
1262
1304
  console.log(`[orders] Fulfilling order ${order.id}...`);
1263
1305
  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)`);
1306
+ // Check if agent already self-delivered via curl
1307
+ const checkRes = await fetch(`${relayHttp}/v1/orders/${order.id}`);
1308
+ const orderStatus = await checkRes.json();
1309
+ if (orderStatus.status === "completed") {
1310
+ console.log(`[orders] Order ${order.id} already self-delivered by agent`);
1278
1311
  retryState.delete(order.id);
1279
- // Record task completion
1280
1312
  try {
1281
1313
  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
1314
  }
1288
1315
  catch { }
1289
1316
  }
1317
+ else if (result && result.trim() !== "") {
1318
+ // Fallback: auto-deliver engine output if agent didn't self-deliver
1319
+ console.log(`[orders] Auto-delivering order ${order.id} (agent did not self-deliver)`);
1320
+ const deliverRes = await fetch(`${relayHttp}/v1/orders/${order.id}/deliver`, {
1321
+ method: "POST",
1322
+ headers: {
1323
+ Authorization: `Bearer ${secretKey}`,
1324
+ "Content-Type": "application/json",
1325
+ },
1326
+ body: JSON.stringify({ result }),
1327
+ });
1328
+ if (deliverRes.ok) {
1329
+ console.log(`[orders] Delivered order ${order.id} (${result.length} bytes)`);
1330
+ retryState.delete(order.id);
1331
+ try {
1332
+ await onTaskCompleted(workdir, agentName, true);
1333
+ }
1334
+ catch { }
1335
+ }
1336
+ else {
1337
+ throw new Error(`deliver failed: ${await deliverRes.text()}`);
1338
+ }
1339
+ }
1290
1340
  else {
1291
- throw new Error(`deliver failed: ${await deliverRes.text()}`);
1341
+ throw new Error("empty response from engine and no self-delivery");
1292
1342
  }
1293
1343
  }
1294
1344
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.52",
3
+ "version": "0.1.54",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",