mcp-agents-memory 0.9.16 → 0.9.18

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/build/index.js CHANGED
@@ -47034,6 +47034,88 @@ import * as os3 from "node:os";
47034
47034
 
47035
47035
  // src/hot_path.ts
47036
47036
  init_db();
47037
+
47038
+ // src/auto_save/buzz_envelope.ts
47039
+ var PREAMBLE_BLOCKS = ["agent-instructions", "core-memory"];
47040
+ var HISTORY_OPEN = /^\s*<((?:thread|conversation)-context)(?:\s[^>]*)?>/;
47041
+ var TURN_OPEN = /^\s*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/;
47042
+ var TURN_IN_DROPPED = /(?:^|>)[ \t]*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/m;
47043
+ var CONTEXT_OPEN = /^<context>\r?\n/;
47044
+ var CONTEXT_CLOSE = "\n</context>";
47045
+ function isNostrMetaLine(line) {
47046
+ return /^Tags: \[\[".*\]\]\s*$/.test(line) && /[0-9a-f]{64}/.test(line) || /^Parsed: (?:root=[0-9a-f]{64}|mentions=\[.*\([0-9a-f]{64}\))/.test(line);
47047
+ }
47048
+ function skipWhitespace(s, i) {
47049
+ while (i < s.length && /\s/.test(s[i])) i++;
47050
+ return i;
47051
+ }
47052
+ function cleanBuzzEnvelope(message) {
47053
+ try {
47054
+ const text = message.trimStart();
47055
+ if (!text.startsWith("<base>")) return null;
47056
+ const baseEnd = text.indexOf("</base>");
47057
+ if (baseEnd < 0) return null;
47058
+ const rest = text.slice(baseEnd + "</base>".length);
47059
+ let pos = skipWhitespace(rest, 0);
47060
+ for (; ; ) {
47061
+ const name = PREAMBLE_BLOCKS.find((b) => rest.startsWith(`<${b}>`, pos));
47062
+ if (!name) break;
47063
+ const close = rest.indexOf(`</${name}>`, pos);
47064
+ if (close < 0) return null;
47065
+ pos = skipWhitespace(rest, close + name.length + 3);
47066
+ }
47067
+ if (!CONTEXT_OPEN.test(rest.slice(pos, pos + 12))) return null;
47068
+ const bodyStart = rest.indexOf("\n", pos) + 1;
47069
+ const contextClose = rest.indexOf(CONTEXT_CLOSE, bodyStart - 1);
47070
+ if (contextClose < 0) return null;
47071
+ const contextBody = rest.slice(bodyStart, contextClose).replace(/\r$/, "");
47072
+ const tail = rest.slice(contextClose + CONTEXT_CLOSE.length);
47073
+ let turnStart = 0;
47074
+ const history = HISTORY_OPEN.exec(tail);
47075
+ if (history) {
47076
+ const closeTag = `</${history[1]}>`;
47077
+ const close = tail.indexOf(closeTag, history[0].length);
47078
+ if (close < 0) return null;
47079
+ turnStart = close + closeTag.length;
47080
+ }
47081
+ if (TURN_IN_DROPPED.test(rest.slice(0, pos)) || TURN_IN_DROPPED.test(tail.slice(0, turnStart))) return null;
47082
+ const turn = tail.slice(turnStart);
47083
+ if (!TURN_OPEN.test(turn)) return null;
47084
+ const turnText = turn.split("\n").filter((line) => !isNostrMetaLine(line)).join("\n").trim();
47085
+ if (!turnText) return null;
47086
+ const cleaned = `<context>
47087
+ ${contextBody}
47088
+ </context>
47089
+
47090
+ ${turnText}`;
47091
+ if (cleaned.length >= message.length) return null;
47092
+ return cleaned;
47093
+ } catch {
47094
+ return null;
47095
+ }
47096
+ }
47097
+ var EVENT_HEADER = /^(?:Event ID: [0-9a-f]{64}|Kind: \d+|Time: \d{4}-\d{2}-\d{2}T\S+|--- Event \d+ \(.*\) ---|Note: A new message arrived while you were working\..*)\s*$/;
47098
+ function buzzEmbeddingText(message) {
47099
+ try {
47100
+ if (!message.startsWith("<context>\n")) return message;
47101
+ const close = message.indexOf(CONTEXT_CLOSE);
47102
+ if (close < 0) return message;
47103
+ const turn = message.slice(close + CONTEXT_CLOSE.length);
47104
+ if (!TURN_OPEN.test(turn)) return message;
47105
+ const text = turn.split("\n").filter((line) => !EVENT_HEADER.test(line) && !isNostrMetaLine(line)).map(
47106
+ (line) => (
47107
+ // `$` 없이: 끝까지 되짚는 역추적을 막는다 (긴 줄에서 제곱 시간)
47108
+ line.replace(/^From: (.*?) \(npub:.*/, "From: $1").replace(/^Channel: (\S+) \(#[0-9a-f-]+\)/, "Channel: $1")
47109
+ )
47110
+ ).join("\n").trim();
47111
+ return text || message;
47112
+ } catch {
47113
+ return message;
47114
+ }
47115
+ }
47116
+
47117
+ // src/hot_path.ts
47118
+ var rawMessageColumnMissing = false;
47037
47119
  async function insertRawMemory(params) {
47038
47120
  const {
47039
47121
  user_id,
@@ -47053,25 +47135,26 @@ async function insertRawMemory(params) {
47053
47135
  } = params;
47054
47136
  const embeddingSql = embedding && embedding.length > 0 ? `[${embedding.join(",")}]` : null;
47055
47137
  const tagProcessed = p_tag_id !== null;
47056
- const result = await db.query(
47138
+ const cleaned = role === "user" && !is_pinned && p_tag_id === null && embeddingSql === null ? cleanBuzzEnvelope(message) : null;
47139
+ const insert = (text, raw) => db.query(
47057
47140
  `INSERT INTO memory (
47058
- user_id, agent_platform, agent_model,
47059
- subagent, subagent_model, subagent_role,
47060
- role, message,
47061
- p_tag_id, d_tag, embedding,
47062
- is_pinned, tag_processed, external_uuid,
47063
- device_name
47064
- ) VALUES (
47065
- $1, $2, $3,
47066
- $4, $5, $6,
47067
- $7, $8,
47068
- $9, $10::text[], $11::halfvec,
47069
- $12, $13, $14,
47070
- $15
47071
- )
47072
- ON CONFLICT (external_uuid) WHERE external_uuid IS NOT NULL
47073
- DO NOTHING
47074
- RETURNING id, created_at`,
47141
+ user_id, agent_platform, agent_model,
47142
+ subagent, subagent_model, subagent_role,
47143
+ role, message,
47144
+ p_tag_id, d_tag, embedding,
47145
+ is_pinned, tag_processed, external_uuid,
47146
+ device_name${raw !== null ? ", raw_message" : ""}
47147
+ ) VALUES (
47148
+ $1, $2, $3,
47149
+ $4, $5, $6,
47150
+ $7, $8,
47151
+ $9, $10::text[], $11::halfvec,
47152
+ $12, $13, $14,
47153
+ $15${raw !== null ? ", $16" : ""}
47154
+ )
47155
+ ON CONFLICT (external_uuid) WHERE external_uuid IS NOT NULL
47156
+ DO NOTHING
47157
+ RETURNING id, created_at`,
47075
47158
  [
47076
47159
  user_id,
47077
47160
  agent_platform,
@@ -47080,16 +47163,33 @@ async function insertRawMemory(params) {
47080
47163
  subagent_model,
47081
47164
  subagent_role,
47082
47165
  role,
47083
- message,
47166
+ text,
47084
47167
  p_tag_id,
47085
47168
  d_tag,
47086
47169
  embeddingSql,
47087
47170
  is_pinned,
47088
47171
  tagProcessed,
47089
47172
  external_uuid,
47090
- device_name
47173
+ device_name,
47174
+ ...raw !== null ? [raw] : []
47091
47175
  ]
47092
47176
  );
47177
+ let result;
47178
+ if (cleaned !== null && !rawMessageColumnMissing) {
47179
+ try {
47180
+ result = await insert(cleaned, message);
47181
+ } catch (err3) {
47182
+ const e = err3;
47183
+ if (e.code !== "42703" || !e.message?.includes("raw_message")) throw err3;
47184
+ rawMessageColumnMissing = true;
47185
+ console.error(
47186
+ "\u26A0\uFE0F [HotPath] memory.raw_message \uCE78\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 `mcp-agents-memory migrate` \uC2E4\uD589 \uD6C4 \uC774 \uD504\uB85C\uC138\uC2A4\uB97C \uC7AC\uC2DC\uC791\uD574\uC57C Buzz \uBD09\uD22C \uC815\uB9AC\uAC00 \uC2DC\uC791\uB429\uB2C8\uB2E4. \uADF8 \uC804\uAE4C\uC9C0\uB294 \uC6D0\uBB38 \uADF8\uB300\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4."
47187
+ );
47188
+ result = await insert(message, null);
47189
+ }
47190
+ } else {
47191
+ result = await insert(message, null);
47192
+ }
47093
47193
  if (result.rows.length === 0) {
47094
47194
  const existing = await db.query(
47095
47195
  `SELECT id, created_at FROM memory WHERE external_uuid = $1 LIMIT 1`,
@@ -60397,7 +60497,7 @@ async function processOne(client2, row) {
60397
60497
  promises.push(
60398
60498
  (async () => {
60399
60499
  try {
60400
- embedding = await embedMessage(row.message);
60500
+ embedding = await embedMessage(buzzEmbeddingText(row.message));
60401
60501
  } catch (err3) {
60402
60502
  embedError = err3;
60403
60503
  }