@agentvault/agentvault 0.23.14 → 0.23.15

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
@@ -64849,7 +64849,7 @@ var init_channel = __esm({
64849
64849
  */
64850
64850
  sendActivitySpan(spanData) {
64851
64851
  if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
64852
- const pluginVersion = true ? "0.23.14" : "0.0.0-dev";
64852
+ const pluginVersion = true ? "0.23.15" : "0.0.0-dev";
64853
64853
  const agentName = this.config.agentName ?? "Agent";
64854
64854
  const resource = {
64855
64855
  "service.name": "agentvault-agent",
@@ -65194,13 +65194,18 @@ var init_channel = __esm({
65194
65194
  * entry, then persist.
65195
65195
  */
65196
65196
  async _handleServerError(payload) {
65197
- if (payload?.detail !== "conversation deleted") return;
65197
+ const detail = payload?.detail;
65198
+ if (detail !== "conversation deleted" && detail !== "unknown group") return;
65198
65199
  const mlsGroupId = payload.group_id;
65199
65200
  if (!mlsGroupId) return;
65200
65201
  const groups = this._persisted?.mlsGroups;
65201
65202
  if (!groups) return;
65202
65203
  const gid = Object.keys(groups).find((k2) => groups[k2]?.mlsGroupId === mlsGroupId);
65203
65204
  if (!gid) return;
65205
+ if (detail === "unknown group") {
65206
+ await this._reconcileConversationGroups(gid, mlsGroupId);
65207
+ return;
65208
+ }
65204
65209
  try {
65205
65210
  await deleteMlsState(this.config.dataDir, mlsGroupId);
65206
65211
  } catch {
@@ -65213,6 +65218,70 @@ var init_channel = __esm({
65213
65218
  );
65214
65219
  this.emit("dm_group_pruned", { conversationGroupId: gid, mlsGroupId });
65215
65220
  }
65221
+ /**
65222
+ * Re-resolve the conversation→group map from the server (#719).
65223
+ *
65224
+ * `_persisted.conversationGroupIds` and `_persisted.groupId` are built ONCE,
65225
+ * in `_activate()`, from the activation response. `_activate` runs at
65226
+ * enrollment and never again, so when the owner deletes a conversation and a
65227
+ * new one is created the agent keeps addressing the OLD group forever.
65228
+ * Nothing reconciled it — not restart (the stale map is reloaded from disk),
65229
+ * not reconnect, not the heartbeat.
65230
+ *
65231
+ * wren, 2026-07-31: `groupId` 53798dd2 had no `mls_groups` row while three
65232
+ * ACTIVE conversations sat on 99faf707. Inbound worked, every reply was
65233
+ * refused `unknown group` and dropped. Silent since 2026-07-02 — the #460
65234
+ * fan-out was spraying all 12 known groups, so a live one always got hit.
65235
+ *
65236
+ * Best-effort and conservative, mirroring `_refreshRoomRoster`: on any
65237
+ * failure the existing map is kept. The prune is NARROW — only the group the
65238
+ * server named, and only once the server has positively reported an active
65239
+ * conversation on some other group. Absence of data is never treated as
65240
+ * evidence of deletion.
65241
+ */
65242
+ async _reconcileConversationGroups(staleGid, staleMlsGroupId) {
65243
+ const jwt2 = this._deviceJwt ?? this._persisted?.deviceJwt;
65244
+ if (!jwt2 || !this._persisted) return;
65245
+ let rows;
65246
+ try {
65247
+ const res = await fetch(`${this.config.apiUrl}/api/v1/conversations`, {
65248
+ headers: { Authorization: `Bearer ${jwt2}` }
65249
+ });
65250
+ if (!res.ok) return;
65251
+ rows = await res.json();
65252
+ } catch (err) {
65253
+ console.warn("[SecureChannel] Conversation re-resolve failed:", err);
65254
+ return;
65255
+ }
65256
+ if (!Array.isArray(rows)) return;
65257
+ const mine = rows.filter(
65258
+ (r2) => r2?.agent_device_id === this._deviceId && r2?.status === "active" && typeof r2?.group_id === "string" && typeof r2?.id === "string"
65259
+ );
65260
+ if (mine.length === 0) return;
65261
+ const before = this._persisted.groupId;
65262
+ this._sessionGroupIds = new Map(mine.map((r2) => [r2.id, r2.group_id]));
65263
+ this._persisted.conversationGroupIds = Object.fromEntries(this._sessionGroupIds);
65264
+ const primary = mine.find((r2) => r2.id === this._persisted.primaryConversationId) ?? mine[0];
65265
+ this._persisted.groupId = primary.group_id;
65266
+ this._persisted.primaryConversationId = primary.id;
65267
+ const liveGroupIds = new Set(mine.map((r2) => r2.group_id));
65268
+ if (!liveGroupIds.has(staleGid)) {
65269
+ try {
65270
+ await deleteMlsState(this.config.dataDir, staleMlsGroupId);
65271
+ } catch {
65272
+ }
65273
+ this._mlsGroups.delete(`1to1-group:${staleGid}`);
65274
+ delete this._persisted.mlsGroups?.[staleGid];
65275
+ this.emit("dm_group_pruned", {
65276
+ conversationGroupId: staleGid,
65277
+ mlsGroupId: staleMlsGroupId
65278
+ });
65279
+ }
65280
+ await this._persistState();
65281
+ console.log(
65282
+ `[SecureChannel] Re-resolved conversation groups after 'unknown group' ${staleMlsGroupId.slice(0, 8)}: primary group ${String(before).slice(0, 8)} \u2192 ${this._persisted.groupId.slice(0, 8)} (${mine.length} active conversation(s))`
65283
+ );
65284
+ }
65216
65285
  /**
65217
65286
  * Return info for all joined rooms.
65218
65287
  */
@@ -66479,13 +66548,12 @@ var init_channel = __esm({
66479
66548
  sessions,
66480
66549
  messageHistory: this._persisted.messageHistory ?? []
66481
66550
  };
66482
- if (conversations.length > 0) {
66483
- const firstConv = conversations[0];
66484
- if (firstConv.group_id) {
66485
- this._persisted.groupId = firstConv.group_id;
66551
+ if (primary) {
66552
+ if (primary.group_id) {
66553
+ this._persisted.groupId = primary.group_id;
66486
66554
  }
66487
- if (firstConv.default_topic_id) {
66488
- this._persisted.defaultTopicId = firstConv.default_topic_id;
66555
+ if (primary.default_topic_id) {
66556
+ this._persisted.defaultTopicId = primary.default_topic_id;
66489
66557
  }
66490
66558
  }
66491
66559
  this._sessionGroupIds = /* @__PURE__ */ new Map();
@@ -66588,7 +66656,7 @@ var init_channel = __esm({
66588
66656
  agentVersion: this.config.agentVersion ?? "0.0.0",
66589
66657
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
66590
66658
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
66591
- pluginVersion: true ? "0.23.14" : "0.0.0-dev"
66659
+ pluginVersion: true ? "0.23.15" : "0.0.0-dev"
66592
66660
  });
66593
66661
  this._telemetryReporter.startAutoFlush(3e4);
66594
66662
  }
@@ -66906,7 +66974,7 @@ var init_channel = __esm({
66906
66974
  agentVersion: this.config.agentVersion ?? "0.0.0",
66907
66975
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
66908
66976
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
66909
- pluginVersion: true ? "0.23.14" : "0.0.0-dev"
66977
+ pluginVersion: true ? "0.23.15" : "0.0.0-dev"
66910
66978
  });
66911
66979
  this._telemetryReporter.startAutoFlush(3e4);
66912
66980
  }
@@ -97191,7 +97259,7 @@ var init_index = __esm({
97191
97259
  init_skill_invoker();
97192
97260
  await init_skill_telemetry();
97193
97261
  await init_policy_enforcer();
97194
- VERSION = true ? "0.23.14" : "0.0.0-dev";
97262
+ VERSION = true ? "0.23.15" : "0.0.0-dev";
97195
97263
  }
97196
97264
  });
97197
97265
  await init_index();