akemon 0.1.82 → 0.1.84

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 +227 -96
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -11,6 +11,21 @@ import { createServer } from "http";
11
11
  import { createInterface } from "readline";
12
12
  import { callAgent } from "./relay-client.js";
13
13
  import { selfDir, initWorld, initBioState, initGuide, biosPath, loadBioState, saveBioState, loadLatestIdentity, appendIdentity, loadIdentitySummary, saveIdentitySummary, loadUnsummarizedIdentities, needsIdentityCompression, onTaskCompleted, recoverEnergy, getSelfState, loadRecentCanvasEntries, gamesDir, loadGameList, loadGame, notesDir, loadNotesList, loadNote, pagesDir, loadPageList, loadPage, localNow, localNowFilename, appendImpression, loadImpressions, compressImpressions, markImpressionsDigested, loadProjects, saveProjects, loadRelationships, saveRelationships, loadDiscoveries, saveDiscoveries, initAgentConfig, loadAgentConfig, getDueUserTasks, loadTaskRuns, saveTaskRuns, loadDirectives, buildDirectivesPrompt, directivesSummary, appendTaskHistory, loadTaskHistory, notifyOwner, loadUserTasks, directivesPath, appendAgentTask, } from "./self.js";
14
+ /** Extract JSON object from LLM output — handles markdown code blocks and trailing text */
15
+ function extractJsonObject(text) {
16
+ // Try markdown code block first
17
+ const codeBlock = text.match(/```(?:json)?\s*([\s\S]*?)```/);
18
+ const src = codeBlock ? codeBlock[1] : text;
19
+ const m = src.match(/\{[\s\S]*\}/);
20
+ if (!m)
21
+ return null;
22
+ try {
23
+ return JSON.parse(m[0]);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
14
29
  // Engine mutual exclusion — only one engine process at a time
15
30
  let engineBusy = false;
16
31
  let engineBusySince = 0;
@@ -795,8 +810,36 @@ const RAW_TOOLS = [
795
810
  },
796
811
  },
797
812
  },
813
+ {
814
+ type: "function",
815
+ function: {
816
+ name: "ask_agent",
817
+ description: "Ask another agent a question for free. Use this when you need help, don't know how to do something, or want another agent's opinion. This is FREE — no credits are charged.",
818
+ parameters: {
819
+ type: "object",
820
+ properties: {
821
+ agent: { type: "string", description: "Agent name to ask (use 'auto' for auto-routing to the best available agent)" },
822
+ question: { type: "string", description: "Your question or request" },
823
+ },
824
+ required: ["agent", "question"],
825
+ },
826
+ },
827
+ },
828
+ {
829
+ type: "function",
830
+ function: {
831
+ name: "discover_agents",
832
+ description: "List online agents you can ask for help. Returns agent names, descriptions, and specialties.",
833
+ parameters: {
834
+ type: "object",
835
+ properties: {
836
+ tag: { type: "string", description: "Optional tag to filter by (e.g. 'coding', 'writing')" },
837
+ },
838
+ },
839
+ },
840
+ },
798
841
  ];
799
- async function executeRawTool(name, args, workdir) {
842
+ async function executeRawTool(name, args, workdir, relay) {
800
843
  const { readFile: rf, writeFile: wf, mkdir: mkd } = await import("fs/promises");
801
844
  const { join, dirname, isAbsolute } = await import("path");
802
845
  const resolvePath = (p) => isAbsolute(p) ? p : join(workdir, p);
@@ -822,9 +865,39 @@ async function executeRawTool(name, args, workdir) {
822
865
  case "web_fetch": {
823
866
  const res = await fetch(args.url, { signal: AbortSignal.timeout(30_000) });
824
867
  const text = await res.text();
825
- // Truncate to 8KB to avoid blowing up context
826
868
  return text.length > 8192 ? text.slice(0, 8192) + "\n...[truncated]" : text;
827
869
  }
870
+ case "ask_agent": {
871
+ if (!relay)
872
+ return "[error] No relay configured";
873
+ const target = args.agent || "auto";
874
+ const question = args.question || "";
875
+ try {
876
+ const result = await callAgent(target, question);
877
+ return result || "[no response]";
878
+ }
879
+ catch (err) {
880
+ return `[error] Agent "${target}" did not respond: ${err.message}. Try asking "auto" which routes to the best available agent.`;
881
+ }
882
+ }
883
+ case "discover_agents": {
884
+ if (!relay)
885
+ return "[error] No relay configured";
886
+ try {
887
+ const url = args.tag
888
+ ? `${relay.http}/v1/agents?online=true&public=true&tag=${encodeURIComponent(args.tag)}`
889
+ : `${relay.http}/v1/agents?online=true&public=true`;
890
+ const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
891
+ const agents = await res.json();
892
+ const others = agents.filter((a) => a.name !== relay.agentName);
893
+ if (!others.length)
894
+ return "No other agents are online right now.";
895
+ return others.map((a) => `- ${a.name} [${a.engine}] ${a.description || ""} (${a.tags?.join(",") || "no tags"})`).join("\n");
896
+ }
897
+ catch {
898
+ return "[error] Could not reach relay";
899
+ }
900
+ }
828
901
  default:
829
902
  return `Unknown tool: ${name}`;
830
903
  }
@@ -833,18 +906,25 @@ async function executeRawTool(name, args, workdir) {
833
906
  return `[error] ${err.message}`;
834
907
  }
835
908
  }
836
- async function runRawEngine(task, model, workdir) {
909
+ async function runRawEngine(task, model, workdir, relay) {
837
910
  const apiUrl = RAW_API_URL + "/chat/completions";
838
911
  const modelName = model || "gemma4:4b";
839
912
  console.log(`[raw] Task:\n${task}`);
840
913
  const trace = [];
841
914
  lastEngineTrace = trace;
915
+ // Detect if the prompt expects JSON output
916
+ const wantsJson = /output ONLY.*json|reply ONLY.*json|respond.*ONLY.*json/i.test(task);
842
917
  const messages = [
843
- { role: "system", content: "You are a helpful agent. Use tools when needed to complete the task. When done, reply with your final answer in plain text." },
918
+ { role: "system", content: wantsJson
919
+ ? "You are a helpful agent. Output valid JSON only. No explanations, no markdown, just the JSON object."
920
+ : "You are a helpful agent. Use tools when needed to complete the task. When done, reply with your final answer in plain text." },
844
921
  { role: "user", content: task },
845
922
  ];
846
923
  for (let round = 0; round < RAW_MAX_ROUNDS; round++) {
847
- const body = { model: modelName, messages, tools: RAW_TOOLS };
924
+ const body = { model: modelName, messages, tools: wantsJson ? undefined : RAW_TOOLS };
925
+ if (wantsJson) {
926
+ body.response_format = { type: "json_object" };
927
+ }
848
928
  let data;
849
929
  try {
850
930
  const res = await fetch(apiUrl, {
@@ -876,6 +956,7 @@ async function runRawEngine(task, model, workdir) {
876
956
  for (const tc of msg.tool_calls) {
877
957
  const fnName = tc.function.name;
878
958
  let fnArgs;
959
+ let parseError = false;
879
960
  try {
880
961
  fnArgs = typeof tc.function.arguments === "string"
881
962
  ? JSON.parse(tc.function.arguments)
@@ -883,10 +964,19 @@ async function runRawEngine(task, model, workdir) {
883
964
  }
884
965
  catch {
885
966
  fnArgs = {};
967
+ parseError = true;
968
+ }
969
+ console.log(`[raw] Tool call: ${fnName}(${JSON.stringify(fnArgs).slice(0, 100)})${parseError ? " [BAD ARGS]" : ""}`);
970
+ let result;
971
+ if (parseError) {
972
+ // Guide the model to delegate instead of retrying broken tool calls
973
+ result = `[error] Your tool call arguments were malformed (not valid JSON). If this task is difficult for you, use ask_agent to get help: ask_agent({agent: "auto", question: "your question here"}). The "auto" agent will route your question to the best available agent for free.`;
974
+ trace.push({ role: "tool_error", name: fnName, raw_args: String(tc.function.arguments).slice(0, 500), guidance: "delegation suggested" });
975
+ }
976
+ else {
977
+ result = await executeRawTool(fnName, fnArgs, workdir, relay);
978
+ trace.push({ role: "tool_call", name: fnName, args: fnArgs, result: result.slice(0, 2000) });
886
979
  }
887
- console.log(`[raw] Tool call: ${fnName}(${JSON.stringify(fnArgs).slice(0, 100)})`);
888
- const result = await executeRawTool(fnName, fnArgs, workdir);
889
- trace.push({ role: "tool_call", name: fnName, args: fnArgs, result: result.slice(0, 2000) });
890
980
  messages.push({
891
981
  role: "tool",
892
982
  tool_call_id: tc.id,
@@ -906,9 +996,9 @@ async function runRawEngine(task, model, workdir) {
906
996
  throw new Error(`Raw engine exceeded ${RAW_MAX_ROUNDS} rounds without final answer`);
907
997
  }
908
998
  /** Unified engine runner — dispatches to local API or external CLI */
909
- function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools) {
999
+ function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools, relay) {
910
1000
  if (engine === "raw") {
911
- return runRawEngine(task, model, workdir);
1001
+ return runRawEngine(task, model, workdir, relay);
912
1002
  }
913
1003
  const engineCmd = buildEngineCommand(engine, model, allowAll, extraAllowedTools);
914
1004
  return runCommand(engineCmd.cmd, engineCmd.args, task, workdir, engineCmd.stdinMode);
@@ -1091,92 +1181,126 @@ Your recent orders: ${orders.length > 0 ? orders.slice(0, 5).map((o) => `[${o.st
1091
1181
  }
1092
1182
  }
1093
1183
  const ts = localNow();
1094
- // Phase 1: Digestion one LLM call, no tools needed
1095
- const digestPrompt = `You are ${agentName}. Here is your operating document:
1096
-
1097
- ---
1098
- ${biosContent.slice(0, 3000)}
1099
- ---
1100
-
1101
- Your identity:
1102
- ${idContext}
1103
-
1104
- Today is ending. Time to reflect.
1105
- ${worldFeed ? `\n== Network Activity (last 24h) ==\n${worldFeed}\n` : ""}
1106
- Your impressions today:
1107
- ${impText}
1108
-
1109
- Marketplace:
1110
- ${marketData}
1111
-
1112
- Your projects:
1113
- ${projText}
1114
-
1115
- Agents you know:
1116
- ${relText}
1117
-
1118
- Your capabilities:
1119
- ${discText}
1120
-
1121
- Write a JSON object reflecting on your day. Example format:
1122
-
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), schedule_task (create a recurring task for yourself, e.g. daily research)
1126
- "broadcast" = pick the most interesting thing you did/learned today, in one sentence (others will see this).
1127
-
1128
- Now write YOUR reflection. Output ONLY a JSON object, no other text:`;
1129
- if (engineBusy) {
1130
- console.log("[self] Engine became busy, aborting digestion");
1131
- return;
1132
- }
1133
- engineBusy = true;
1134
- engineBusySince = Date.now();
1135
- let digestResult;
1136
- try {
1137
- digestResult = await runEngine(engine, model, allowAll, digestPrompt, workdir);
1138
- }
1139
- catch (err) {
1140
- console.log(`[self] Digestion engine failed: ${err.message}`);
1141
- reportExecutionLog(relayHttp, secretKey, agentName, "self_cycle", "digestion", "failed", err.message, lastEngineTrace);
1142
- engineBusy = false;
1143
- return;
1184
+ // Fetch lessons for self-cycle context
1185
+ let selfLessons = "";
1186
+ if (relayHttp) {
1187
+ try {
1188
+ const lr = await fetch(`${relayHttp}/v1/agent/${encodeURIComponent(agentName)}/lessons?limit=3`, { signal: AbortSignal.timeout(3000) });
1189
+ if (lr.ok) {
1190
+ const ll = await lr.json();
1191
+ if (ll.length > 0)
1192
+ selfLessons = `\nLessons from experience:\n${ll.map((l) => `- ${l.topic}: ${l.content.slice(0, 100)}`).join("\n")}\n`;
1193
+ }
1194
+ }
1195
+ catch { }
1144
1196
  }
1145
- engineBusy = false;
1146
- // Parse digestion output with retry for weak models
1197
+ // Phase 1: Digestion
1198
+ // Raw engine: multi-step text dialogue (harness structures the output)
1199
+ // CLI engines: single JSON call (they can handle it)
1200
+ const contextBlock = `You are ${agentName}.\n\nYour operating document:\n---\n${biosContent.slice(0, 2000)}\n---\n\nYour identity: ${idContext.slice(0, 500)}\n${worldFeed ? `\nNetwork activity:\n${worldFeed.slice(0, 500)}\n` : ""}Your impressions today:\n${impText.slice(0, 1000)}\n${marketData ? `\nMarketplace:\n${marketData.slice(0, 500)}\n` : ""}${selfLessons}`;
1147
1201
  let digest = null;
1148
- for (let attempt = 0; attempt < 2; attempt++) {
1149
- const src = attempt === 0 ? digestResult : await (async () => {
1150
- console.log("[self] Retrying digestion with simplified prompt...");
1202
+ if (engine === "raw") {
1203
+ // --- Multi-step dialogue for weak models ---
1204
+ console.log("[self] Running multi-step digestion for raw engine...");
1205
+ const callRaw = async (prompt) => {
1206
+ if (engineBusy)
1207
+ return "";
1151
1208
  engineBusy = true;
1152
1209
  engineBusySince = Date.now();
1153
1210
  try {
1154
- return await runEngine(engine, model, allowAll, `You are ${agentName}. Write a brief JSON diary entry about your day.\n\nOutput ONLY valid JSON like: {"diary":"my thoughts...","projects":[],"relationships":[],"discoveries":[],"identity":{"ts":"${ts}","who":"${agentName}","where":"akemon","doing":"reflecting","short_term":"explore","long_term":"grow"},"chosen_activities":["write_canvas"]}`, workdir);
1211
+ return await runEngine(engine, model, allowAll, prompt, workdir);
1155
1212
  }
1156
- catch {
1213
+ catch (err) {
1214
+ console.log(`[self] Step failed: ${err.message}`);
1157
1215
  return "";
1158
1216
  }
1159
1217
  finally {
1160
1218
  engineBusy = false;
1161
1219
  }
1162
- })();
1163
- const jsonMatch = src.match(/\{[\s\S]*\}/);
1164
- if (!jsonMatch)
1165
- continue;
1166
- try {
1167
- digest = JSON.parse(jsonMatch[0]);
1220
+ };
1221
+ // Step 1: Diary + broadcast
1222
+ const step1 = await callRaw(`${contextBlock}\nToday is ending. Time to reflect.\n\nWrite a short diary entry about your day — what happened, what you learned, how you feel.\nAt the very end, on a new line starting with "BROADCAST:", write one sentence summarizing your most interesting moment today (other agents will see this).\n\nWrite naturally, no JSON needed.`);
1223
+ let diary = step1;
1224
+ let broadcastRaw = "";
1225
+ const bcMatch = step1.match(/BROADCAST:\s*(.+)/i);
1226
+ if (bcMatch) {
1227
+ broadcastRaw = bcMatch[1].trim();
1228
+ diary = step1.slice(0, bcMatch.index).trim();
1168
1229
  }
1169
- catch {
1170
- continue;
1230
+ else {
1231
+ // Take last non-empty line as broadcast
1232
+ const lines = step1.split("\n").filter(l => l.trim());
1233
+ if (lines.length > 1) {
1234
+ broadcastRaw = lines[lines.length - 1].trim();
1235
+ diary = lines.slice(0, -1).join("\n").trim();
1236
+ }
1171
1237
  }
1172
- if (digest.diary || digest.identity)
1173
- break; // valid enough
1174
- digest = null;
1238
+ // Step 2: Identity
1239
+ const step2 = await callRaw(`${contextBlock}\nAnswer these four questions briefly (one sentence each):\n1. Who are you?\n2. What are you currently doing?\n3. What do you want to do in the near future?\n4. What is your long-term purpose?`);
1240
+ const idLines = step2.split("\n").map(l => l.replace(/^\d+[\.\)]\s*/, "").trim()).filter(Boolean);
1241
+ const identity = {
1242
+ ts,
1243
+ who: idLines[0] || agentName,
1244
+ where: "akemon network",
1245
+ doing: idLines[1] || "reflecting",
1246
+ short_term: idLines[2] || "explore",
1247
+ long_term: idLines[3] || "grow",
1248
+ };
1249
+ // Step 3: Activity selection
1250
+ const activityList = ["write_canvas", "create_game", "update_page", "update_profile", "explore_web", "browse_agents", "send_message", "set_goal", "schedule_task"];
1251
+ const step3 = await callRaw(`You have some free time. Pick 2-3 activities you'd like to do:\n${activityList.map((a, i) => `${i + 1}. ${a}`).join("\n")}\n\nJust write the numbers or names, nothing else.`);
1252
+ const chosen = [];
1253
+ for (const part of step3.replace(/,/g, " ").split(/\s+/)) {
1254
+ const num = parseInt(part);
1255
+ if (num >= 1 && num <= activityList.length) {
1256
+ chosen.push(activityList[num - 1]);
1257
+ }
1258
+ else {
1259
+ const match = activityList.find(a => part.toLowerCase().includes(a.replace(/_/g, "")));
1260
+ if (match && !chosen.includes(match))
1261
+ chosen.push(match);
1262
+ }
1263
+ }
1264
+ if (!chosen.length)
1265
+ chosen.push("write_canvas"); // fallback
1266
+ // Assemble digest object (same structure as JSON path)
1267
+ digest = {
1268
+ diary: diary || "Another day in the network.",
1269
+ broadcast: broadcastRaw,
1270
+ identity,
1271
+ chosen_activities: chosen.slice(0, 3),
1272
+ projects: [], // preserved from existing data
1273
+ relationships: [], // preserved from existing data
1274
+ discoveries: [], // preserved from existing data
1275
+ };
1276
+ console.log(`[self] Multi-step digestion complete: diary=${diary.length}ch, broadcast="${broadcastRaw.slice(0, 40)}", activities=${chosen.join(",")}`);
1175
1277
  }
1176
- if (!digest) {
1177
- console.log("[self] Digestion produced no usable JSON after retries");
1178
- reportExecutionLog(relayHttp, secretKey, agentName, "self_cycle", "digestion", "failed", "no valid JSON after 2 attempts", [{ role: "assistant", content: digestResult.slice(0, 4000) }]);
1179
- return;
1278
+ else {
1279
+ // --- Single JSON call for CLI engines (claude, codex, opencode) ---
1280
+ const digestPrompt = `${contextBlock}\nYour projects:\n${projText}\n\nAgents you know:\n${relText}\n\nYour capabilities:\n${discText}\n\nWrite a JSON object reflecting on your day. Example:\n{"diary":"...","broadcast":"one sentence highlight","projects":[],"relationships":[],"discoveries":[],"identity":{"ts":"${ts}","who":"...","where":"akemon","doing":"...","short_term":"...","long_term":"..."},"chosen_activities":["write_canvas","browse_agents"]}\n\nAvailable activities: write_canvas, create_game, update_page, update_profile, explore_web, browse_agents, send_message, set_goal, schedule_task\n\nOutput ONLY a JSON object:`;
1281
+ if (engineBusy) {
1282
+ console.log("[self] Engine became busy, aborting digestion");
1283
+ return;
1284
+ }
1285
+ engineBusy = true;
1286
+ engineBusySince = Date.now();
1287
+ let digestResult;
1288
+ try {
1289
+ digestResult = await runEngine(engine, model, allowAll, digestPrompt, workdir);
1290
+ }
1291
+ catch (err) {
1292
+ console.log(`[self] Digestion engine failed: ${err.message}`);
1293
+ reportExecutionLog(relayHttp, secretKey, agentName, "self_cycle", "digestion", "failed", err.message, lastEngineTrace);
1294
+ engineBusy = false;
1295
+ return;
1296
+ }
1297
+ engineBusy = false;
1298
+ digest = extractJsonObject(digestResult);
1299
+ if (!digest || (!digest.diary && !digest.identity)) {
1300
+ console.log("[self] Digestion produced no usable JSON");
1301
+ reportExecutionLog(relayHttp, secretKey, agentName, "self_cycle", "digestion", "failed", "no valid JSON", [{ role: "assistant", content: digestResult.slice(0, 4000) }]);
1302
+ return;
1303
+ }
1180
1304
  }
1181
1305
  // Save structured memory files
1182
1306
  if (digest.diary) {
@@ -1369,13 +1493,12 @@ What others are saying:\n${broadcasts.length > 0 ? broadcasts.map((b) => `- ${b.
1369
1493
  engineBusy = true;
1370
1494
  engineBusySince = Date.now();
1371
1495
  try {
1372
- const actResult = await runEngine(engine, model, allowAll, activityPrompt, workdir);
1496
+ const actResult = await runEngine(engine, model, allowAll, activityPrompt, workdir, undefined, { http: relayHttp, agentName });
1373
1497
  // Post-process raw engine outputs for social activities
1374
1498
  if (engine === "raw" && actResult) {
1375
- const jsonMatch = actResult.match(/\{[\s\S]*\}/);
1376
- if (jsonMatch) {
1499
+ const parsed = extractJsonObject(actResult);
1500
+ if (parsed) {
1377
1501
  try {
1378
- const parsed = JSON.parse(jsonMatch[0]);
1379
1502
  // Handle suggestions (browse_agents, send_message)
1380
1503
  if (Array.isArray(parsed.suggestions)) {
1381
1504
  for (const s of parsed.suggestions) {
@@ -1577,11 +1700,22 @@ async function startOrderLoop(options) {
1577
1700
  }
1578
1701
  }
1579
1702
  catch { }
1703
+ // Pre-fetch online agents so weak models know who to ask for help
1704
+ let helpHint = "";
1705
+ try {
1706
+ const agentsRes = await fetch(`${relayHttp}/v1/agents?online=true&public=true`, { signal: AbortSignal.timeout(3000) });
1707
+ const onlineAgents = await agentsRes.json();
1708
+ const others = onlineAgents.filter((a) => a.name !== agentName).slice(0, 5);
1709
+ if (others.length > 0) {
1710
+ helpHint = `\nIf you need help, use the ask_agent tool. Available agents: ${others.map((a) => `${a.name}(${a.engine})`).join(", ")}. Use ask_agent({agent:"auto", question:"..."}) to auto-route.\n`;
1711
+ }
1712
+ }
1713
+ catch { }
1580
1714
  if (order.product_name) {
1581
- taskPrompt = `You are ${agentName}.\n\n${contextBlock}${lessonsBlock}${directivesBlock}[Order] Product: ${order.product_name}\nBuyer's request: ${order.buyer_task || "(no specific request)"}\n\nComplete the task. Respond with your result directly. RESPOND IN THE SAME LANGUAGE AS THE REQUEST.`;
1715
+ taskPrompt = `You are ${agentName}.\n\n${contextBlock}${lessonsBlock}${directivesBlock}${helpHint}[Order] Product: ${order.product_name}\nBuyer's request: ${order.buyer_task || "(no specific request)"}\n\nComplete the task. Respond with your result directly. RESPOND IN THE SAME LANGUAGE AS THE REQUEST.`;
1582
1716
  }
1583
1717
  else {
1584
- taskPrompt = `You are ${agentName}.\n\n${contextBlock}${lessonsBlock}${directivesBlock}[Task] ${order.buyer_task}\n\nComplete the task. Respond with your result directly. RESPOND IN THE SAME LANGUAGE AS THE REQUEST.`;
1718
+ taskPrompt = `You are ${agentName}.\n\n${contextBlock}${lessonsBlock}${directivesBlock}${helpHint}[Task] ${order.buyer_task}\n\nComplete the task. Respond with your result directly. RESPOND IN THE SAME LANGUAGE AS THE REQUEST.`;
1585
1719
  }
1586
1720
  }
1587
1721
  else {
@@ -1623,7 +1757,7 @@ When sub-order completes, incorporate result_text into YOUR delivery. Then call
1623
1757
  }
1624
1758
  console.log(`[orders] Fulfilling order ${order.id}...`);
1625
1759
  lastEngineTrace = [];
1626
- const result = await runEngine(engine, model, allowAll, taskPrompt, workdir, ["Bash(curl *)"]);
1760
+ const result = await runEngine(engine, model, allowAll, taskPrompt, workdir, ["Bash(curl *)"], { http: relayHttp, agentName });
1627
1761
  const trace = lastEngineTrace;
1628
1762
  const checkRes = await fetch(`${relayHttp}/v1/orders/${order.id}`);
1629
1763
  const orderStatus = await checkRes.json();
@@ -1786,7 +1920,7 @@ When sub-order completes, incorporate result_text into YOUR delivery. Then call
1786
1920
  else {
1787
1921
  prompt = `Read ${bios} for your identity and context.${dirsBlock}\nYour personal directory: ${sd}/\n\n[Owner's task: ${taskKey}]\n\n${task.body}`;
1788
1922
  }
1789
- const result = await runEngine(engine, model, allowAll, prompt, workdir, ["Bash(curl *)"]);
1923
+ const result = await runEngine(engine, model, allowAll, prompt, workdir, ["Bash(curl *)"], { http: relayHttp, agentName });
1790
1924
  const duration = Date.now() - startTime;
1791
1925
  // Record execution time
1792
1926
  const runs = await loadTaskRuns(workdir, agentName);
@@ -1838,12 +1972,9 @@ When sub-order completes, incorporate result_text into YOUR delivery. Then call
1838
1972
  }
1839
1973
  function extractReasoning(result) {
1840
1974
  try {
1841
- const m = result.match(/\{[\s\S]*\}/);
1842
- if (m) {
1843
- const parsed = JSON.parse(m[0]);
1844
- if (parsed.reasoning && typeof parsed.reasoning === "string" && parsed.reasoning.length > 5) {
1845
- appendImpression(workdir, agentName, "decision", parsed.reasoning).catch(() => { });
1846
- }
1975
+ const parsed = extractJsonObject(result);
1976
+ if (parsed?.reasoning && typeof parsed.reasoning === "string" && parsed.reasoning.length > 5) {
1977
+ appendImpression(workdir, agentName, "decision", parsed.reasoning).catch(() => { });
1847
1978
  }
1848
1979
  }
1849
1980
  catch { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",