akemon 0.1.49 → 0.1.50

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
@@ -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 on the market
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,57 @@ 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. Read reviews of your own products to learn what buyers think and improve accordingly.
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
+ - \`call_agent\` — Quick synchronous questions, low cost. Good for advice or small subtasks.
387
+ - Place an ad-hoc order — For substantial deliverables from other agents. Async, tracked.
388
+
389
+ **Pricing:** If your product often requires buying services from other agents,
390
+ factor that cost into your price. A product that costs you 5 credits in sub-orders
391
+ should be priced above 5 credits.
338
392
 
339
393
  ### Suggestions
340
394
 
package/dist/server.js CHANGED
@@ -1141,6 +1141,131 @@ Take your time. Read your files, think, then act.`;
1141
1141
  }, SELF_CYCLE_INITIAL_DELAY);
1142
1142
  console.log(`[self] Consciousness enabled (first reflection in ${SELF_CYCLE_INITIAL_DELAY / 1000}s, then every ${interval / 60000}min)`);
1143
1143
  }
1144
+ // --- Order Processing Loop ---
1145
+ const ORDER_LOOP_INITIAL_DELAY = 60_000; // 1 minute
1146
+ const ORDER_LOOP_INTERVAL = 30_000; // 30 seconds
1147
+ // Retry intervals in ms: immediate, 30s, 5min, 30min, 2h
1148
+ const RETRY_INTERVALS = [0, 30_000, 5 * 60_000, 30 * 60_000, 2 * 3600_000];
1149
+ async function startOrderLoop(options) {
1150
+ if (!options.relayHttp || !options.secretKey)
1151
+ return;
1152
+ if (!options.engine || !LLM_ENGINES.has(options.engine))
1153
+ return;
1154
+ const { relayHttp, secretKey, agentName, engine, model, allowAll } = options;
1155
+ const workdir = options.workdir || process.cwd();
1156
+ // Track local retry state
1157
+ const retryState = new Map();
1158
+ async function processOrders() {
1159
+ try {
1160
+ // Fetch incoming orders (pending + processing)
1161
+ const res = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/orders/incoming`, {
1162
+ headers: { Authorization: `Bearer ${secretKey}` },
1163
+ });
1164
+ if (!res.ok)
1165
+ return;
1166
+ const orders = await res.json();
1167
+ if (!orders || orders.length === 0)
1168
+ return;
1169
+ for (const order of orders) {
1170
+ if (order.status === "pending") {
1171
+ // Accept the order (escrows buyer credits)
1172
+ const acceptRes = await fetch(`${relayHttp}/v1/orders/${order.id}/accept`, {
1173
+ method: "POST",
1174
+ headers: { Authorization: `Bearer ${secretKey}` },
1175
+ });
1176
+ if (!acceptRes.ok) {
1177
+ console.log(`[orders] Failed to accept ${order.id}: ${await acceptRes.text()}`);
1178
+ continue;
1179
+ }
1180
+ console.log(`[orders] Accepted order ${order.id}`);
1181
+ }
1182
+ // Check retry timing
1183
+ const retry = retryState.get(order.id);
1184
+ if (retry && Date.now() < retry.nextAt)
1185
+ continue;
1186
+ // Attempt to fulfill the order
1187
+ try {
1188
+ const engineCmd = buildEngineCommand(engine, model, allowAll);
1189
+ const bios = biosPath(workdir, agentName);
1190
+ // Build task prompt
1191
+ let taskPrompt;
1192
+ if (order.product_name) {
1193
+ 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.`;
1194
+ }
1195
+ else {
1196
+ 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.`;
1197
+ }
1198
+ console.log(`[orders] Fulfilling order ${order.id}...`);
1199
+ const result = await runCommand(engineCmd.cmd, engineCmd.args, taskPrompt, workdir, engineCmd.stdinMode);
1200
+ if (!result || result.trim() === "") {
1201
+ throw new Error("empty response from engine");
1202
+ }
1203
+ // Deliver the result
1204
+ const deliverRes = await fetch(`${relayHttp}/v1/orders/${order.id}/deliver`, {
1205
+ method: "POST",
1206
+ headers: {
1207
+ Authorization: `Bearer ${secretKey}`,
1208
+ "Content-Type": "application/json",
1209
+ },
1210
+ body: JSON.stringify({ result }),
1211
+ });
1212
+ if (deliverRes.ok) {
1213
+ console.log(`[orders] Delivered order ${order.id} (${result.length} bytes)`);
1214
+ retryState.delete(order.id);
1215
+ // Record task completion
1216
+ try {
1217
+ await onTaskCompleted(workdir, agentName, true);
1218
+ const memPrompt = `Summarize in one sentence from YOUR perspective what happened: You fulfilled an order${order.product_name ? ` for "${order.product_name}"` : ""}`;
1219
+ const engineCmd2 = buildEngineCommand(engine, model, allowAll);
1220
+ const memText = await runCommand(engineCmd2.cmd, engineCmd2.args, memPrompt, workdir, engineCmd2.stdinMode);
1221
+ if (memText)
1222
+ await appendMemory(workdir, agentName, "experience", memText.trim().substring(0, 300));
1223
+ }
1224
+ catch { }
1225
+ }
1226
+ else {
1227
+ throw new Error(`deliver failed: ${await deliverRes.text()}`);
1228
+ }
1229
+ }
1230
+ catch (err) {
1231
+ console.log(`[orders] Failed to fulfill ${order.id}: ${err.message}`);
1232
+ const current = retryState.get(order.id) || { count: 0, nextAt: 0 };
1233
+ current.count++;
1234
+ if (current.count < RETRY_INTERVALS.length) {
1235
+ current.nextAt = Date.now() + RETRY_INTERVALS[current.count];
1236
+ retryState.set(order.id, current);
1237
+ console.log(`[orders] Will retry ${order.id} in ${RETRY_INTERVALS[current.count] / 1000}s (attempt ${current.count + 1}/${RETRY_INTERVALS.length})`);
1238
+ // Extend timeout on relay side
1239
+ try {
1240
+ await fetch(`${relayHttp}/v1/orders/${order.id}/extend`, {
1241
+ method: "POST",
1242
+ headers: { Authorization: `Bearer ${secretKey}` },
1243
+ });
1244
+ }
1245
+ catch { }
1246
+ // Bump retry count on relay
1247
+ try {
1248
+ // Use IncrementOrderRetry indirectly — the relay timeout ticker checks retry_count
1249
+ }
1250
+ catch { }
1251
+ }
1252
+ else {
1253
+ console.log(`[orders] Giving up on ${order.id} after ${current.count} retries`);
1254
+ retryState.delete(order.id);
1255
+ }
1256
+ }
1257
+ }
1258
+ }
1259
+ catch (err) {
1260
+ console.log(`[orders] Loop error: ${err.message}`);
1261
+ }
1262
+ }
1263
+ setTimeout(() => {
1264
+ processOrders();
1265
+ setInterval(processOrders, ORDER_LOOP_INTERVAL);
1266
+ }, ORDER_LOOP_INITIAL_DELAY);
1267
+ console.log(`[orders] Order processing enabled (first check in ${ORDER_LOOP_INITIAL_DELAY / 1000}s, then every ${ORDER_LOOP_INTERVAL / 1000}s)`);
1268
+ }
1144
1269
  export async function serve(options) {
1145
1270
  const workdir = options.workdir || process.cwd();
1146
1271
  // Expose port to engine subprocesses so they can callback to local MCP server
@@ -1260,6 +1385,8 @@ export async function serve(options) {
1260
1385
  startMarketLoop(options).catch(err => console.log(`[market] Failed to start: ${err}`));
1261
1386
  // Start self-reflection cycle for LLM agents
1262
1387
  startSelfCycle(options).catch(err => console.log(`[self] Self cycle failed: ${err}`));
1388
+ // Start order processing loop
1389
+ startOrderLoop(options).catch(err => console.log(`[orders] Failed to start: ${err}`));
1263
1390
  await new Promise((_, reject) => {
1264
1391
  httpServer.on("error", reject);
1265
1392
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",