@agentvault/grok-bridge 0.4.27 → 0.4.28

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.
Files changed (2) hide show
  1. package/dist/index.js +89 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11718,11 +11718,11 @@ async function joinWithFirstMatchingKp(welcomeBytes, candidates) {
11718
11718
  return null;
11719
11719
  }
11720
11720
  function ownIdentity() {
11721
- const v2 = true ? "0.23.60" : FALLBACK;
11721
+ const v2 = true ? "0.23.61" : FALLBACK;
11722
11722
  return `${PACKAGE}@${v2}`;
11723
11723
  }
11724
11724
  function buildSha() {
11725
- const raw = true ? "9599d8e" : "";
11725
+ const raw = true ? "129e537" : "";
11726
11726
  const cleaned = (raw ?? "").trim();
11727
11727
  return !cleaned || cleaned === "unknown" ? null : cleaned;
11728
11728
  }
@@ -12540,6 +12540,10 @@ function buildToolInvokeSpan(report) {
12540
12540
  "tool.duration_ms": durationMs
12541
12541
  };
12542
12542
  if (isError) attributes["tool.error_kind"] = safeErrorKind(report.errorKind);
12543
+ const resets = report.limitResetsAt;
12544
+ if (attributes["tool.error_kind"] === "plan_limit_reached" && typeof resets === "number" && Number.isInteger(resets) && resets > 0 && resets < 1e11) {
12545
+ attributes["av.limit_resets_at"] = resets;
12546
+ }
12543
12547
  if (kind !== "unknown" && typeof conv.id === "string" && conv.id) {
12544
12548
  attributes["av.conversation_id"] = conv.id.slice(0, 64);
12545
12549
  }
@@ -70780,6 +70784,11 @@ var init_dist = __esm({
70780
70784
  "ambiguous_target",
70781
70785
  "no_receipt",
70782
70786
  "invalid_request",
70787
+ // #1467: the owner's own AI plan refused the turn (a bridge on a subscription).
70788
+ "plan_limit_reached",
70789
+ // #1467: a Muse turn failed — Meta answered 429, or anything else.
70790
+ "model_rate_limited",
70791
+ "model_error",
70783
70792
  UNCLASSIFIED_ERROR
70784
70793
  ];
70785
70794
  KNOWN_CODES = new Set(KNOWN_TOOL_ERROR_CODES);
@@ -70991,6 +71000,17 @@ var init_dist = __esm({
70991
71000
  * self-heal rather than be logged and dropped. */
70992
71001
  _mlsCommitFailCounts = /* @__PURE__ */ new Map();
70993
71002
  static MAX_MLS_DECRYPT_FAILS = 3;
71003
+ /**
71004
+ * #1518: ids of MLS application frames this process has already decrypted
71005
+ * (server-assigned `mls_messages.id`, the same on the live delivery pull and
71006
+ * on a `/sync` / reconnect replay). A replayed frame cannot be decrypted a
71007
+ * second time — forward secrecy deleted its key — so without this every
71008
+ * reconnect after a backend deploy fed already-read messages into the
71009
+ * decrypt-failure counter and re-admitted the agent (+2 epochs). Insertion
71010
+ * ordered; the oldest ids fall out past DECRYPTED_ID_CAP.
71011
+ */
71012
+ _decryptedMessageIds = /* @__PURE__ */ new Map();
71013
+ static DECRYPTED_ID_CAP = 5e3;
70994
71014
  /**
70995
71015
  * #1084: consecutive resyncs that found NOTHING to apply, per group.
70996
71016
  *
@@ -73196,7 +73216,7 @@ ${text}`,
73196
73216
  */
73197
73217
  sendActivitySpan(spanData) {
73198
73218
  if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
73199
- const pluginVersion = true ? "0.23.60" : "0.0.0-dev";
73219
+ const pluginVersion = true ? "0.23.61" : "0.0.0-dev";
73200
73220
  const agentName = this.config.agentName ?? "Agent";
73201
73221
  const resource = {
73202
73222
  "service.name": "agentvault-agent",
@@ -75406,7 +75426,7 @@ ${text}`,
75406
75426
  agentVersion: this.config.agentVersion ?? "0.0.0",
75407
75427
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
75408
75428
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
75409
- pluginVersion: true ? "0.23.60" : "0.0.0-dev"
75429
+ pluginVersion: true ? "0.23.61" : "0.0.0-dev"
75410
75430
  });
75411
75431
  this._telemetryReporter.startAutoFlush(3e4);
75412
75432
  }
@@ -75738,7 +75758,7 @@ ${text}`,
75738
75758
  agentVersion: this.config.agentVersion ?? "0.0.0",
75739
75759
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
75740
75760
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
75741
- pluginVersion: true ? "0.23.60" : "0.0.0-dev"
75761
+ pluginVersion: true ? "0.23.61" : "0.0.0-dev"
75742
75762
  });
75743
75763
  this._telemetryReporter.startAutoFlush(3e4);
75744
75764
  }
@@ -76174,9 +76194,14 @@ ${text}`,
76174
76194
  if (groupId) void this._requestWelcomeSelfHeal(groupId);
76175
76195
  return;
76176
76196
  }
76197
+ if (this._alreadyDecrypted(data.message_id)) {
76198
+ console.debug(`[SecureChannel] MLS 1:1 frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
76199
+ return;
76200
+ }
76177
76201
  try {
76178
76202
  const cipherBytes = new Uint8Array(Buffer.from(data.payload, "hex"));
76179
76203
  const result = await mgr.decrypt(cipherBytes);
76204
+ this._rememberDecrypted(data.message_id);
76180
76205
  if (mgrKey) this._mlsDecryptFailCounts.delete(mgrKey);
76181
76206
  const mlsGroupId = (convGroupId ? this._persisted?.mlsGroups?.[convGroupId]?.mlsGroupId : null) ?? this._persisted?.mlsConversations?.[convId]?.mlsGroupId ?? groupId;
76182
76207
  if (mlsGroupId) {
@@ -77199,9 +77224,14 @@ ${baseText}`;
77199
77224
  }
77200
77225
  return;
77201
77226
  }
77227
+ if (this._alreadyDecrypted(data.message_id)) {
77228
+ console.debug(`[SecureChannel] MLS room frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
77229
+ return;
77230
+ }
77202
77231
  try {
77203
77232
  const ciphertext = Buffer.from(data.payload, "hex");
77204
77233
  const result = await mlsGroup.decrypt(new Uint8Array(ciphertext));
77234
+ this._rememberDecrypted(data.message_id);
77205
77235
  this._mlsDecryptFailCounts.delete(resolvedRoomId);
77206
77236
  await saveMlsState(this.config.dataDir, groupId, JSON.stringify(mlsGroup.exportState()));
77207
77237
  if (result.isHandshake || !result.plaintext) {
@@ -78379,16 +78409,57 @@ ${baseText}`;
78379
78409
  }
78380
78410
  return await mlsGroup.encrypt(plaintextBytes);
78381
78411
  }
78412
+ /** #1518: is the server answering at all? Bounded; any failure is "no". */
78413
+ async _serverReachable() {
78414
+ try {
78415
+ const res = await fetch(`${this.config.apiUrl}/health`, { signal: AbortSignal.timeout(5e3) });
78416
+ return res.ok;
78417
+ } catch {
78418
+ return false;
78419
+ }
78420
+ }
78421
+ /** #1518: the server is down — don't re-key (that needs the same server).
78422
+ * Clear the run so the next failures ask again. Reported as handled. */
78423
+ _deferResync(groupKey, groupId, why) {
78424
+ this._mlsDecryptFailCounts.delete(groupKey);
78425
+ console.warn(
78426
+ `[SecureChannel] Resync for ${groupId.slice(0, 8)}: server unreachable (${why}) \u2014 NOT re-keying; will retry (#1518)`
78427
+ );
78428
+ return true;
78429
+ }
78430
+ /** #1518: has this process already decrypted the frame with this id? */
78431
+ _alreadyDecrypted(messageId) {
78432
+ return typeof messageId === "string" && messageId !== "" && this._decryptedMessageIds.has(messageId);
78433
+ }
78434
+ /** #1518: remember a decrypted frame's id (bounded; oldest dropped). */
78435
+ _rememberDecrypted(messageId) {
78436
+ if (typeof messageId !== "string" || messageId === "") return;
78437
+ this._decryptedMessageIds.set(messageId, true);
78438
+ if (this._decryptedMessageIds.size > _SecureChannel.DECRYPTED_ID_CAP) {
78439
+ const oldest = this._decryptedMessageIds.keys().next().value;
78440
+ if (oldest !== void 0) this._decryptedMessageIds.delete(oldest);
78441
+ }
78442
+ }
78382
78443
  async _resyncOnDivergence(groupKey, groupId) {
78383
78444
  const mgr = this._mlsGroups.get(groupKey);
78384
78445
  if (!mgr?.isInitialized) return false;
78385
78446
  const fromEpoch = Number(mgr.epoch);
78386
78447
  try {
78387
- const res = await fetch(
78388
- `${this.config.apiUrl}/api/v1/mls/groups/${groupId}/sync?last_epoch=${fromEpoch}`,
78389
- { headers: { Authorization: `Bearer ${this._deviceJwt}` } }
78390
- );
78448
+ let res;
78449
+ try {
78450
+ res = await fetch(
78451
+ `${this.config.apiUrl}/api/v1/mls/groups/${groupId}/sync?last_epoch=${fromEpoch}`,
78452
+ { headers: { Authorization: `Bearer ${this._deviceJwt}` } }
78453
+ );
78454
+ } catch (netErr) {
78455
+ if (!await this._serverReachable()) return this._deferResync(groupKey, groupId, String(netErr));
78456
+ console.warn(`[SecureChannel] Resync-on-divergence failed for ${groupId.slice(0, 8)}:`, netErr);
78457
+ return false;
78458
+ }
78391
78459
  if (!res.ok) {
78460
+ if ((res.status >= 500 || res.status === 429) && !await this._serverReachable()) {
78461
+ return this._deferResync(groupKey, groupId, `HTTP ${res.status}`);
78462
+ }
78392
78463
  console.warn(`[SecureChannel] Resync /sync failed for ${groupId.slice(0, 8)}: ${res.status}`);
78393
78464
  return false;
78394
78465
  }
@@ -79503,9 +79574,14 @@ ${baseText}`;
79503
79574
  console.warn(`[SecureChannel] MLS group not loaded for A2A ${a2aChannelId.slice(0, 8)}`);
79504
79575
  return;
79505
79576
  }
79577
+ if (this._alreadyDecrypted(data.message_id)) {
79578
+ console.debug(`[SecureChannel] MLS A2A frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
79579
+ return;
79580
+ }
79506
79581
  try {
79507
79582
  const ciphertext = new Uint8Array(Buffer.from(data.payload, "hex"));
79508
79583
  const result = await mlsGroup.decrypt(ciphertext);
79584
+ this._rememberDecrypted(data.message_id);
79509
79585
  this._mlsDecryptFailCounts.delete(`a2a:${a2aChannelId}`);
79510
79586
  await saveMlsState(this.config.dataDir, groupId, JSON.stringify(mlsGroup.exportState()));
79511
79587
  if (result.isHandshake || !result.plaintext) {
@@ -102156,7 +102232,7 @@ data:
102156
102232
  await init_policy_enforcer();
102157
102233
  init_room_protocol();
102158
102234
  init_tool_telemetry();
102159
- VERSION = true ? "0.23.60" : "0.0.0-dev";
102235
+ VERSION = true ? "0.23.61" : "0.0.0-dev";
102160
102236
  }
102161
102237
  });
102162
102238
  await init_index();
@@ -104427,7 +104503,7 @@ async function main() {
104427
104503
  const info = parseInfoFlags(process.argv.slice(2));
104428
104504
  if (info.showVersion || info.showHelp) {
104429
104505
  const version2 = buildClientVersion2(
104430
- true ? "0.4.27" : void 0
104506
+ true ? "0.4.28" : void 0
104431
104507
  );
104432
104508
  if (info.showVersion) printLine(version2);
104433
104509
  if (info.showHelp) {
@@ -104466,7 +104542,7 @@ async function main() {
104466
104542
  process.exit(0);
104467
104543
  }
104468
104544
  const cfg = loadConfig(process.env, process.argv.slice(2));
104469
- logLine(`[grok-bridge] version: ${true ? "0.4.27" : "dev"}`);
104545
+ logLine(`[grok-bridge] version: ${true ? "0.4.28" : "dev"}`);
104470
104546
  mkdirSync7(cfg.workspaceDir, { recursive: true });
104471
104547
  mkdirSync7(cfg.fenceHome, { recursive: true });
104472
104548
  seedFenceCredential({
@@ -104481,7 +104557,7 @@ async function main() {
104481
104557
  agentName: cfg.agentName,
104482
104558
  platform: "node",
104483
104559
  clientVersion: buildClientVersion2(
104484
- true ? "0.4.27" : void 0
104560
+ true ? "0.4.28" : void 0
104485
104561
  )
104486
104562
  });
104487
104563
  channelRef = channel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/grok-bridge",
3
- "version": "0.4.27",
3
+ "version": "0.4.28",
4
4
  "type": "module",
5
5
  "description": "AgentVault Grok Bridge — daemon bridging a Grok agent into E2E-encrypted AgentVault direct messages and rooms.",
6
6
  "main": "dist/index.js",