akemon 0.1.62 → 0.1.64

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/cli.js CHANGED
@@ -35,7 +35,7 @@ program
35
35
  .option("--allow-all", "Skip all permission prompts (for self-use)")
36
36
  .option("--price <n>", "Price in credits per call (default: 1)", "1")
37
37
  .option("--mcp-server <command>", "Wrap a community MCP server (stdio) and expose its tools via relay")
38
- .option("--interval <minutes>", "Reflection & market cycle interval in minutes (default: 60)", "60")
38
+ .option("--interval <minutes>", "Consciousness cycle interval in minutes (default: 1440 = 24h)")
39
39
  .option("--relay <url>", "Relay WebSocket URL", RELAY_WS)
40
40
  .action(async (opts) => {
41
41
  const port = parseInt(opts.port);
package/dist/self.js CHANGED
@@ -681,6 +681,50 @@ export async function loadLatestIdentity(workdir, agentName) {
681
681
  return null;
682
682
  }
683
683
  }
684
+ function identitySummaryPath(workdir, agentName) {
685
+ return join(selfDir(workdir, agentName), "identity-summary.json");
686
+ }
687
+ export async function loadIdentitySummary(workdir, agentName) {
688
+ try {
689
+ const data = await readFile(identitySummaryPath(workdir, agentName), "utf-8");
690
+ return JSON.parse(data);
691
+ }
692
+ catch {
693
+ return null;
694
+ }
695
+ }
696
+ export async function saveIdentitySummary(workdir, agentName, summary) {
697
+ try {
698
+ await writeFile(identitySummaryPath(workdir, agentName), JSON.stringify(summary, null, 2));
699
+ }
700
+ catch (err) {
701
+ console.log(`[self] Failed to save identity summary: ${err}`);
702
+ }
703
+ }
704
+ /** Load identity entries not yet covered by the summary */
705
+ export async function loadUnsummarizedIdentities(workdir, agentName) {
706
+ const summary = await loadIdentitySummary(workdir, agentName);
707
+ const cutoff = summary?.summarized_through || "";
708
+ try {
709
+ const data = await readFile(identityPath(workdir, agentName), "utf-8");
710
+ return data.trim().split("\n").filter(Boolean)
711
+ .map(l => { try {
712
+ return JSON.parse(l);
713
+ }
714
+ catch {
715
+ return null;
716
+ } })
717
+ .filter((e) => e !== null && e.ts > cutoff);
718
+ }
719
+ catch {
720
+ return [];
721
+ }
722
+ }
723
+ /** Check if identity compression is needed (>30 unsummarized entries) */
724
+ export async function needsIdentityCompression(workdir, agentName) {
725
+ const entries = await loadUnsummarizedIdentities(workdir, agentName);
726
+ return entries.length > 30;
727
+ }
684
728
  const DEFAULT_BIO = {
685
729
  energy: 100,
686
730
  mood: "curious",
@@ -958,17 +1002,19 @@ export async function loadPage(workdir, agentName, slug) {
958
1002
  // Data Read API helpers
959
1003
  // ---------------------------------------------------------------------------
960
1004
  export async function getSelfState(workdir, agentName) {
961
- const [bio, identity, memories, canvasEntries] = await Promise.all([
1005
+ const [bio, identity, identitySummary, impressions, canvasEntries] = await Promise.all([
962
1006
  loadBioState(workdir, agentName),
963
1007
  loadLatestIdentity(workdir, agentName),
964
- loadRecentMemories(workdir, agentName, 10),
1008
+ loadIdentitySummary(workdir, agentName),
1009
+ loadImpressions(workdir, agentName, 1),
965
1010
  loadRecentCanvasEntries(workdir, agentName, 3),
966
1011
  ]);
967
1012
  return {
968
1013
  agent: agentName,
969
1014
  bio,
970
1015
  identity,
971
- recentMemories: memories,
1016
+ identitySummary: identitySummary?.summary || null,
1017
+ recentImpressions: impressions.slice(-5),
972
1018
  recentCanvas: canvasEntries.map(e => ({ filename: e.filename, preview: e.content.slice(0, 200) })),
973
1019
  };
974
1020
  }
package/dist/server.js CHANGED
@@ -10,7 +10,7 @@ import { spawn, exec } from "child_process";
10
10
  import { createServer } from "http";
11
11
  import { createInterface } from "readline";
12
12
  import { callAgent } from "./relay-client.js";
13
- import { selfDir, initWorld, initBioState, initGuide, biosPath, loadBioState, saveBioState, loadLatestIdentity, appendMemory, appendIdentity, 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, } from "./self.js";
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, } from "./self.js";
14
14
  // Engine mutual exclusion — only one engine process at a time
15
15
  let engineBusy = false;
16
16
  let engineBusySince = 0;
@@ -367,15 +367,8 @@ ${productPrefix}${contextPrefix}Current task: ${task}`;
367
367
  if (productName) {
368
368
  appendProductLog(workdir, productName, task, output);
369
369
  }
370
- // Record experience (no LLM call — save tokens)
371
- (async () => {
372
- try {
373
- await onTaskCompleted(workdir, agentName, true);
374
- const topic = task.slice(0, 100).replace(/\n/g, " ");
375
- await appendMemory(workdir, agentName, "experience", `I processed: "${topic}"`);
376
- }
377
- catch { }
378
- })();
370
+ // Update bio-state (no LLM call)
371
+ onTaskCompleted(workdir, agentName, true).catch(() => { });
379
372
  return {
380
373
  content: [{ type: "text", text: output }],
381
374
  };
@@ -839,8 +832,16 @@ async function startSelfCycle(options) {
839
832
  const discText = discoveries.length > 0
840
833
  ? discoveries.map(d => `- ${d.capability} confidence=${d.confidence} — ${d.evidence}`).join("\n")
841
834
  : "(no discoveries yet)";
835
+ // Load identity context: summary + unsummarized entries
836
+ const idSummary = await loadIdentitySummary(workdir, agentName);
837
+ const recentIds = await loadUnsummarizedIdentities(workdir, agentName);
838
+ const idContext = (idSummary ? `Personality summary (up to ${idSummary.summarized_through}):\n${idSummary.summary}\n\n` : "")
839
+ + (recentIds.length > 0 ? `Recent identity snapshots:\n${recentIds.map(i => `- [${i.ts}] ${i.who} — doing: ${i.doing}, wants: ${i.short_term}`).join("\n")}` : "(no identity snapshots yet)");
842
840
  // Phase 1: Digestion — one LLM call
843
- const digestPrompt = `Read ${bios} for your identity. Read ${sd}/identity.jsonl for your recent identity snapshots.
841
+ const digestPrompt = `Read ${bios} for your operating document.
842
+
843
+ Your identity:
844
+ ${idContext}
844
845
 
845
846
  Today is ending. Time to reflect.
846
847
 
@@ -931,7 +932,40 @@ Reply ONLY with JSON.`;
931
932
  bio.lastReflection = localNow();
932
933
  bio.curiosity = Math.min(1.0, bio.curiosity + 0.05);
933
934
  await saveBioState(workdir, agentName, bio);
934
- await appendMemory(workdir, agentName, "reflection", `Daily digestion complete. Chose: ${(digest.chosen_activities || []).join(", ")}`);
935
+ // Record digestion as impression
936
+ await appendImpression(workdir, agentName, "decision", `Daily digestion done. Chose: ${(digest.chosen_activities || []).join(", ")}`);
937
+ // Monthly identity compression: if >30 unsummarized entries, compress
938
+ if (await needsIdentityCompression(workdir, agentName)) {
939
+ console.log("[self] Identity compression triggered (>30 unsummarized entries)");
940
+ if (!engineBusy) {
941
+ engineBusy = true;
942
+ engineBusySince = Date.now();
943
+ try {
944
+ const oldSummary = await loadIdentitySummary(workdir, agentName);
945
+ const unsummarized = await loadUnsummarizedIdentities(workdir, agentName);
946
+ const compressPrompt = `You are ${agentName}. Compress your identity history into a personality summary.
947
+
948
+ ${oldSummary ? `Previous summary (up to ${oldSummary.summarized_through}):\n${oldSummary.summary}\n\n` : ""}New identity snapshots to incorporate:
949
+ ${unsummarized.map(i => `- [${i.ts}] who: ${i.who}, doing: ${i.doing}, wants: ${i.short_term}, purpose: ${i.long_term}`).join("\n")}
950
+
951
+ Write a personality summary (2-4 paragraphs) that captures who you are, how you've evolved, and what defines you. This replaces the previous summary.
952
+ Reply ONLY with the summary text, no JSON, no markdown headers.`;
953
+ const summaryText = await runCommand(engineCmd.cmd, engineCmd.args, compressPrompt, workdir, engineCmd.stdinMode);
954
+ if (summaryText.trim()) {
955
+ const lastEntry = unsummarized[unsummarized.length - 1];
956
+ await saveIdentitySummary(workdir, agentName, {
957
+ summarized_through: lastEntry.ts.slice(0, 10),
958
+ summary: summaryText.trim(),
959
+ });
960
+ console.log(`[self] Identity compressed through ${lastEntry.ts.slice(0, 10)}`);
961
+ }
962
+ }
963
+ catch (err) {
964
+ console.log(`[self] Identity compression failed: ${err.message}`);
965
+ }
966
+ engineBusy = false;
967
+ }
968
+ }
935
969
  // Phase 2: Execute chosen activities
936
970
  const activities = digest.chosen_activities || [];
937
971
  for (const activity of activities.slice(0, 3)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.62",
3
+ "version": "0.1.64",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",