@arkimedehq/openclaw-recordare 0.1.0 → 0.2.0

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/index.js CHANGED
@@ -97,7 +97,7 @@ var require_code = __commonJS({
97
97
  }
98
98
  exports._ = _;
99
99
  var plus = new _Code("+");
100
- function str2(strs, ...args) {
100
+ function str3(strs, ...args) {
101
101
  const expr = [safeStringify(strs[0])];
102
102
  let i = 0;
103
103
  while (i < args.length) {
@@ -108,7 +108,7 @@ var require_code = __commonJS({
108
108
  optimize(expr);
109
109
  return new _Code(expr);
110
110
  }
111
- exports.str = str2;
111
+ exports.str = str3;
112
112
  function addCodeArg(code, arg) {
113
113
  if (arg instanceof _Code)
114
114
  code.push(...arg._items);
@@ -151,7 +151,7 @@ var require_code = __commonJS({
151
151
  return;
152
152
  }
153
153
  function strConcat(c1, c2) {
154
- return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str2`${c1}${c2}`;
154
+ return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str3`${c1}${c2}`;
155
155
  }
156
156
  exports.strConcat = strConcat;
157
157
  function interpolate(x) {
@@ -865,12 +865,12 @@ var require_codegen = __commonJS({
865
865
  }
866
866
  // `for-in` statement.
867
867
  // With option `ownProperties` replaced with a `for-of` loop for object keys
868
- forIn(nameOrPrefix, obj2, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.const) {
868
+ forIn(nameOrPrefix, obj, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.const) {
869
869
  if (this.opts.ownProperties) {
870
- return this.forOf(nameOrPrefix, (0, code_1._)`Object.keys(${obj2})`, forBody);
870
+ return this.forOf(nameOrPrefix, (0, code_1._)`Object.keys(${obj})`, forBody);
871
871
  }
872
872
  const name = this._scope.toName(nameOrPrefix);
873
- return this._for(new ForIter("in", varKind, name, obj2), () => forBody(name));
873
+ return this._for(new ForIter("in", varKind, name, obj), () => forBody(name));
874
874
  }
875
875
  // end `for` loop
876
876
  endFor() {
@@ -1113,22 +1113,22 @@ var require_util = __commonJS({
1113
1113
  return (0, codegen_1._)`${topSchemaRef}${schemaPath}${(0, codegen_1.getProperty)(keyword)}`;
1114
1114
  }
1115
1115
  exports.schemaRefOrVal = schemaRefOrVal;
1116
- function unescapeFragment(str2) {
1117
- return unescapeJsonPointer(decodeURIComponent(str2));
1116
+ function unescapeFragment(str3) {
1117
+ return unescapeJsonPointer(decodeURIComponent(str3));
1118
1118
  }
1119
1119
  exports.unescapeFragment = unescapeFragment;
1120
- function escapeFragment(str2) {
1121
- return encodeURIComponent(escapeJsonPointer(str2));
1120
+ function escapeFragment(str3) {
1121
+ return encodeURIComponent(escapeJsonPointer(str3));
1122
1122
  }
1123
1123
  exports.escapeFragment = escapeFragment;
1124
- function escapeJsonPointer(str2) {
1125
- if (typeof str2 == "number")
1126
- return `${str2}`;
1127
- return str2.replace(/~/g, "~0").replace(/\//g, "~1");
1124
+ function escapeJsonPointer(str3) {
1125
+ if (typeof str3 == "number")
1126
+ return `${str3}`;
1127
+ return str3.replace(/~/g, "~0").replace(/\//g, "~1");
1128
1128
  }
1129
1129
  exports.escapeJsonPointer = escapeJsonPointer;
1130
- function unescapeJsonPointer(str2) {
1131
- return str2.replace(/~1/g, "/").replace(/~0/g, "~");
1130
+ function unescapeJsonPointer(str3) {
1131
+ return str3.replace(/~1/g, "/").replace(/~0/g, "~");
1132
1132
  }
1133
1133
  exports.unescapeJsonPointer = unescapeJsonPointer;
1134
1134
  function eachItem(xs, f) {
@@ -2153,8 +2153,8 @@ var require_json_schema_traverse = __commonJS({
2153
2153
  post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
2154
2154
  }
2155
2155
  }
2156
- function escapeJsonPtr(str2) {
2157
- return str2.replace(/~/g, "~0").replace(/\//g, "~1");
2156
+ function escapeJsonPtr(str3) {
2157
+ return str3.replace(/~/g, "~0").replace(/\//g, "~1");
2158
2158
  }
2159
2159
  }
2160
2160
  });
@@ -2690,11 +2690,11 @@ var require_validate = __commonJS({
2690
2690
  if (!this.allErrors)
2691
2691
  this.gen.if(cond);
2692
2692
  }
2693
- setParams(obj2, assign) {
2693
+ setParams(obj, assign) {
2694
2694
  if (assign)
2695
- Object.assign(this.params, obj2);
2695
+ Object.assign(this.params, obj);
2696
2696
  else
2697
- this.params = obj2;
2697
+ this.params = obj;
2698
2698
  }
2699
2699
  block$data(valid, codeBlock, $dataValid = codegen_1.nil) {
2700
2700
  this.gen.block(() => {
@@ -3251,10 +3251,10 @@ var require_utils = __commonJS({
3251
3251
  isIPV6: true
3252
3252
  };
3253
3253
  }
3254
- function findToken(str2, token) {
3254
+ function findToken(str3, token) {
3255
3255
  let ind = 0;
3256
- for (let i = 0; i < str2.length; i++) {
3257
- if (str2[i] === token) ind++;
3256
+ for (let i = 0; i < str3.length; i++) {
3257
+ if (str3[i] === token) ind++;
3258
3258
  }
3259
3259
  return ind;
3260
3260
  }
@@ -4268,7 +4268,7 @@ var require_core = __commonJS({
4268
4268
  var util_1 = require_util();
4269
4269
  var $dataRefSchema = require_data();
4270
4270
  var uri_1 = require_uri();
4271
- var defaultRegExp = (str2, flags) => new RegExp(str2, flags);
4271
+ var defaultRegExp = (str3, flags) => new RegExp(str3, flags);
4272
4272
  defaultRegExp.code = "new RegExp";
4273
4273
  var META_IGNORE_OPTIONS = ["removeAdditional", "useDefaults", "coerceTypes"];
4274
4274
  var EXT_SCOPE_NAMES = /* @__PURE__ */ new Set([
@@ -5063,16 +5063,16 @@ var require_ucs2length = __commonJS({
5063
5063
  "../../packages/client/node_modules/ajv/dist/runtime/ucs2length.js"(exports) {
5064
5064
  "use strict";
5065
5065
  Object.defineProperty(exports, "__esModule", { value: true });
5066
- function ucs2length(str2) {
5067
- const len = str2.length;
5066
+ function ucs2length(str3) {
5067
+ const len = str3.length;
5068
5068
  let length = 0;
5069
5069
  let pos = 0;
5070
5070
  let value;
5071
5071
  while (pos < len) {
5072
5072
  length++;
5073
- value = str2.charCodeAt(pos++);
5073
+ value = str3.charCodeAt(pos++);
5074
5074
  if (value >= 55296 && value <= 56319 && pos < len) {
5075
- value = str2.charCodeAt(pos);
5075
+ value = str3.charCodeAt(pos);
5076
5076
  if ((value & 64512) === 56320)
5077
5077
  pos++;
5078
5078
  }
@@ -6955,8 +6955,8 @@ var require_formats = __commonJS({
6955
6955
  }
6956
6956
  var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
6957
6957
  var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
6958
- function date4(str2) {
6959
- const matches = DATE.exec(str2);
6958
+ function date4(str3) {
6959
+ const matches = DATE.exec(str3);
6960
6960
  if (!matches)
6961
6961
  return false;
6962
6962
  const year = +matches[1];
@@ -6975,8 +6975,8 @@ var require_formats = __commonJS({
6975
6975
  }
6976
6976
  var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
6977
6977
  function getTime(strictTimeZone) {
6978
- return function time3(str2) {
6979
- const matches = TIME.exec(str2);
6978
+ return function time3(str3) {
6979
+ const matches = TIME.exec(str3);
6980
6980
  if (!matches)
6981
6981
  return false;
6982
6982
  const hr = +matches[1];
@@ -7022,8 +7022,8 @@ var require_formats = __commonJS({
7022
7022
  var DATE_TIME_SEPARATOR = /t|\s/i;
7023
7023
  function getDateTime(strictTimeZone) {
7024
7024
  const time3 = getTime(strictTimeZone);
7025
- return function date_time(str2) {
7026
- const dateTime = str2.split(DATE_TIME_SEPARATOR);
7025
+ return function date_time(str3) {
7026
+ const dateTime = str3.split(DATE_TIME_SEPARATOR);
7027
7027
  return dateTime.length === 2 && date4(dateTime[0]) && time3(dateTime[1]);
7028
7028
  };
7029
7029
  }
@@ -7048,13 +7048,13 @@ var require_formats = __commonJS({
7048
7048
  }
7049
7049
  var NOT_URI_FRAGMENT = /\/|:/;
7050
7050
  var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
7051
- function uri(str2) {
7052
- return NOT_URI_FRAGMENT.test(str2) && URI.test(str2);
7051
+ function uri(str3) {
7052
+ return NOT_URI_FRAGMENT.test(str3) && URI.test(str3);
7053
7053
  }
7054
7054
  var BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
7055
- function byte(str2) {
7055
+ function byte(str3) {
7056
7056
  BYTE.lastIndex = 0;
7057
- return BYTE.test(str2);
7057
+ return BYTE.test(str3);
7058
7058
  }
7059
7059
  var MIN_INT32 = -(2 ** 31);
7060
7060
  var MAX_INT32 = 2 ** 31 - 1;
@@ -7068,11 +7068,11 @@ var require_formats = __commonJS({
7068
7068
  return true;
7069
7069
  }
7070
7070
  var Z_ANCHOR = /[^\\]\\Z/;
7071
- function regex(str2) {
7072
- if (Z_ANCHOR.test(str2))
7071
+ function regex(str3) {
7072
+ if (Z_ANCHOR.test(str3))
7073
7073
  return false;
7074
7074
  try {
7075
- new RegExp(str2);
7075
+ new RegExp(str3);
7076
7076
  return true;
7077
7077
  } catch (e) {
7078
7078
  return false;
@@ -7207,25 +7207,25 @@ var require_content_type = __commonJS({
7207
7207
  var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
7208
7208
  exports.format = format;
7209
7209
  exports.parse = parse3;
7210
- function format(obj2) {
7211
- if (!obj2 || typeof obj2 !== "object") {
7210
+ function format(obj) {
7211
+ if (!obj || typeof obj !== "object") {
7212
7212
  throw new TypeError("argument obj is required");
7213
7213
  }
7214
- var parameters = obj2.parameters;
7215
- var type = obj2.type;
7214
+ var parameters2 = obj.parameters;
7215
+ var type = obj.type;
7216
7216
  if (!type || !TYPE_REGEXP.test(type)) {
7217
7217
  throw new TypeError("invalid type");
7218
7218
  }
7219
7219
  var string4 = type;
7220
- if (parameters && typeof parameters === "object") {
7220
+ if (parameters2 && typeof parameters2 === "object") {
7221
7221
  var param;
7222
- var params = Object.keys(parameters).sort();
7222
+ var params = Object.keys(parameters2).sort();
7223
7223
  for (var i = 0; i < params.length; i++) {
7224
7224
  param = params[i];
7225
7225
  if (!TOKEN_REGEXP.test(param)) {
7226
7226
  throw new TypeError("invalid parameter name");
7227
7227
  }
7228
- string4 += "; " + param + "=" + qstring(parameters[param]);
7228
+ string4 += "; " + param + "=" + qstring(parameters2[param]);
7229
7229
  }
7230
7230
  }
7231
7231
  return string4;
@@ -7243,7 +7243,7 @@ var require_content_type = __commonJS({
7243
7243
  if (!TYPE_REGEXP.test(type)) {
7244
7244
  throw new TypeError("invalid media type");
7245
7245
  }
7246
- var obj2 = new ContentType(type.toLowerCase());
7246
+ var obj = new ContentType(type.toLowerCase());
7247
7247
  if (index !== -1) {
7248
7248
  var key;
7249
7249
  var match;
@@ -7262,20 +7262,20 @@ var require_content_type = __commonJS({
7262
7262
  value = value.replace(QESC_REGEXP, "$1");
7263
7263
  }
7264
7264
  }
7265
- obj2.parameters[key] = value;
7265
+ obj.parameters[key] = value;
7266
7266
  }
7267
7267
  if (index !== header.length) {
7268
7268
  throw new TypeError("invalid parameter format");
7269
7269
  }
7270
7270
  }
7271
- return obj2;
7271
+ return obj;
7272
7272
  }
7273
- function getcontenttype(obj2) {
7273
+ function getcontenttype(obj) {
7274
7274
  var header;
7275
- if (typeof obj2.getHeader === "function") {
7276
- header = obj2.getHeader("content-type");
7277
- } else if (typeof obj2.headers === "object") {
7278
- header = obj2.headers && obj2.headers["content-type"];
7275
+ if (typeof obj.getHeader === "function") {
7276
+ header = obj.getHeader("content-type");
7277
+ } else if (typeof obj.headers === "object") {
7278
+ header = obj.headers && obj.headers["content-type"];
7279
7279
  }
7280
7280
  if (typeof header !== "string") {
7281
7281
  throw new TypeError("content-type header is missing from object");
@@ -7283,14 +7283,14 @@ var require_content_type = __commonJS({
7283
7283
  return header;
7284
7284
  }
7285
7285
  function qstring(val) {
7286
- var str2 = String(val);
7287
- if (TOKEN_REGEXP.test(str2)) {
7288
- return str2;
7286
+ var str3 = String(val);
7287
+ if (TOKEN_REGEXP.test(str3)) {
7288
+ return str3;
7289
7289
  }
7290
- if (str2.length > 0 && !TEXT_REGEXP.test(str2)) {
7290
+ if (str3.length > 0 && !TEXT_REGEXP.test(str3)) {
7291
7291
  throw new TypeError("invalid parameter value");
7292
7292
  }
7293
- return '"' + str2.replace(QUOTE_REGEXP, "\\$1") + '"';
7293
+ return '"' + str3.replace(QUOTE_REGEXP, "\\$1") + '"';
7294
7294
  }
7295
7295
  function ContentType(type) {
7296
7296
  this.parameters = /* @__PURE__ */ Object.create(null);
@@ -7318,12 +7318,15 @@ function parseConfig(raw, env = process.env) {
7318
7318
  if (user) users[k.trim()] = user;
7319
7319
  }
7320
7320
  }
7321
+ const selfSenders = Array.isArray(c.selfSenders) ? c.selfSenders.map(str).filter((v) => !!v) : [];
7321
7322
  const personal = apiKey.startsWith("rp_");
7322
7323
  return {
7323
7324
  url: url2,
7324
7325
  apiKey,
7326
+ memoryPer: c.memoryPer === "user" ? "user" : "agent",
7327
+ selfSenders,
7325
7328
  users,
7326
- // A personal token is one person: with no mapping at all, every turn is theirs (single-person install).
7329
+ // A personal token is one memory (the user header is ignored): any non-empty value stands for it.
7327
7330
  defaultUser: str(c.defaultUser) ?? (personal ? "me" : void 0),
7328
7331
  autoRecall: bool(c.autoRecall, true),
7329
7332
  capture: bool(c.capture, true),
@@ -7342,6 +7345,7 @@ var USER_HEADER = "X-Recordare-User";
7342
7345
  var CONVERSATION_HEADER = "X-Recordare-Conversation";
7343
7346
  var MAX_CONTENT_BYTES = 64 * 1024;
7344
7347
  var MAX_MESSAGES_PER_REQUEST = 500;
7348
+ var SOURCE_PART_BYTES = 4 * 1024 * 1024;
7345
7349
  function clipUtf8(text, maxBytes = MAX_CONTENT_BYTES, marker = " \u2026[truncated]") {
7346
7350
  const bytes = Buffer.from(text, "utf8");
7347
7351
  if (bytes.length <= maxBytes) return text;
@@ -7368,7 +7372,7 @@ var RecordareUnavailableError = class extends Error {
7368
7372
  };
7369
7373
  var MemoryNotEmptyError = class extends Error {
7370
7374
  constructor() {
7371
- super("The memory kind can change only while the memory is empty");
7375
+ super("The memory mode can change only while the memory is empty");
7372
7376
  this.name = "MemoryNotEmptyError";
7373
7377
  }
7374
7378
  };
@@ -7601,8 +7605,8 @@ function defineLazy(object3, key, getter) {
7601
7605
  configurable: true
7602
7606
  });
7603
7607
  }
7604
- function objectClone(obj2) {
7605
- return Object.create(Object.getPrototypeOf(obj2), Object.getOwnPropertyDescriptors(obj2));
7608
+ function objectClone(obj) {
7609
+ return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
7606
7610
  }
7607
7611
  function assignProp(target, prop, value) {
7608
7612
  Object.defineProperty(target, prop, {
@@ -7673,10 +7677,10 @@ function mergeDefs(...defs) {
7673
7677
  function cloneDef(schema) {
7674
7678
  return mergeDefs(schema._zod.def);
7675
7679
  }
7676
- function getElementAtPath(obj2, path) {
7680
+ function getElementAtPath(obj, path) {
7677
7681
  if (!path)
7678
- return obj2;
7679
- return path.reduce((acc, key) => acc?.[key], obj2);
7682
+ return obj;
7683
+ return path.reduce((acc, key) => acc?.[key], obj);
7680
7684
  }
7681
7685
  function promiseAllObject(promisesObj) {
7682
7686
  const keys = Object.keys(promisesObj);
@@ -7691,14 +7695,14 @@ function promiseAllObject(promisesObj) {
7691
7695
  }
7692
7696
  function randomString(length = 10) {
7693
7697
  const chars = "abcdefghijklmnopqrstuvwxyz";
7694
- let str2 = "";
7698
+ let str3 = "";
7695
7699
  for (let i = 0; i < length; i++) {
7696
- str2 += chars[Math.floor(Math.random() * chars.length)];
7700
+ str3 += chars[Math.floor(Math.random() * chars.length)];
7697
7701
  }
7698
- return str2;
7702
+ return str3;
7699
7703
  }
7700
- function esc(str2) {
7701
- return JSON.stringify(str2);
7704
+ function esc(str3) {
7705
+ return JSON.stringify(str3);
7702
7706
  }
7703
7707
  function slugify(input) {
7704
7708
  return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -7812,8 +7816,8 @@ var primitiveTypes = /* @__PURE__ */ new Set([
7812
7816
  "symbol",
7813
7817
  "undefined"
7814
7818
  ]);
7815
- function escapeRegex(str2) {
7816
- return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7819
+ function escapeRegex(str3) {
7820
+ return str3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7817
7821
  }
7818
7822
  function clone(inst, def, params) {
7819
7823
  const cl = new inst._zod.constr(def ?? inst._zod.def);
@@ -8067,13 +8071,13 @@ function getSizableOrigin(input) {
8067
8071
  return "unknown";
8068
8072
  }
8069
8073
  var highSurrogate = /[\uD800-\uDBFF]/;
8070
- function codePointLength(str2) {
8071
- const units = str2.length;
8072
- if (!highSurrogate.test(str2))
8074
+ function codePointLength(str3) {
8075
+ const units = str3.length;
8076
+ if (!highSurrogate.test(str3))
8073
8077
  return units;
8074
8078
  let count = units;
8075
8079
  for (let i = 0; i < units - 1; i++) {
8076
- if ((str2.charCodeAt(i) & 64512) === 55296 && (str2.charCodeAt(i + 1) & 64512) === 56320) {
8080
+ if ((str3.charCodeAt(i) & 64512) === 55296 && (str3.charCodeAt(i + 1) & 64512) === 56320) {
8077
8081
  count--;
8078
8082
  i++;
8079
8083
  }
@@ -8100,9 +8104,9 @@ function parsedType(data) {
8100
8104
  if (Array.isArray(data)) {
8101
8105
  return "array";
8102
8106
  }
8103
- const obj2 = data;
8104
- if (obj2 && Object.getPrototypeOf(obj2) !== Object.prototype && "constructor" in obj2 && obj2.constructor) {
8105
- return obj2.constructor.name;
8107
+ const obj = data;
8108
+ if (obj && Object.getPrototypeOf(obj) !== Object.prototype && "constructor" in obj && obj.constructor) {
8109
+ return obj.constructor.name;
8106
8110
  }
8107
8111
  }
8108
8112
  }
@@ -8120,8 +8124,8 @@ function issue(...args) {
8120
8124
  }
8121
8125
  return { ...iss };
8122
8126
  }
8123
- function cleanEnum(obj2) {
8124
- return Object.entries(obj2).filter(([k, _]) => {
8127
+ function cleanEnum(obj) {
8128
+ return Object.entries(obj).filter(([k, _]) => {
8125
8129
  return Number.isNaN(Number.parseInt(k, 10));
8126
8130
  }).map((el) => el[1]);
8127
8131
  }
@@ -8445,15 +8449,15 @@ var $ZodError = $constructor("$ZodError", initializer);
8445
8449
  var $ZodRealError = $constructor("$ZodError", initializer, void 0, {
8446
8450
  Parent: Error
8447
8451
  });
8448
- function node(obj2, key, make) {
8449
- if (!Object.prototype.hasOwnProperty.call(obj2, key)) {
8452
+ function node(obj, key, make) {
8453
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
8450
8454
  if (key === "__proto__") {
8451
- Object.defineProperty(obj2, key, { value: make(), writable: true, enumerable: true, configurable: true });
8455
+ Object.defineProperty(obj, key, { value: make(), writable: true, enumerable: true, configurable: true });
8452
8456
  } else {
8453
- obj2[key] = make();
8457
+ obj[key] = make();
8454
8458
  }
8455
8459
  }
8456
- return obj2[key];
8460
+ return obj[key];
8457
8461
  }
8458
8462
  function flattenError(error2, mapper = (issue2) => issue2.message) {
8459
8463
  const fieldErrors = {};
@@ -16875,15 +16879,15 @@ function applyElicitationDefaults(schema, data) {
16875
16879
  if (!schema || data === null || typeof data !== "object")
16876
16880
  return;
16877
16881
  if (schema.type === "object" && schema.properties && typeof schema.properties === "object") {
16878
- const obj2 = data;
16882
+ const obj = data;
16879
16883
  const props = schema.properties;
16880
16884
  for (const key of Object.keys(props)) {
16881
16885
  const propSchema = props[key];
16882
- if (obj2[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
16883
- obj2[key] = propSchema.default;
16886
+ if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
16887
+ obj[key] = propSchema.default;
16884
16888
  }
16885
- if (obj2[key] !== void 0) {
16886
- applyElicitationDefaults(propSchema, obj2[key]);
16889
+ if (obj[key] !== void 0) {
16890
+ applyElicitationDefaults(propSchema, obj[key]);
16887
16891
  }
16888
16892
  }
16889
16893
  }
@@ -19066,7 +19070,7 @@ var RecordareMcp = class {
19066
19070
  },
19067
19071
  requestInit: { headers: { ...this.http.headers(user), [CONVERSATION_HEADER]: conversation } }
19068
19072
  });
19069
- const client = new Client(this.options.clientInfo ?? { name: "recordare-client", version: "0.1.0" });
19073
+ const client = new Client(this.options.clientInfo ?? { name: "recordare-client", version: "0.2.0" });
19070
19074
  await client.connect(transport);
19071
19075
  return client;
19072
19076
  }
@@ -19092,11 +19096,11 @@ var RecordareClient = class {
19092
19096
  this.http = new Http(options);
19093
19097
  this.mcp = new RecordareMcp(this.http, options.mcp);
19094
19098
  }
19095
- /** The person behind `user` (auto-provisioned when the client allows it), their consent and kind of memory. */
19099
+ /** The memory behind `user` (auto-provisioned when the client allows it), its mode and gender. */
19096
19100
  me(user) {
19097
19101
  return this.http.request("GET", "api/v1/me", { user });
19098
19102
  }
19099
- /** The person's settings from the platform: the name (keep it in sync on every rename) and the kind of memory. */
19103
+ /** The memory's settings from the platform: the name (keep it in sync on every rename), the mode and the gender. */
19100
19104
  async updateMe(user, settings) {
19101
19105
  try {
19102
19106
  await this.http.request("PATCH", "api/v1/me", { user, body: settings });
@@ -19107,10 +19111,10 @@ var RecordareClient = class {
19107
19111
  }
19108
19112
  /**
19109
19113
  * Sends messages of one conversation, split into requests of at most MAX_MESSAGES_PER_REQUEST. Idempotent: Recordare
19110
- * deduplicates on each message's externalId. Before consent nothing is stored (`stored: false`).
19114
+ * deduplicates on each message's externalId. Recordare always stores (D50): the on/off switch is the platform's.
19111
19115
  */
19112
19116
  async ingest(user, req) {
19113
- const total = { conversationId: null, accepted: 0, duplicates: 0, conflicts: [], stored: true };
19117
+ const total = { conversationId: null, accepted: 0, duplicates: 0, conflicts: [] };
19114
19118
  for (let i = 0; i < req.messages.length; i += MAX_MESSAGES_PER_REQUEST) {
19115
19119
  const last = i + MAX_MESSAGES_PER_REQUEST >= req.messages.length;
19116
19120
  const part = await this.http.request("POST", "api/v1/ingest/messages", {
@@ -19126,7 +19130,6 @@ var RecordareClient = class {
19126
19130
  total.accepted += part.accepted;
19127
19131
  total.duplicates += part.duplicates;
19128
19132
  total.conflicts.push(...part.conflicts);
19129
- total.stored &&= part.stored;
19130
19133
  }
19131
19134
  return total;
19132
19135
  }
@@ -19138,6 +19141,17 @@ var RecordareClient = class {
19138
19141
  context(user, conversation, query) {
19139
19142
  return this.http.request("POST", "api/v1/context", { user, body: { query }, headers: { [CONVERSATION_HEADER]: conversation } });
19140
19143
  }
19144
+ /**
19145
+ * Stores the turn and returns the memory context for it in one round trip (needs the `ingest` and `read` scopes):
19146
+ * the context is computed for the ingested conversation, from `query` or else the turn's last user message.
19147
+ */
19148
+ contextWithTurn(user, turn, query) {
19149
+ return this.http.request("POST", "api/v1/context", { user, body: { ingest: turn, ...query ? { query } : {} } });
19150
+ }
19151
+ /** The conversation ended (session closed, /new): extraction runs now. A conversation Recordare never had is done. */
19152
+ async endConversation(user, conversation) {
19153
+ await this.gone(this.http.request("POST", `api/v1/ingest/conversations/${enc(conversation)}/end`, { user }));
19154
+ }
19141
19155
  /** An edited message: Recordare re-extracts what depended on it. */
19142
19156
  async editMessage(user, conversation, message, content) {
19143
19157
  await this.http.request("PATCH", `api/v1/ingest/conversations/${enc(conversation)}/messages/${enc(message)}`, { user, body: { content } });
@@ -19150,6 +19164,32 @@ var RecordareClient = class {
19150
19164
  async deleteConversation(user, conversation) {
19151
19165
  await this.gone(this.http.request("DELETE", `api/v1/ingest/conversations/${enc(conversation)}`, { user }));
19152
19166
  }
19167
+ // ── Learned sources (WORK_PLAN 8.9, D49): text the agent learns — the client turns files into text ─────────────
19168
+ /**
19169
+ * The agent learns a text. A big one is sent in parts (at paragraph boundaries, `partBytes` each); any size works.
19170
+ * Sending the same `externalId` again replaces the source; the same first part again is a duplicate.
19171
+ */
19172
+ async learnSource(user, source, partBytes = SOURCE_PART_BYTES) {
19173
+ const [first = "", ...rest] = splitParts(source.text, partBytes);
19174
+ let result = await this.http.request("POST", "api/v1/ingest/sources", { user, body: { ...source, text: first, final: rest.length === 0 } });
19175
+ if (result.duplicate) return result;
19176
+ for (const [i, text] of rest.entries()) {
19177
+ result = await this.http.request(
19178
+ "POST",
19179
+ `api/v1/ingest/sources/${enc(source.externalId)}/parts`,
19180
+ { user, body: { part: i + 1, text, final: i === rest.length - 1 } }
19181
+ );
19182
+ }
19183
+ return result;
19184
+ }
19185
+ /** The agent forgets a source (its text and passages; episodes keep a "forgotten source" marker). One it never had counts as done. */
19186
+ async forgetSource(user, externalId) {
19187
+ await this.http.request("DELETE", `api/v1/ingest/sources/${enc(externalId)}`, { user });
19188
+ }
19189
+ /** What the agent learned, newest first. */
19190
+ sources(user) {
19191
+ return this.http.request("GET", "api/v1/sources", { user });
19192
+ }
19153
19193
  // ── The diary (API.md §4): what Recordare remembers, shown to the person in the platform's UI ──────────────────
19154
19194
  /** The timeline, newest first; pass `nextCursor` back as `cursor` for the next page. */
19155
19195
  episodes(user, query = {}) {
@@ -19202,6 +19242,319 @@ var RecordareClient = class {
19202
19242
  }
19203
19243
  }
19204
19244
  };
19245
+ function splitParts(text, maxBytes) {
19246
+ const size = (t) => Buffer.byteLength(t, "utf8");
19247
+ if (size(text) <= maxBytes) return [text];
19248
+ const parts = [];
19249
+ let current = "";
19250
+ const push = (piece) => {
19251
+ const joined = current ? `${current}
19252
+
19253
+ ${piece}` : piece;
19254
+ if (size(joined) <= maxBytes) {
19255
+ current = joined;
19256
+ return;
19257
+ }
19258
+ if (current) parts.push(current);
19259
+ current = piece;
19260
+ };
19261
+ for (const paragraph of text.split(/\n\s*\n/)) {
19262
+ let rest = paragraph;
19263
+ while (size(rest) > maxBytes) {
19264
+ let end = rest.length;
19265
+ while (end > 0 && size(rest.slice(0, end)) > maxBytes) end = Math.floor(end * 0.9);
19266
+ const space = rest.lastIndexOf(" ", end);
19267
+ let cut = space > end / 2 ? space : end;
19268
+ if (/[\uD800-\uDBFF]/.test(rest.charAt(cut - 1))) cut--;
19269
+ push(rest.slice(0, cut));
19270
+ rest = rest.slice(cut).trimStart();
19271
+ }
19272
+ if (rest) push(rest);
19273
+ }
19274
+ if (current) parts.push(current);
19275
+ return parts;
19276
+ }
19277
+
19278
+ // ../../packages/client/src/tools.ts
19279
+ var TOOLS = [
19280
+ {
19281
+ "name": "correct_episode",
19282
+ "title": "Correct a memory",
19283
+ "description": "Correct a remembered episode (wrong date or detail). The old version is kept as history, never shown as current.",
19284
+ "inputSchema": {
19285
+ "type": "object",
19286
+ "properties": {
19287
+ "id": {
19288
+ "type": "string",
19289
+ "format": "uuid",
19290
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19291
+ },
19292
+ "content": {
19293
+ "type": "string"
19294
+ },
19295
+ "occurred_at": {
19296
+ "type": "string",
19297
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19298
+ },
19299
+ "date_precision": {
19300
+ "type": "string",
19301
+ "enum": [
19302
+ "day",
19303
+ "month",
19304
+ "year",
19305
+ "approximate"
19306
+ ]
19307
+ }
19308
+ },
19309
+ "required": [
19310
+ "id"
19311
+ ],
19312
+ "$schema": "http://json-schema.org/draft-07/schema#"
19313
+ }
19314
+ },
19315
+ {
19316
+ "name": "forget_episode",
19317
+ "title": "Forget a memory",
19318
+ "description": "Forget an episode, when asked to. It is deleted with its corrections and never recreated.",
19319
+ "inputSchema": {
19320
+ "type": "object",
19321
+ "properties": {
19322
+ "id": {
19323
+ "type": "string",
19324
+ "format": "uuid",
19325
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19326
+ }
19327
+ },
19328
+ "required": [
19329
+ "id"
19330
+ ],
19331
+ "$schema": "http://json-schema.org/draft-07/schema#"
19332
+ }
19333
+ },
19334
+ {
19335
+ "name": "learn_source",
19336
+ "title": "Learn a text",
19337
+ "description": "Learn a text as knowledge (a manual, a page, a note \u2014 as plain text; send it again with the same title to replace it). It stays searchable with search_knowledge; the learning becomes a memory of this conversation.",
19338
+ "inputSchema": {
19339
+ "type": "object",
19340
+ "properties": {
19341
+ "title": {
19342
+ "type": "string"
19343
+ },
19344
+ "text": {
19345
+ "type": "string"
19346
+ },
19347
+ "author": {
19348
+ "type": "string"
19349
+ },
19350
+ "kind": {
19351
+ "type": "string",
19352
+ "enum": [
19353
+ "document",
19354
+ "page",
19355
+ "note",
19356
+ "book",
19357
+ "own_text"
19358
+ ]
19359
+ },
19360
+ "uri": {
19361
+ "type": "string"
19362
+ }
19363
+ },
19364
+ "required": [
19365
+ "title",
19366
+ "text"
19367
+ ],
19368
+ "$schema": "http://json-schema.org/draft-07/schema#"
19369
+ }
19370
+ },
19371
+ {
19372
+ "name": "log_episode",
19373
+ "title": "Note something that happened or is planned",
19374
+ "description": 'Explicit capture ("note that today I serviced the car"). Resolve the date yourself (ISO).',
19375
+ "inputSchema": {
19376
+ "type": "object",
19377
+ "properties": {
19378
+ "content": {
19379
+ "type": "string"
19380
+ },
19381
+ "kind": {
19382
+ "type": "string",
19383
+ "enum": [
19384
+ "event",
19385
+ "plan"
19386
+ ]
19387
+ },
19388
+ "occurred_at": {
19389
+ "type": "string",
19390
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19391
+ },
19392
+ "occurred_until": {
19393
+ "type": "string",
19394
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19395
+ },
19396
+ "date_precision": {
19397
+ "type": "string",
19398
+ "enum": [
19399
+ "day",
19400
+ "month",
19401
+ "year",
19402
+ "approximate"
19403
+ ]
19404
+ },
19405
+ "people": {
19406
+ "type": "array",
19407
+ "items": {
19408
+ "type": "string"
19409
+ }
19410
+ },
19411
+ "place": {
19412
+ "type": "string"
19413
+ }
19414
+ },
19415
+ "required": [
19416
+ "content"
19417
+ ],
19418
+ "$schema": "http://json-schema.org/draft-07/schema#"
19419
+ }
19420
+ },
19421
+ {
19422
+ "name": "remember",
19423
+ "title": "Remember something",
19424
+ "description": 'Explicit "remember that\u2026" about preferences, habits, values, knowledge.',
19425
+ "inputSchema": {
19426
+ "type": "object",
19427
+ "properties": {
19428
+ "content": {
19429
+ "type": "string"
19430
+ },
19431
+ "category": {
19432
+ "type": "string",
19433
+ "enum": [
19434
+ "preference",
19435
+ "habit",
19436
+ "value",
19437
+ "relationship",
19438
+ "knowledge",
19439
+ "profile",
19440
+ "constraint"
19441
+ ]
19442
+ }
19443
+ },
19444
+ "required": [
19445
+ "content"
19446
+ ],
19447
+ "$schema": "http://json-schema.org/draft-07/schema#"
19448
+ }
19449
+ },
19450
+ {
19451
+ "name": "resolve_period",
19452
+ "title": "Turn a period expression into dates",
19453
+ "description": 'Deterministic: "questa settimana", "la settimana scorsa", "a febbraio", "lo scorso dicembre", "last week"\u2026 \u2192 {from, to} (ISO, inclusive).',
19454
+ "inputSchema": {
19455
+ "type": "object",
19456
+ "properties": {
19457
+ "expression": {
19458
+ "type": "string"
19459
+ }
19460
+ },
19461
+ "required": [
19462
+ "expression"
19463
+ ],
19464
+ "$schema": "http://json-schema.org/draft-07/schema#"
19465
+ }
19466
+ },
19467
+ {
19468
+ "name": "search_episodes",
19469
+ "title": "Search what happened",
19470
+ "description": 'Search your memory of what happened: what you lived, did, planned or learned, and what happened to the people you know (events, plans, changes), with dates and status. Each item has a subject: you (written in the first person), a person by name, someone, or undecided. Use `from`/`to` (ISO dates, inclusive; see resolve_period) for questions about a period. mode: "search" = most relevant, "list" = chronological in the period (overviews, counting), "latest" = most recent first ("when did I last\u2026").',
19471
+ "inputSchema": {
19472
+ "type": "object",
19473
+ "properties": {
19474
+ "query": {
19475
+ "description": "What to look for \u2014 pass the question also when listing a period: it ranks the items and finds the matching chat excerpts",
19476
+ "type": "string"
19477
+ },
19478
+ "from": {
19479
+ "description": "Start date, ISO (YYYY-MM-DD or YYYY-MM)",
19480
+ "type": "string",
19481
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19482
+ },
19483
+ "to": {
19484
+ "description": "End date, ISO (YYYY-MM-DD or YYYY-MM), inclusive",
19485
+ "type": "string",
19486
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19487
+ },
19488
+ "mode": {
19489
+ "type": "string",
19490
+ "enum": [
19491
+ "search",
19492
+ "list",
19493
+ "latest"
19494
+ ]
19495
+ },
19496
+ "include_plans": {
19497
+ "type": "boolean"
19498
+ },
19499
+ "limit": {
19500
+ "type": "integer",
19501
+ "minimum": 1,
19502
+ "maximum": 50
19503
+ }
19504
+ },
19505
+ "$schema": "http://json-schema.org/draft-07/schema#"
19506
+ }
19507
+ },
19508
+ {
19509
+ "name": "search_knowledge",
19510
+ "title": "Search what you learned",
19511
+ "description": "Search the sources you learned (manuals, documents, pages, notes you were given or wrote): passages of their text, each with its source (title, author, who gave it, when) and the episodes that refer to it. For what happened, use search_episodes.",
19512
+ "inputSchema": {
19513
+ "type": "object",
19514
+ "properties": {
19515
+ "query": {
19516
+ "type": "string",
19517
+ "description": "What to look up"
19518
+ },
19519
+ "limit": {
19520
+ "type": "integer",
19521
+ "minimum": 1,
19522
+ "maximum": 20
19523
+ }
19524
+ },
19525
+ "required": [
19526
+ "query"
19527
+ ],
19528
+ "$schema": "http://json-schema.org/draft-07/schema#"
19529
+ }
19530
+ },
19531
+ {
19532
+ "name": "search_memory",
19533
+ "title": "Search what you know about yourself and others",
19534
+ "description": 'Search your memory of preferences, habits, values, relationships, knowledge and current state (car, home, job\u2026) \u2014 yours and of the people you know; each item has its subject. Use `as_of` (ISO date) for "what was it on that date" questions; each fact comes with its history.',
19535
+ "inputSchema": {
19536
+ "type": "object",
19537
+ "properties": {
19538
+ "query": {
19539
+ "type": "string",
19540
+ "description": "Topic"
19541
+ },
19542
+ "as_of": {
19543
+ "description": "ISO date (YYYY-MM-DD); default today",
19544
+ "type": "string",
19545
+ "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$"
19546
+ },
19547
+ "include_pending": {
19548
+ "type": "boolean"
19549
+ }
19550
+ },
19551
+ "required": [
19552
+ "query"
19553
+ ],
19554
+ "$schema": "http://json-schema.org/draft-07/schema#"
19555
+ }
19556
+ }
19557
+ ];
19205
19558
 
19206
19559
  // ../../packages/client/src/delivery.ts
19207
19560
  var DEFAULT_DELIVERY = { maxAttempts: 12, baseDelayMs: 5e3, maxDelayMs: 60 * 60 * 1e3 };
@@ -19218,6 +19571,7 @@ function afterFailure(err, attempts, policy = DEFAULT_DELIVERY, random2 = Math.r
19218
19571
 
19219
19572
  // src/identity.ts
19220
19573
  function resolveUser(cfg, channel, senderId) {
19574
+ if (cfg.memoryPer === "agent") return cfg.defaultUser;
19221
19575
  if (senderId) {
19222
19576
  const mapped = channel ? cfg.users[`${channel}:${senderId}`] : void 0;
19223
19577
  if (mapped) return mapped;
@@ -19225,6 +19579,22 @@ function resolveUser(cfg, channel, senderId) {
19225
19579
  }
19226
19580
  return cfg.defaultUser;
19227
19581
  }
19582
+ var senderRef = (channel, senderId) => `${channel ?? "openclaw"}:${senderId}`;
19583
+ function senderParticipant(channel, senderId, displayName) {
19584
+ return {
19585
+ ref: senderRef(channel, senderId),
19586
+ role: "other",
19587
+ identity: { channel: channel ?? "openclaw", externalId: senderId },
19588
+ ...displayName ? { displayName } : {}
19589
+ };
19590
+ }
19591
+ function resolveSpeaker(cfg, channel, senderId, displayName) {
19592
+ if (cfg.memoryPer === "user" || !senderId || cfg.selfSenders.includes(senderRef(channel, senderId))) {
19593
+ return { ref: "holder", role: "user" };
19594
+ }
19595
+ const participant = senderParticipant(channel, senderId, displayName);
19596
+ return { ref: participant.ref, role: "other", participant };
19597
+ }
19228
19598
  function conversationId(sessionKey, sessionId) {
19229
19599
  if (!sessionKey && !sessionId) return void 0;
19230
19600
  return `openclaw:${sessionKey ?? "session"}${sessionId ? `/${sessionId}` : ""}`;
@@ -19237,62 +19607,19 @@ function isSystemRun(ctx) {
19237
19607
  }
19238
19608
 
19239
19609
  // src/tools.ts
19240
- var isoDay = { type: "string", pattern: "^\\d{4}-\\d{2}(-\\d{2})?$" };
19241
- var precision = { type: "string", enum: ["day", "month", "year", "approximate"] };
19242
- var uuid2 = { type: "string", description: "The episode id, from search_episodes" };
19243
- var obj = (properties, required2 = []) => ({ type: "object", properties, required: required2 });
19244
- var TOOLS = [
19245
- {
19246
- mcpName: "search_episodes",
19247
- label: "Recordare: search what happened",
19248
- description: 'Search what the user lived, did or planned (events, plans, changes), with dates and status, in the user\'s long-term memory. Use `from`/`to` (ISO dates, inclusive; see recordare_resolve_period) for questions about a period. mode: "search" = most relevant, "list" = chronological in the period (overviews, counting), "latest" = most recent first.',
19249
- parameters: obj({
19250
- query: { type: "string", description: "What to look for \u2014 pass the user's question also when listing a period" },
19251
- from: { ...isoDay, description: "Start date, ISO (YYYY-MM-DD or YYYY-MM)" },
19252
- to: { ...isoDay, description: "End date, ISO (YYYY-MM-DD or YYYY-MM), inclusive" },
19253
- mode: { type: "string", enum: ["search", "list", "latest"] },
19254
- include_plans: { type: "boolean" },
19255
- limit: { type: "integer", minimum: 1, maximum: 50 }
19256
- })
19257
- },
19258
- {
19259
- mcpName: "search_memory",
19260
- label: "Recordare: search who the user is",
19261
- description: 'Search the user\'s preferences, habits, values, relationships, knowledge and current state (car, home, job\u2026) in their long-term memory. Use `as_of` (ISO date) for "what was it on that date" questions; each fact comes with its history.',
19262
- parameters: obj({
19263
- query: { type: "string", description: "Topic" },
19264
- as_of: { ...isoDay, description: "ISO date (YYYY-MM-DD); default today" },
19265
- include_pending: { type: "boolean" }
19266
- }, ["query"])
19267
- },
19268
- {
19269
- mcpName: "resolve_period",
19270
- label: "Recordare: period to dates",
19271
- description: 'Deterministic: "this week", "last week", "in February", "last December", "la settimana scorsa"\u2026 \u2192 {from, to} (ISO, inclusive).',
19272
- parameters: obj({ expression: { type: "string" } }, ["expression"])
19273
- },
19274
- {
19275
- mcpName: "remember",
19276
- label: "Recordare: remember",
19277
- description: `Explicit "remember that\u2026" about the user's preferences, habits, values, knowledge (long-term memory).`,
19278
- parameters: obj({
19279
- content: { type: "string" },
19280
- category: { type: "string", enum: ["preference", "habit", "value", "relationship", "knowledge", "profile", "constraint"] }
19281
- }, ["content"])
19282
- },
19283
- {
19284
- mcpName: "correct_episode",
19285
- label: "Recordare: correct a memory",
19286
- description: "The user corrects a remembered episode (wrong date or detail). The old version is kept as history, never shown as current.",
19287
- parameters: obj({ id: uuid2, content: { type: "string" }, occurred_at: isoDay, date_precision: precision }, ["id"])
19288
- },
19289
- {
19290
- mcpName: "forget_episode",
19291
- label: "Recordare: forget a memory",
19292
- description: "The user asks to forget an episode. It is deleted with its corrections and never recreated.",
19293
- parameters: obj({ id: uuid2 }, ["id"])
19294
- }
19295
- ];
19610
+ var OFFERED = TOOLS.filter((t) => t.name !== "log_episode");
19611
+ var NAMES = new RegExp(`\\b(${OFFERED.map((t) => t.name).join("|")})\\b`, "g");
19612
+ function parameters(schema) {
19613
+ const { $schema: _ignored, ...rest } = structuredClone(schema);
19614
+ return rest;
19615
+ }
19616
+ var TOOLS2 = OFFERED.map((t) => ({
19617
+ mcpName: t.name,
19618
+ label: `Recordare: ${t.title.charAt(0).toLowerCase()}${t.title.slice(1)}`,
19619
+ // Tool names the description mentions are the plugin's (`recordare_…`); the memory is the agent's long-term one (D50).
19620
+ description: `${t.description.replace(NAMES, "recordare_$1")} (Recordare: your long-term memory.)`,
19621
+ parameters: parameters(t.inputSchema)
19622
+ }));
19296
19623
  var toolName = (spec) => `recordare_${spec.mcpName}`;
19297
19624
 
19298
19625
  // src/transcript.ts
@@ -19333,14 +19660,16 @@ function lastTurn(messages) {
19333
19660
  }
19334
19661
 
19335
19662
  // src/plugin.ts
19336
- var VERSION = "0.1.0";
19663
+ var VERSION = "0.2.0";
19337
19664
  var TOOL_TIMEOUT_MS = 2e4;
19338
19665
  var RETRY = { maxAttempts: 8, baseDelayMs: 2e3, maxDelayMs: 5 * 6e4 };
19339
19666
  var MAX_QUEUE = 500;
19340
19667
  var MAX_TRACKED = 500;
19341
19668
  var MAX_GROUP_BUFFER = 50;
19669
+ var MAX_NAMES = 1e3;
19342
19670
  var hash = (s) => createHash("sha256").update(s).digest("hex").slice(0, 16);
19343
19671
  var errName = (err) => err instanceof Error ? err.message : "error";
19672
+ var str2 = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
19344
19673
  function remember(map, key, value, max = MAX_TRACKED) {
19345
19674
  map.delete(key);
19346
19675
  map.set(key, value);
@@ -19362,12 +19691,19 @@ function registerRecordare(api, cfg, kinds) {
19362
19691
  const slow = new RecordareClient({ baseUrl: cfg.url, apiKey: cfg.apiKey, mcp: { clientInfo, maxSessions: 50 } });
19363
19692
  const headerUser = (user) => cfg.personal ? "" : user;
19364
19693
  const turns = /* @__PURE__ */ new Map();
19365
- const lastSent = /* @__PURE__ */ new Map();
19694
+ const captured = /* @__PURE__ */ new Map();
19366
19695
  const groupBuffer = /* @__PURE__ */ new Map();
19367
19696
  const groupParticipants = /* @__PURE__ */ new Map();
19697
+ const names = /* @__PURE__ */ new Map();
19368
19698
  const queue = [];
19369
19699
  let timer;
19370
19700
  let stopped = false;
19701
+ if (cfg.memoryPer === "agent" && !cfg.defaultUser) {
19702
+ log.warn("recordare: set defaultUser (the agent's Recordare account) or use a personal token; memory is off");
19703
+ }
19704
+ if (cfg.memoryPer === "agent" && Object.keys(cfg.users).length) {
19705
+ log.warn('recordare: `users` is used only with memoryPer "user"; every sender is a participant of the agent\'s memory');
19706
+ }
19371
19707
  async function deliver(p) {
19372
19708
  try {
19373
19709
  const res = await slow.ingest(headerUser(p.user), p.req);
@@ -19413,14 +19749,18 @@ function registerRecordare(api, cfg, kinds) {
19413
19749
  const user = resolveUser(cfg, channel, ctx.senderId);
19414
19750
  const conversation = conversationId(key, ctx.sessionId);
19415
19751
  if (!user || !conversation) return null;
19416
- return { user, conversation, channel };
19752
+ const name = ctx.senderId ? names.get(senderRef(channel, ctx.senderId)) : void 0;
19753
+ return { user, conversation, channel, speaker: resolveSpeaker(cfg, channel, ctx.senderId, name) };
19417
19754
  }
19418
19755
  function conversationMeta(w, ctx) {
19419
19756
  const participants = [
19420
- { ref: "owner", role: "owner" },
19757
+ { ref: "holder", role: "holder" },
19421
19758
  { ref: "assistant", role: "assistant", displayName: ctx.agentId ?? "assistant" },
19422
- ...ctx.sessionKey ? groupParticipants.get(ctx.sessionKey) ?? [] : []
19759
+ ...w.speaker.participant ? [w.speaker.participant] : []
19423
19760
  ];
19761
+ for (const p of ctx.sessionKey ? groupParticipants.get(ctx.sessionKey) ?? [] : []) {
19762
+ if (!participants.some((q) => q.ref === p.ref)) participants.push(p);
19763
+ }
19424
19764
  return {
19425
19765
  externalId: w.conversation,
19426
19766
  source: "chat",
@@ -19445,20 +19785,26 @@ function registerRecordare(api, cfg, kinds) {
19445
19785
  const now = (/* @__PURE__ */ new Date()).toISOString();
19446
19786
  const id = event.currentUserMessageId ?? ctx.runId ?? hash(`${w.conversation}\0${text}\0${now}`);
19447
19787
  const conversation = conversationMeta(w, ctx);
19448
- const message = { externalId: `${id}:u`, role: "user", authorRef: "owner", content: clipUtf8(text), sentAt: now };
19788
+ const message = { externalId: `${id}:u`, role: w.speaker.role, authorRef: w.speaker.ref, content: clipUtf8(text), sentAt: now };
19449
19789
  remember(turns, ctx.runId ?? w.conversation, { user: w.user, conversation, message });
19450
- if (cfg.capture) {
19451
- const others = takeGroupMessages(ctx.sessionKey, text);
19452
- try {
19453
- await fast.ingest(headerUser(w.user), { conversation, messages: [...others, message] });
19454
- } catch (err) {
19455
- log.warn(`recordare: ingest before the turn failed (${errName(err)}), will retry`);
19456
- void send(w.user, { conversation, messages: [...others, message] });
19790
+ if (!cfg.capture) {
19791
+ const ctxRes = await fast.context(headerUser(w.user), w.conversation, text.slice(0, 4e3));
19792
+ return ctxRes.block ? { prependContext: ctxRes.block } : void 0;
19793
+ }
19794
+ const turn = { conversation, messages: [...takeGroupMessages(ctx.sessionKey, text), message] };
19795
+ remember(captured, w.conversation, w.user);
19796
+ try {
19797
+ if (!cfg.autoRecall) {
19798
+ await fast.ingest(headerUser(w.user), turn);
19799
+ return void 0;
19457
19800
  }
19801
+ const ctxRes = await fast.contextWithTurn(headerUser(w.user), turn, text.slice(0, 4e3));
19802
+ return ctxRes.block ? { prependContext: ctxRes.block } : void 0;
19803
+ } catch (err) {
19804
+ log.warn(`recordare: storing the message before the turn failed (${errName(err)}), will retry; no memory context this turn`);
19805
+ void send(w.user, turn);
19806
+ return void 0;
19458
19807
  }
19459
- if (!cfg.autoRecall) return;
19460
- const ctxRes = await fast.context(headerUser(w.user), w.conversation, text.slice(0, 4e3));
19461
- return ctxRes.block ? { prependContext: ctxRes.block } : void 0;
19462
19808
  } catch (err) {
19463
19809
  log.warn(`recordare: memory context unavailable (${errName(err)})`);
19464
19810
  return void 0;
@@ -19476,10 +19822,10 @@ function registerRecordare(api, cfg, kinds) {
19476
19822
  const now = (/* @__PURE__ */ new Date()).toISOString();
19477
19823
  const runId = event.runId ?? ctx.runId ?? hash(`${w.conversation}\0${turn.assistant}`);
19478
19824
  const conversation = conversationMeta(w, ctx);
19479
- const userMessage = stashed?.message ?? (turn.user ? { externalId: `${runId}:u`, role: "user", authorRef: "owner", content: clipUtf8(turn.user), sentAt: now } : void 0);
19825
+ const userMessage = stashed?.message ?? (turn.user ? { externalId: `${runId}:u`, role: w.speaker.role, authorRef: w.speaker.ref, content: clipUtf8(turn.user), sentAt: now } : void 0);
19480
19826
  const answer = { externalId: `${runId}:a`, role: "assistant", authorRef: "assistant", content: clipUtf8(turn.assistant), sentAt: now };
19481
19827
  const messages = [...userMessage ? [userMessage] : [], answer];
19482
- remember(lastSent, w.conversation, { user: w.user, conversation, message: answer });
19828
+ remember(captured, w.conversation, w.user);
19483
19829
  await send(w.user, { conversation, messages });
19484
19830
  } catch (err) {
19485
19831
  log.warn(`recordare: capture failed (${errName(err)})`);
@@ -19489,10 +19835,10 @@ function registerRecordare(api, cfg, kinds) {
19489
19835
  try {
19490
19836
  if (!cfg.capture || ["compaction", "shutdown", "restart"].includes(event.reason ?? "")) return;
19491
19837
  const conv = conversationId(event.sessionKey ?? ctx.sessionKey, event.sessionId ?? ctx.sessionId);
19492
- const last = conv ? lastSent.get(conv) : void 0;
19493
- if (!conv || !last?.message) return;
19494
- lastSent.delete(conv);
19495
- await send(last.user, { conversation: last.conversation, messages: [last.message], hints: { conversationEnded: true } });
19838
+ const user = conv ? captured.get(conv) : void 0;
19839
+ if (!conv || user === void 0) return;
19840
+ captured.delete(conv);
19841
+ await slow.endConversation(headerUser(user), conv);
19496
19842
  } catch (err) {
19497
19843
  log.warn(`recordare: end of conversation not sent (${errName(err)})`);
19498
19844
  }
@@ -19501,18 +19847,22 @@ function registerRecordare(api, cfg, kinds) {
19501
19847
  try {
19502
19848
  const key = event.sessionKey ?? ctx.sessionKey;
19503
19849
  const senderId = event.senderId ?? ctx.senderId;
19504
- if (!cfg.capture || !cfg.groups || !isGroupSession(key) || !senderId || !event.content?.trim()) return;
19505
- const ref = `${ctx.channelId}:${senderId}`;
19850
+ if (!senderId) return;
19851
+ const ref = senderRef(ctx.channelId, senderId);
19852
+ const name = str2(event.metadata?.senderName) ?? str2(event.metadata?.senderUsername);
19853
+ if (name) remember(names, ref, name, MAX_NAMES);
19854
+ if (!cfg.capture || !cfg.groups || !isGroupSession(key) || !event.content?.trim()) return;
19855
+ const speaker = cfg.memoryPer === "agent" ? resolveSpeaker(cfg, ctx.channelId, senderId, name) : { ref, role: "other", participant: senderParticipant(ctx.channelId, senderId, name) };
19506
19856
  const members2 = groupParticipants.get(key) ?? [];
19507
- if (!members2.some((p) => p.ref === ref)) {
19508
- remember(groupParticipants, key, [...members2, { ref, role: "other", identity: { channel: ctx.channelId, externalId: senderId } }]);
19857
+ if (speaker.participant && !members2.some((p) => p.ref === speaker.ref)) {
19858
+ remember(groupParticipants, key, [...members2, speaker.participant]);
19509
19859
  }
19510
19860
  const at = event.timestamp ? new Date(event.timestamp) : /* @__PURE__ */ new Date();
19511
19861
  const buffered = groupBuffer.get(key) ?? [];
19512
19862
  buffered.push({
19513
19863
  externalId: `msg:${event.messageId ?? ctx.messageId ?? hash(`${ref}\0${event.content}\0${at.toISOString()}`)}`,
19514
- role: "other",
19515
- authorRef: ref,
19864
+ role: speaker.role,
19865
+ authorRef: speaker.ref,
19516
19866
  content: clipUtf8(event.content),
19517
19867
  sentAt: at.toISOString()
19518
19868
  });
@@ -19522,7 +19872,7 @@ function registerRecordare(api, cfg, kinds) {
19522
19872
  }
19523
19873
  });
19524
19874
  if (cfg.tools) {
19525
- for (const spec of TOOLS) {
19875
+ for (const spec of TOOLS2) {
19526
19876
  const name = toolName(spec);
19527
19877
  api.registerTool((ctx) => {
19528
19878
  if (kinds.isIncognito(ctx.sessionKey)) return null;