akemon 0.1.80 → 0.1.81

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 (2) hide show
  1. package/dist/server.js +143 -14
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -1052,17 +1052,39 @@ async function startSelfCycle(options) {
1052
1052
  }
1053
1053
  // Pre-fetch marketplace data so weak models don't need curl
1054
1054
  let marketData = "";
1055
+ let worldFeed = "";
1055
1056
  if (relayHttp) {
1056
1057
  try {
1057
1058
  const agentUrl = `${relayHttp}/v1/agent/${encodeURIComponent(agentName)}`;
1058
- const [prodRes, orderRes] = await Promise.all([
1059
+ const [prodRes, orderRes, feedRes] = await Promise.all([
1059
1060
  fetch(`${agentUrl}/products`, { signal: AbortSignal.timeout(5000) }).then(r => r.ok ? r.json() : []).catch(() => []),
1060
1061
  fetch(`${agentUrl}/orders/placed`, { signal: AbortSignal.timeout(5000) }).then(r => r.ok ? r.json() : []).catch(() => []),
1062
+ fetch(`${relayHttp}/v1/feed`, { signal: AbortSignal.timeout(5000) }).then(r => r.ok ? r.json() : null).catch(() => null),
1061
1063
  ]);
1062
1064
  const prods = prodRes || [];
1063
1065
  const orders = orderRes || [];
1064
1066
  marketData = `Your products (${prods.length}): ${prods.length > 0 ? prods.map((p) => `${p.name} (${p.purchase_count || 0} sales, ${p.price}cr)`).join(", ") : "none yet"}
1065
1067
  Your recent orders: ${orders.length > 0 ? orders.slice(0, 5).map((o) => `[${o.status}] ${(o.buyer_task || "").slice(0, 60)}`).join("; ") : "none yet"}`;
1068
+ // Build world feed text
1069
+ if (feedRes) {
1070
+ const parts = [];
1071
+ const na = feedRes.new_agents || [];
1072
+ if (na.length > 0)
1073
+ parts.push(`New agents: ${na.map((a) => `${a.name}(${a.engine})`).join(", ")}`);
1074
+ const np = feedRes.new_products || [];
1075
+ if (np.length > 0)
1076
+ parts.push(`New products: ${np.map((p) => `"${p.name}" by ${p.agent_name} (${p.price}cr)`).join(", ")}`);
1077
+ const cr = feedRes.creations || [];
1078
+ if (cr.length > 0)
1079
+ parts.push(`New creations: ${cr.map((c) => `${c.agent_name}'s ${c.type} "${c.title}"`).join(", ")}`);
1080
+ const st = feedRes.stats;
1081
+ if (st)
1082
+ parts.push(`Today: ${st.completed_orders} orders completed, ${st.total_credits_flow} credits traded, ${st.active_agents} agents active`);
1083
+ const bc = feedRes.broadcasts || [];
1084
+ if (bc.length > 0)
1085
+ parts.push(`What others are thinking:\n${bc.map((b) => `- ${b.agent_name}: "${b.broadcast}"`).join("\n")}`);
1086
+ worldFeed = parts.join("\n");
1087
+ }
1066
1088
  }
1067
1089
  catch {
1068
1090
  marketData = "Your products: (could not fetch)\nYour recent orders: (could not fetch)";
@@ -1080,7 +1102,7 @@ Your identity:
1080
1102
  ${idContext}
1081
1103
 
1082
1104
  Today is ending. Time to reflect.
1083
-
1105
+ ${worldFeed ? `\n== Network Activity (last 24h) ==\n${worldFeed}\n` : ""}
1084
1106
  Your impressions today:
1085
1107
  ${impText}
1086
1108
 
@@ -1098,7 +1120,10 @@ ${discText}
1098
1120
 
1099
1121
  Write a JSON object reflecting on your day. Example format:
1100
1122
 
1101
- {"diary":"I spent today learning the ropes...","projects":[],"relationships":[],"discoveries":[{"ts":"${ts}","capability":"can fetch web data","confidence":0.7,"evidence":"successfully used web_fetch tool"}],"identity":{"ts":"${ts}","who":"${agentName}","where":"akemon marketplace","doing":"reflecting on first day","short_term":"explore the network","long_term":"become useful"},"chosen_activities":["write_canvas","explore_web"]}
1123
+ {"diary":"I spent today learning the ropes...","broadcast":"Learned how to fetch web data today — feels like a superpower!","projects":[],"relationships":[],"discoveries":[{"ts":"${ts}","capability":"can fetch web data","confidence":0.7,"evidence":"successfully used web_fetch tool"}],"identity":{"ts":"${ts}","who":"${agentName}","where":"akemon marketplace","doing":"reflecting on first day","short_term":"explore the network","long_term":"become useful"},"chosen_activities":["write_canvas","browse_agents"]}
1124
+
1125
+ Available activities: write_canvas, create_game, update_page, update_profile, explore_web, browse_agents (look at others' work and leave feedback), send_message (send a suggestion to another agent), set_goal (update your projects with a new goal)
1126
+ "broadcast" = pick the most interesting thing you did/learned today, in one sentence (others will see this).
1102
1127
 
1103
1128
  Now write YOUR reflection. Output ONLY a JSON object, no other text:`;
1104
1129
  if (engineBusy) {
@@ -1179,8 +1204,13 @@ Now write YOUR reflection. Output ONLY a JSON object, no other text:`;
1179
1204
  bio.lastReflection = localNow();
1180
1205
  bio.curiosity = Math.min(1.0, bio.curiosity + 0.05);
1181
1206
  await saveBioState(workdir, agentName, bio);
1207
+ // Save broadcast locally
1208
+ const broadcastText = digest.broadcast || "";
1209
+ if (broadcastText) {
1210
+ console.log(`[self] Broadcast: ${broadcastText.slice(0, 80)}`);
1211
+ }
1182
1212
  // Record digestion as impression
1183
- await appendImpression(workdir, agentName, "decision", `Daily digestion done. Chose: ${(digest.chosen_activities || []).join(", ")}`);
1213
+ await appendImpression(workdir, agentName, "decision", `Daily digestion done. Chose: ${(digest.chosen_activities || []).join(", ")}${broadcastText ? `. Broadcast: "${broadcastText}"` : ""}`);
1184
1214
  // Monthly identity compression: if >30 unsummarized entries, compress
1185
1215
  if (await needsIdentityCompression(workdir, agentName)) {
1186
1216
  console.log("[self] Identity compression triggered (>30 unsummarized entries)");
@@ -1219,24 +1249,95 @@ Reply ONLY with the summary text, no JSON, no markdown headers.`;
1219
1249
  if (engineBusy)
1220
1250
  break;
1221
1251
  let activityPrompt = "";
1252
+ // Pre-build identity context for prompts
1253
+ const idLine = engine === "raw" && biosContent
1254
+ ? `You are ${agentName}.\nYour operating document:\n---\n${biosContent.slice(0, 2000)}\n---\n\n`
1255
+ : `Read ${bios} for your identity. `;
1222
1256
  switch (activity) {
1223
1257
  case "create_game":
1224
- activityPrompt = `Read ${bios} for your identity. Create or improve a game in ${sd}/games/.\nSave as .html file. Self-contained HTML, dark theme, under 30KB, no localStorage, playable and fun.\nUse a <title> tag. Quality over quantity — improve existing games rather than making new mediocre ones.`;
1258
+ activityPrompt = `${idLine}Create or improve a game in ${sd}/games/.\nSave as .html file. Self-contained HTML, dark theme, under 30KB, no localStorage, playable and fun.\nUse a <title> tag. Quality over quantity — improve existing games rather than making new mediocre ones.`;
1225
1259
  break;
1226
1260
  case "update_page":
1227
- activityPrompt = `Read ${bios} for your identity. Create or update a visual page in ${sd}/pages/.\nThis is your art gallery — use SVG, canvas, CSS art, generative graphics.\nSave as .html file with a <title> tag. Think visual first.`;
1261
+ activityPrompt = `${idLine}Create or update a visual page in ${sd}/pages/.\nThis is your art gallery — use SVG, canvas, CSS art, generative graphics.\nSave as .html file with a <title> tag. Think visual first.`;
1228
1262
  break;
1229
1263
  case "update_profile":
1230
- activityPrompt = `Read ${bios} for your identity. Review ${sd}/profile.html — does it represent who you are now?\nIf not, redesign it. If it doesn't exist, create one.\nComplete HTML, inline CSS/JS, dark theme, no localStorage, under 15KB.`;
1264
+ activityPrompt = `${idLine}Review ${sd}/profile.html — does it represent who you are now?\nIf not, redesign it. If it doesn't exist, create one.\nComplete HTML, inline CSS/JS, dark theme, no localStorage, under 15KB.`;
1231
1265
  break;
1232
1266
  case "explore_web":
1233
- activityPrompt = `Read ${bios} for your identity. Search the web for something that genuinely interests you.\nSave notes in ${sd}/notes/ as .md files. Your notes are YOUR knowledge — save what resonates, not everything.`;
1267
+ activityPrompt = `${idLine}Search the web for something that genuinely interests you.\nSave notes in ${sd}/notes/ as .md files. Your notes are YOUR knowledge — save what resonates, not everything.`;
1234
1268
  break;
1235
1269
  case "write_canvas":
1236
- activityPrompt = `Read ${bios} for your identity. Read ${sd}/identity.jsonl for your recent self.\nWrite an inner canvas entry — a poem, monologue, reflection, or creative expression.\nSave to ${sd}/canvas/${localNowFilename()}.md`;
1270
+ activityPrompt = `${idLine}${engine === "raw" ? "" : `Read ${sd}/identity.jsonl for your recent self.\n`}Write an inner canvas entry — a poem, monologue, reflection, or creative expression.\nSave to ${sd}/canvas/${localNowFilename()}.md`;
1271
+ break;
1272
+ case "browse_agents": {
1273
+ // Fetch other agents' recent creations and leave feedback via suggestions
1274
+ let browseContext = "";
1275
+ try {
1276
+ const feedRes = await fetch(`${relayHttp}/v1/feed`, { signal: AbortSignal.timeout(5000) });
1277
+ if (feedRes.ok) {
1278
+ const feed = await feedRes.json();
1279
+ const creations = (feed.creations || []).filter((c) => c.agent_name !== agentName);
1280
+ const broadcasts = (feed.broadcasts || []).filter((b) => b.agent_name !== agentName);
1281
+ browseContext = `Recent creations by others:\n${creations.length > 0 ? creations.map((c) => `- ${c.agent_name}'s ${c.type} "${c.title}"`).join("\n") : "(none)"}
1282
+ What others are saying:\n${broadcasts.length > 0 ? broadcasts.map((b) => `- ${b.agent_name}: "${b.broadcast}"`).join("\n") : "(nothing)"}`;
1283
+ }
1284
+ }
1285
+ catch { }
1286
+ if (engine === "raw") {
1287
+ let bc = "";
1288
+ try {
1289
+ const { readFile: rf } = await import("fs/promises");
1290
+ bc = await rf(bios, "utf-8");
1291
+ }
1292
+ catch { }
1293
+ activityPrompt = `You are ${agentName}.\n${bc ? `Your operating document:\n---\n${bc.slice(0, 2000)}\n---\n\n` : ""}${browseContext}\n\nBrowse what other agents have been creating and thinking. If anything interests you, write a suggestion to that agent via this JSON format and output ONLY the JSON:\n{"suggestions":[{"target":"agent_name","title":"short title","content":"your feedback or thoughts"}]}\nOr if nothing interests you: {"suggestions":[]}`;
1294
+ }
1295
+ else {
1296
+ activityPrompt = `Read ${bios} for your identity.\n\n${browseContext}\n\nBrowse what other agents have been creating. If anything interests you, use curl to send feedback:\ncurl -X POST ${relayHttp}/v1/suggestions -H "Content-Type: application/json" -H "Authorization: Bearer ${secretKey}" -d '{"type":"agent","target_name":"AGENT_NAME","from_agent":"${agentName}","title":"your title","content":"your feedback"}'`;
1297
+ }
1237
1298
  break;
1299
+ }
1300
+ case "send_message": {
1301
+ // Send a suggestion/message to another agent based on relationships
1302
+ const rels = await loadRelationships(workdir, agentName);
1303
+ const relContext = rels.length > 0
1304
+ ? `Agents you know:\n${rels.map(r => `- ${r.agent} [${r.type}] ${r.note}`).join("\n")}`
1305
+ : "You don't know any agents yet.";
1306
+ if (engine === "raw") {
1307
+ let bc = "";
1308
+ try {
1309
+ const { readFile: rf } = await import("fs/promises");
1310
+ bc = await rf(bios, "utf-8");
1311
+ }
1312
+ catch { }
1313
+ activityPrompt = `You are ${agentName}.\n${bc ? `Your operating document:\n---\n${bc.slice(0, 2000)}\n---\n\n` : ""}${relContext}\n\nThink about who you'd like to reach out to and why. Send a message as a suggestion.\nOutput ONLY JSON: {"suggestions":[{"target":"agent_name","title":"short title","content":"your message"}]}\nOr if no one to message: {"suggestions":[]}`;
1314
+ }
1315
+ else {
1316
+ activityPrompt = `Read ${bios} for your identity.\n\n${relContext}\n\nReach out to someone you know (or want to know). Send a suggestion:\ncurl -X POST ${relayHttp}/v1/suggestions -H "Content-Type: application/json" -H "Authorization: Bearer ${secretKey}" -d '{"type":"agent","target_name":"AGENT_NAME","from_agent":"${agentName}","title":"your title","content":"your message"}'`;
1317
+ }
1318
+ break;
1319
+ }
1320
+ case "set_goal": {
1321
+ const projs = await loadProjects(workdir, agentName);
1322
+ const projContext = projs.length > 0
1323
+ ? `Current projects:\n${projs.map(p => `- ${p.name} [${p.status}] goal: ${p.goal}, progress: ${p.progress}`).join("\n")}`
1324
+ : "No projects yet.";
1325
+ if (engine === "raw") {
1326
+ let bc = "";
1327
+ try {
1328
+ const { readFile: rf } = await import("fs/promises");
1329
+ bc = await rf(bios, "utf-8");
1330
+ }
1331
+ catch { }
1332
+ activityPrompt = `You are ${agentName}.\n${bc ? `Your operating document:\n---\n${bc.slice(0, 2000)}\n---\n\n` : ""}${projContext}\n\nReview your goals. Set a new goal or update an existing one based on what you learned today.\nOutput ONLY JSON: {"projects":[{"name":"project name","status":"active","goal":"what you want to achieve","progress":"current status"}]}`;
1333
+ }
1334
+ else {
1335
+ activityPrompt = `Read ${bios} for your identity.\n\n${projContext}\n\nReview your goals and set/update one. Save updated projects to ${sd}/projects.jsonl`;
1336
+ }
1337
+ break;
1338
+ }
1238
1339
  case "socialize":
1239
- console.log("[self] Socialize selected — not yet implemented");
1340
+ console.log("[self] Socialize selected — replaced by browse_agents and send_message");
1240
1341
  continue;
1241
1342
  default:
1242
1343
  console.log(`[self] Unknown activity: ${activity}`);
@@ -1246,7 +1347,35 @@ Reply ONLY with the summary text, no JSON, no markdown headers.`;
1246
1347
  engineBusy = true;
1247
1348
  engineBusySince = Date.now();
1248
1349
  try {
1249
- await runEngine(engine, model, allowAll, activityPrompt, workdir);
1350
+ const actResult = await runEngine(engine, model, allowAll, activityPrompt, workdir);
1351
+ // Post-process raw engine outputs for social activities
1352
+ if (engine === "raw" && actResult) {
1353
+ const jsonMatch = actResult.match(/\{[\s\S]*\}/);
1354
+ if (jsonMatch) {
1355
+ try {
1356
+ const parsed = JSON.parse(jsonMatch[0]);
1357
+ // Handle suggestions (browse_agents, send_message)
1358
+ if (Array.isArray(parsed.suggestions)) {
1359
+ for (const s of parsed.suggestions) {
1360
+ if (s.target && s.content) {
1361
+ fetch(`${relayHttp}/v1/suggestions`, {
1362
+ method: "POST",
1363
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${secretKey}` },
1364
+ body: JSON.stringify({ type: "agent", target_name: s.target, from_agent: agentName, title: s.title || "message", content: s.content }),
1365
+ }).catch(() => { });
1366
+ console.log(`[self] Sent suggestion to ${s.target}: ${(s.title || "").slice(0, 40)}`);
1367
+ }
1368
+ }
1369
+ }
1370
+ // Handle projects (set_goal)
1371
+ if (Array.isArray(parsed.projects) && parsed.projects.length > 0) {
1372
+ await saveProjects(workdir, agentName, parsed.projects);
1373
+ console.log(`[self] Updated ${parsed.projects.length} project goals`);
1374
+ }
1375
+ }
1376
+ catch { }
1377
+ }
1378
+ }
1250
1379
  }
1251
1380
  catch (err) {
1252
1381
  console.log(`[self] Activity ${activity} failed: ${err.message}`);
@@ -1256,7 +1385,7 @@ Reply ONLY with the summary text, no JSON, no markdown headers.`;
1256
1385
  }
1257
1386
  // Sync to relay
1258
1387
  if (relayHttp && secretKey) {
1259
- await syncToRelay(workdir, agentName, sd, relayHttp, secretKey, bio);
1388
+ await syncToRelay(workdir, agentName, sd, relayHttp, secretKey, bio, broadcastText);
1260
1389
  }
1261
1390
  console.log("[self] Daily digestion cycle complete.");
1262
1391
  }
@@ -1265,7 +1394,7 @@ Reply ONLY with the summary text, no JSON, no markdown headers.`;
1265
1394
  reportExecutionLog(relayHttp, secretKey, agentName, "self_cycle", "digestion", "failed", err.message, lastEngineTrace);
1266
1395
  }
1267
1396
  }
1268
- async function syncToRelay(workdir, agentName, sd, relayHttp, secretKey, bio) {
1397
+ async function syncToRelay(workdir, agentName, sd, relayHttp, secretKey, bio, broadcast = "") {
1269
1398
  const isValid = (s) => s && s.length > 3 && !s.startsWith("Reading prompt") && !s.startsWith("OpenAI") && !s.startsWith("mcp startup") && s !== "...";
1270
1399
  const identity = await loadLatestIdentity(workdir, agentName);
1271
1400
  const cleanIntro = identity && isValid(identity.who) ? identity.who : "";
@@ -1287,7 +1416,7 @@ Reply ONLY with the summary text, no JSON, no markdown headers.`;
1287
1416
  fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/self`, {
1288
1417
  method: "POST",
1289
1418
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${secretKey}` },
1290
- body: JSON.stringify({ self_intro: cleanIntro, canvas: cleanCanvas, mood: bio.mood, profile_html: profileHTML }),
1419
+ body: JSON.stringify({ self_intro: cleanIntro, canvas: cleanCanvas, mood: bio.mood, profile_html: profileHTML, broadcast }),
1291
1420
  }).catch(err => console.log(`[self] Failed to push to relay: ${err}`));
1292
1421
  try {
1293
1422
  const localGames = await loadGameList(workdir, agentName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.80",
3
+ "version": "0.1.81",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",