@mclawnet/agent 0.6.30 → 0.6.31

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.
@@ -46,6 +46,13 @@ export interface SpawnOptions {
46
46
  mcpConfigPath?: string;
47
47
  /** Memory system role ID. When set, SessionManager auto-injects memory prompt + MCP config */
48
48
  roleId?: string;
49
+ /**
50
+ * Optional first user input. When set, SessionManager uses this as the
51
+ * semantic-retrieval query for `buildMemorySection` (Pipeline A) so the
52
+ * injected memory section is relevant to what the user is about to ask.
53
+ * Falls back to an empty query (importance-top-K) when omitted.
54
+ */
55
+ initialUserInput?: string;
49
56
  /** Extra directories to mount via --add-dir */
50
57
  additionalDirs?: string[];
51
58
  /** Optional allowlist of tool names to forward to the backend (PR3.5). */
@@ -1 +1 @@
1
- {"version":3,"file":"backend-adapter.d.ts","sourceRoot":"","sources":["../src/backend-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IAEb,kCAAkC;IAClC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEtD,qCAAqC;IACrC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,6CAA6C;IAC7C,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnD,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IAEzE,qCAAqC;IACrC,cAAc,CAAC,CACb,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAChD,KAAK,IAAI,GACT,IAAI,CAAC;IAER,6BAA6B;IAC7B,OAAO,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAEzE;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,CACf,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACnD,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;IAE/E;;;;;;;;;OASG;IACH,oBAAoB,CAAC,CACnB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,KAAK,IAAI,GACT,IAAI,CAAC;CACT"}
1
+ {"version":3,"file":"backend-adapter.d.ts","sourceRoot":"","sources":["../src/backend-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IAEb,kCAAkC;IAClC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEtD,qCAAqC;IACrC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,6CAA6C;IAC7C,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnD,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IAEzE,qCAAqC;IACrC,cAAc,CAAC,CACb,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAChD,KAAK,IAAI,GACT,IAAI,CAAC;IAER,6BAA6B;IAC7B,OAAO,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAEzE;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,CACf,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACnD,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;IAE/E;;;;;;;;;OASG;IACH,oBAAoB,CAAC,CACnB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,KAAK,IAAI,GACT,IAAI,CAAC;CACT"}
@@ -470,6 +470,7 @@ async function handleSwarmControl(coord, msg, opts) {
470
470
 
471
471
  // src/hub-connection.ts
472
472
  import { createLogger as createLogger2, previewFields } from "@mclawnet/logger";
473
+ import { DEFAULT_ASSISTANT_ROLE_ID } from "@mclawnet/memory";
473
474
  var log2 = createLogger2({ module: "agent" });
474
475
  var HubConnection = class {
475
476
  ws = null;
@@ -598,10 +599,16 @@ var HubConnection = class {
598
599
  }
599
600
  if (this.authState === "authenticated") {
600
601
  this.lastAckAt = Date.now();
602
+ if (data && data.type === "heartbeat_ack") {
603
+ return;
604
+ }
601
605
  if (this.handleSessionMessage(data)) return;
602
606
  this.onMessage?.(data);
603
607
  }
604
608
  });
609
+ this.ws.on("pong", () => {
610
+ this.lastAckAt = Date.now();
611
+ });
605
612
  this.ws.on("close", (code, reason) => {
606
613
  log2.warn({ code, reason: reason.toString() }, "disconnected from hub");
607
614
  this.stopHeartbeat();
@@ -1014,10 +1021,12 @@ var HubConnection = class {
1014
1021
  workDir,
1015
1022
  resumeId,
1016
1023
  useBrainCore,
1017
- roleId: "role-__assistant__",
1024
+ roleId: DEFAULT_ASSISTANT_ROLE_ID,
1018
1025
  maxOutputTokens
1019
1026
  }).then(() => {
1020
- sm.sendInput(sessionId, content);
1027
+ sm.sendUserInput(sessionId, content).catch((err) => {
1028
+ log2.warn({ err, sessionId }, "sendUserInput failed");
1029
+ });
1021
1030
  }).catch((err) => {
1022
1031
  this.send({
1023
1032
  type: "session.error",
@@ -1029,7 +1038,9 @@ var HubConnection = class {
1029
1038
  if (sm.isHealthy(sessionId)) {
1030
1039
  log2.info({ sessionId }, "claude.execute: reusing healthy session");
1031
1040
  log2.debug({ sessionId, ...previewFields(content) }, "claude.execute: input");
1032
- sm.sendInput(sessionId, content);
1041
+ sm.sendUserInput(sessionId, content).catch((err) => {
1042
+ log2.warn({ err, sessionId }, "sendUserInput failed");
1043
+ });
1033
1044
  } else if (sm.hasSession(sessionId) && claudeSessionId) {
1034
1045
  const recommendedMax = sm.getRecommendedMaxOutputTokens(sessionId);
1035
1046
  log2.warn({ sessionId, claudeSessionId }, "claude.execute: session unhealthy, recreating with --resume");
@@ -1069,12 +1080,12 @@ var HubConnection = class {
1069
1080
  return true;
1070
1081
  }
1071
1082
  if (msg.type === "session.create") {
1072
- log2.info({ sessionId: msg.sessionId, roleId: "role-__assistant__" }, "session.create with memory injection");
1083
+ log2.info({ sessionId: msg.sessionId, roleId: DEFAULT_ASSISTANT_ROLE_ID }, "session.create with memory injection");
1073
1084
  this.sessionManager.createSession({
1074
1085
  sessionId: msg.sessionId,
1075
1086
  workDir: msg.workDir,
1076
1087
  resumeId: msg.resumeId,
1077
- roleId: "role-__assistant__"
1088
+ roleId: DEFAULT_ASSISTANT_ROLE_ID
1078
1089
  }).then((claudeSessionId) => {
1079
1090
  this.send({
1080
1091
  type: "session.created",
@@ -1101,7 +1112,9 @@ var HubConnection = class {
1101
1112
  { sessionId: msg.sessionId, ...previewFields(msg.content) },
1102
1113
  "claude.input"
1103
1114
  );
1104
- this.sessionManager.sendInput(msg.sessionId, msg.content);
1115
+ this.sessionManager.sendUserInput(msg.sessionId, msg.content).catch((err) => {
1116
+ log2.warn({ err, sessionId: msg.sessionId }, "sendUserInput failed");
1117
+ });
1105
1118
  return true;
1106
1119
  }
1107
1120
  return false;
@@ -1161,6 +1174,10 @@ var HubConnection = class {
1161
1174
  return;
1162
1175
  }
1163
1176
  this.send({ type: "heartbeat", ts: Date.now() });
1177
+ try {
1178
+ this.ws?.ping();
1179
+ } catch {
1180
+ }
1164
1181
  }, this.heartbeatInterval);
1165
1182
  }
1166
1183
  stopHeartbeat() {
@@ -1694,7 +1711,12 @@ function makeRealSwarmStarter(_deps) {
1694
1711
 
1695
1712
  // src/session-manager.ts
1696
1713
  import { createLogger as createLogger5, previewFields as previewFields2 } from "@mclawnet/logger";
1697
- import { buildMemorySection } from "@mclawnet/memory";
1714
+ import {
1715
+ buildMemorySection,
1716
+ EmbeddingService,
1717
+ createEmbeddingProviders,
1718
+ initDatabase
1719
+ } from "@mclawnet/memory";
1698
1720
  import { MAX_TOKENS_LADDER, clampLadderIndex } from "@mclawnet/shared";
1699
1721
 
1700
1722
  // src/skill-loader.ts
@@ -2056,6 +2078,13 @@ function isPidAlive(pid) {
2056
2078
  }
2057
2079
 
2058
2080
  // src/session-manager.ts
2081
+ var sharedEmbeddingService = null;
2082
+ function getSharedEmbeddingService() {
2083
+ if (sharedEmbeddingService) return sharedEmbeddingService;
2084
+ const db = initDatabase();
2085
+ sharedEmbeddingService = new EmbeddingService(db, createEmbeddingProviders());
2086
+ return sharedEmbeddingService;
2087
+ }
2059
2088
  var log5 = createLogger5({ module: "agent/session-manager" });
2060
2089
  var DEFAULT_MAX_PROCESSES = 30;
2061
2090
  var MAX_PROCESSES = Number(process.env.CLAWNET_MAX_PROCESSES) || DEFAULT_MAX_PROCESSES;
@@ -2162,19 +2191,26 @@ var SessionManager = class {
2162
2191
  if (this.sessions.size >= MAX_PROCESSES) {
2163
2192
  throw new SessionLimitReachedError(this.snapshotPoolForError());
2164
2193
  }
2165
- if (options.roleId) {
2194
+ if (options.workDir) {
2166
2195
  try {
2167
- const memorySection = buildMemorySection(options.roleId);
2168
- const roleHint = `
2169
-
2170
- [Memory Context] Your roleId is "${options.roleId}". Always use this roleId when calling memory_search, memory_store, memory_stats, or memory_reflect.`;
2171
- options.systemPrompt = options.systemPrompt ? `${memorySection}${roleHint}
2196
+ const query = options.initialUserInput ?? "";
2197
+ const memorySection = await buildMemorySection({
2198
+ query,
2199
+ workDir: options.workDir,
2200
+ embeddingService: getSharedEmbeddingService()
2201
+ });
2202
+ options.systemPrompt = options.systemPrompt ? `${memorySection}
2172
2203
 
2173
- ${options.systemPrompt}` : `${memorySection}${roleHint}`;
2174
- log5.debug({ roleId: options.roleId, sessionId: options.sessionId }, "memory prompt + roleId hint injected");
2204
+ ${options.systemPrompt}` : memorySection;
2205
+ log5.debug({ workDir: options.workDir, sessionId: options.sessionId }, "memory prompt injected");
2175
2206
  } catch (err) {
2176
- log5.warn({ err, roleId: options.roleId }, "failed to build memory section, proceeding without");
2207
+ log5.warn({ err, workDir: options.workDir }, "failed to build memory section, proceeding without");
2177
2208
  }
2209
+ } else {
2210
+ log5.warn(
2211
+ { sessionId: options.sessionId, roleId: options.roleId },
2212
+ "session created without workDir \u2014 memory injection skipped (all memories would be cross-workdir; pass workDir to enable scoped retrieval)"
2213
+ );
2178
2214
  }
2179
2215
  try {
2180
2216
  const notice = getPendingNotification();
@@ -2192,6 +2228,12 @@ ${notice.text}`;
2192
2228
  } catch (err) {
2193
2229
  log5.debug({ err }, "failed to inject pending notification");
2194
2230
  }
2231
+ if (this.classify(options.sessionId) === "chat") {
2232
+ const ideaHint = `
2233
+
2234
+ [Idea Capture] When you propose a concrete user-actionable idea, feature suggestion, or follow-up TODO, additionally emit a single tag like \`<idea title="short title" body="one-paragraph context"/>\` at the end of that paragraph. Keep it concise and use it sparingly \u2014 only for things the user would plausibly want to save and revisit. The tag itself will be hidden from the chat view.`;
2235
+ options.systemPrompt = options.systemPrompt ? `${options.systemPrompt}${ideaHint}` : ideaHint.trimStart();
2236
+ }
2195
2237
  try {
2196
2238
  const process2 = await this.adapter.spawn(options);
2197
2239
  this.sessions.set(options.sessionId, process2);
@@ -2344,6 +2386,39 @@ ${notice.text}`;
2344
2386
  );
2345
2387
  this.adapter.send(process2, input);
2346
2388
  }
2389
+ /**
2390
+ * User-input variant of sendInput: best-effort prepend a `<memory-context>`
2391
+ * block sourced from semantic retrieval (Pipeline B). Falls back to plain
2392
+ * sendInput if retrieval errors or exceeds the 200ms budget — we never
2393
+ * block the user's turn on memory.
2394
+ */
2395
+ async sendUserInput(sessionId, content) {
2396
+ const meta = this.sessionMeta.get(sessionId);
2397
+ const workDir = meta?.workDir;
2398
+ let prefixed = content;
2399
+ try {
2400
+ const section = await Promise.race([
2401
+ buildMemorySection({
2402
+ query: content,
2403
+ workDir,
2404
+ embeddingService: getSharedEmbeddingService()
2405
+ }),
2406
+ new Promise(
2407
+ (resolve) => setTimeout(() => resolve(""), 200)
2408
+ )
2409
+ ]);
2410
+ if (section && section.trim().length > 0) {
2411
+ prefixed = `<memory-context>
2412
+ ${section}
2413
+ </memory-context>
2414
+
2415
+ ${content}`;
2416
+ }
2417
+ } catch (err) {
2418
+ log5.debug({ err, sessionId }, "sendUserInput: memory retrieval skipped");
2419
+ }
2420
+ this.sendInput(sessionId, prefixed);
2421
+ }
2347
2422
  async abortSession(sessionId) {
2348
2423
  const process2 = this.sessions.get(sessionId);
2349
2424
  if (!process2) return;
@@ -3051,11 +3126,12 @@ function createSwarmAwareSessionStartedHandler(deps) {
3051
3126
  // src/start.ts
3052
3127
  import { createLogger as createLogger9 } from "@mclawnet/logger";
3053
3128
  import {
3054
- initDatabase,
3129
+ initDatabase as initDatabase2,
3055
3130
  MemoryStore,
3056
- EmbeddingService,
3057
- createEmbeddingProviders,
3058
- distillConversation
3131
+ EmbeddingService as EmbeddingService2,
3132
+ createEmbeddingProviders as createEmbeddingProviders2,
3133
+ distillConversation,
3134
+ DEFAULT_ASSISTANT_ROLE_ID as DEFAULT_ASSISTANT_ROLE_ID2
3059
3135
  } from "@mclawnet/memory";
3060
3136
  import {
3061
3137
  SkillStore,
@@ -3120,9 +3196,9 @@ async function startAgent(options) {
3120
3196
  let skillStore = null;
3121
3197
  let memoryDb = null;
3122
3198
  try {
3123
- memoryDb = initDatabase(dbPath);
3199
+ memoryDb = initDatabase2(dbPath);
3124
3200
  memoryStore = new MemoryStore(memoryDb);
3125
- embeddingService = new EmbeddingService(memoryDb, createEmbeddingProviders());
3201
+ embeddingService = new EmbeddingService2(memoryDb, createEmbeddingProviders2());
3126
3202
  skillStore = new SkillStore(clawnetDir);
3127
3203
  evolutionPipeline = new EvolutionPipeline(clawnetDir);
3128
3204
  } catch (err) {
@@ -3134,7 +3210,7 @@ async function startAgent(options) {
3134
3210
  try {
3135
3211
  await distillConversation(
3136
3212
  messages,
3137
- "role-__assistant__",
3213
+ DEFAULT_ASSISTANT_ROLE_ID2,
3138
3214
  memoryStore,
3139
3215
  embeddingService
3140
3216
  );
@@ -3145,7 +3221,7 @@ async function startAgent(options) {
3145
3221
  if (!skillStore || !evolutionPipeline) return;
3146
3222
  const skills = skillStore.scan();
3147
3223
  if (skills.length === 0) return;
3148
- const recent = memoryStore.getMemoriesByRole("role-__assistant__", "working");
3224
+ const recent = memoryStore.getRecentMemoriesByRole(DEFAULT_ASSISTANT_ROLE_ID2, { limit: 50 });
3149
3225
  const refs = recent.map((m) => ({
3150
3226
  id: m.id,
3151
3227
  type: m.type,
@@ -3265,4 +3341,4 @@ export {
3265
3341
  FsBridge,
3266
3342
  startAgent
3267
3343
  };
3268
- //# sourceMappingURL=chunk-LXSWV3VS.js.map
3344
+ //# sourceMappingURL=chunk-U5CD3OZ3.js.map