@agentvault/claude-bridge 0.7.8 → 0.7.10

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
@@ -64124,6 +64124,31 @@ var init_transport2 = __esm2({
64124
64124
  "use strict";
64125
64125
  }
64126
64126
  });
64127
+ function a2aChannelSignature(channels) {
64128
+ return JSON.stringify(
64129
+ channels.map((c22) => ({
64130
+ id: c22.channelId?.slice(0, 8),
64131
+ status: c22.status,
64132
+ participants: c22.participant_count
64133
+ })).sort((a2, b22) => (a2.id ?? "").localeCompare(b22.id ?? ""))
64134
+ );
64135
+ }
64136
+ var A2ALogGate;
64137
+ var init_a2a_log_gate = __esm2({
64138
+ "src/a2a-log-gate.ts"() {
64139
+ "use strict";
64140
+ A2ALogGate = class {
64141
+ last = null;
64142
+ /** True when this state differs from the last reported one. Records it. */
64143
+ shouldReport(channels) {
64144
+ const sig = a2aChannelSignature(channels);
64145
+ if (sig === this.last) return false;
64146
+ this.last = sig;
64147
+ return true;
64148
+ }
64149
+ };
64150
+ }
64151
+ });
64127
64152
  var openclaw_compat_exports = {};
64128
64153
  __export2(openclaw_compat_exports, {
64129
64154
  AGENT_EVENT_CANDIDATES: () => AGENT_EVENT_CANDIDATES,
@@ -64683,6 +64708,7 @@ var init_channel = __esm2({
64683
64708
  await init_crypto_helpers();
64684
64709
  await init_state();
64685
64710
  init_transport2();
64711
+ init_a2a_log_gate();
64686
64712
  ROOM_AGENT_TYPES = /* @__PURE__ */ new Set([
64687
64713
  "message",
64688
64714
  "text",
@@ -64748,6 +64774,11 @@ var init_channel = __esm2({
64748
64774
  _heartbeatTimer = null;
64749
64775
  _heartbeatCallback = null;
64750
64776
  _heartbeatIntervalSeconds = 0;
64777
+ /** #798: report the A2A channel set only when it CHANGES. This line polls
64778
+ * every 30s and produced 90.2% of bridge.log (90,841/100,702 lines) and a
64779
+ * 27.9MB gateway.log on wren, every one reading `channels=0`. Not deleted —
64780
+ * #794's A2A watch needs the transitions. */
64781
+ _a2aLogGate = new A2ALogGate();
64751
64782
  _wakeDetectorTimer = null;
64752
64783
  _lastWakeTick = Date.now();
64753
64784
  _trustToken = null;
@@ -67201,7 +67232,9 @@ var init_channel = __esm2({
67201
67232
  }
67202
67233
  const myHub = this._persisted.hubAddress || "";
67203
67234
  const myHubId = this._persisted.hubId || "";
67204
- console.log(`[listA2AChannels] myHub=${myHub}, channels=${channels.length}, raw=${JSON.stringify(channels.map((c22) => ({ id: c22.channelId?.slice(0, 8), status: c22.status, participants: c22.participant_count })))}`);
67235
+ if (this._a2aLogGate.shouldReport(channels)) {
67236
+ console.log(`[listA2AChannels] myHub=${myHub}, channels=${channels.length}, raw=${JSON.stringify(channels.map((c22) => ({ id: c22.channelId?.slice(0, 8), status: c22.status, participants: c22.participant_count })))}`);
67237
+ }
67205
67238
  for (const ch2 of channels) {
67206
67239
  if (ch2.status === "active" || ch2.status === "approved") {
67207
67240
  const myParticipant = ch2.participants?.find(
@@ -133175,6 +133208,28 @@ var PersistentClaudeSession = class {
133175
133208
  * #416 fallback delivery (which delivers via `void reply(...)` WITHOUT setting
133176
133209
  * saidThisTurn, so !saidThisTurn alone would false-flag it). */
133177
133210
  sawResultThisTurn = false;
133211
+ /**
133212
+ * Per-turn telemetry lifted off the SDK's `result` message.
133213
+ *
133214
+ * The message arrives on EVERY turn and we kept one boolean from it
133215
+ * (`sawResultThisTurn`), discarding the rest. That is the #791 shape: data
133216
+ * delivered on the healthy path that nothing reads.
133217
+ *
133218
+ * It costs us a real answer. A turn that produced nothing (`composed=0,
133219
+ * said=false`) could be the model choosing silence, the turn cap being hit, or
133220
+ * the provider returning 429 — three different bugs with one symptom, and
133221
+ * `subtype`/`apiErrorStatus` are what separate them. 4 of 12 turns on
133222
+ * 2026-08-07 were silent and could not be attributed.
133223
+ *
133224
+ * `durationApiMs` vs `durationMs` also gives the model-time / SDK-overhead
133225
+ * split directly. That split previously had to be reconstructed by joining
133226
+ * `WorkerIncident.ranMs` against SDK transcripts on disk by wall clock.
133227
+ *
133228
+ * Every field is OPTIONAL and left undefined when no result arrives (abort or
133229
+ * crash mid-turn): absent must read as absent, never as a zero that looks like
133230
+ * a real measurement.
133231
+ */
133232
+ resultTelemetry = {};
133178
133233
  /** In-process room MCP server — hoisted so buildSdkOptions can reference it. */
133179
133234
  roomServer;
133180
133235
  /** AbortController for the in-flight query(); abort() triggers it (queue timeout). */
@@ -133239,7 +133294,8 @@ var PersistentClaudeSession = class {
133239
133294
  return {
133240
133295
  composedChars: this.turnText.length,
133241
133296
  sawResult: this.sawResultThisTurn,
133242
- said: this.saidThisTurn
133297
+ said: this.saidThisTurn,
133298
+ ...this.resultTelemetry
133243
133299
  };
133244
133300
  }
133245
133301
  async *input() {
@@ -133261,6 +133317,7 @@ var PersistentClaudeSession = class {
133261
133317
  this.saidThisTurn = false;
133262
133318
  this.turnText = "";
133263
133319
  this.sawResultThisTurn = false;
133320
+ this.resultTelemetry = {};
133264
133321
  yield item.msg;
133265
133322
  }
133266
133323
  }
@@ -133403,6 +133460,21 @@ var PersistentClaudeSession = class {
133403
133460
  }
133404
133461
  } else if (m6.type === "result") {
133405
133462
  this.sawResultThisTurn = true;
133463
+ const r7 = m6;
133464
+ const num = (k2) => typeof r7[k2] === "number" ? r7[k2] : void 0;
133465
+ const str = (k2) => typeof r7[k2] === "string" ? r7[k2] : void 0;
133466
+ const usage = r7.usage ?? {};
133467
+ const unum = (k2) => typeof usage[k2] === "number" ? usage[k2] : void 0;
133468
+ this.resultTelemetry = {
133469
+ durationMs: num("duration_ms"),
133470
+ durationApiMs: num("duration_api_ms"),
133471
+ numTurns: num("num_turns"),
133472
+ subtype: str("subtype"),
133473
+ stopReason: str("stop_reason"),
133474
+ apiErrorStatus: num("api_error_status"),
133475
+ cacheReadTokens: unum("cache_read_input_tokens"),
133476
+ cacheCreationTokens: unum("cache_creation_input_tokens")
133477
+ };
133406
133478
  const reply = this.activeReply;
133407
133479
  if (this.currentReplyExpected && !this.saidThisTurn && this.turnText.trim()) {
133408
133480
  if (reply) {
@@ -134113,7 +134185,7 @@ async function main() {
134113
134185
  "[bridge] warning: passing the invite token on the command line is visible to other local users via 'ps'. Prefer: AV_INVITE_TOKEN=\u2026 npx @agentvault/claude-bridge"
134114
134186
  );
134115
134187
  }
134116
- logLine(`[bridge] version: ${true ? "0.7.8" : "dev"}`);
134188
+ logLine(`[bridge] version: ${true ? "0.7.10" : "dev"}`);
134117
134189
  logLine(`[bridge] data dir: ${cfg.dataDir} (${cfg.dataDirSource})`);
134118
134190
  logLine(`[bridge] workspace: ${cfg.workspaceDir} \xB7 permissions: ${cfg.permissionMode} \xB7 enclave dir fenced`);
134119
134191
  if (cfg.armRoom) {
package/dist/session.d.ts CHANGED
@@ -143,6 +143,28 @@ export declare class PersistentClaudeSession {
143
143
  * #416 fallback delivery (which delivers via `void reply(...)` WITHOUT setting
144
144
  * saidThisTurn, so !saidThisTurn alone would false-flag it). */
145
145
  private sawResultThisTurn;
146
+ /**
147
+ * Per-turn telemetry lifted off the SDK's `result` message.
148
+ *
149
+ * The message arrives on EVERY turn and we kept one boolean from it
150
+ * (`sawResultThisTurn`), discarding the rest. That is the #791 shape: data
151
+ * delivered on the healthy path that nothing reads.
152
+ *
153
+ * It costs us a real answer. A turn that produced nothing (`composed=0,
154
+ * said=false`) could be the model choosing silence, the turn cap being hit, or
155
+ * the provider returning 429 — three different bugs with one symptom, and
156
+ * `subtype`/`apiErrorStatus` are what separate them. 4 of 12 turns on
157
+ * 2026-08-07 were silent and could not be attributed.
158
+ *
159
+ * `durationApiMs` vs `durationMs` also gives the model-time / SDK-overhead
160
+ * split directly. That split previously had to be reconstructed by joining
161
+ * `WorkerIncident.ranMs` against SDK transcripts on disk by wall clock.
162
+ *
163
+ * Every field is OPTIONAL and left undefined when no result arrives (abort or
164
+ * crash mid-turn): absent must read as absent, never as a zero that looks like
165
+ * a real measurement.
166
+ */
167
+ private resultTelemetry;
146
168
  /** In-process room MCP server — hoisted so buildSdkOptions can reference it. */
147
169
  private roomServer;
148
170
  /** AbortController for the in-flight query(); abort() triggers it (queue timeout). */
@@ -185,6 +207,14 @@ export declare class PersistentClaudeSession {
185
207
  composedChars: number;
186
208
  sawResult: boolean;
187
209
  said: boolean;
210
+ durationMs?: number;
211
+ durationApiMs?: number;
212
+ numTurns?: number;
213
+ subtype?: string;
214
+ stopReason?: string;
215
+ apiErrorStatus?: number;
216
+ cacheReadTokens?: number;
217
+ cacheCreationTokens?: number;
188
218
  };
189
219
  private input;
190
220
  /**
@@ -61,11 +61,33 @@ export type WorkerIncident = {
61
61
  * could not separate them.
62
62
  */
63
63
  replyExpected?: boolean;
64
- /** What the worker had produced when it died, when the session can report it. */
64
+ /**
65
+ * What the worker had produced when it died, when the session can report it.
66
+ *
67
+ * The `duration*`/`numTurns`/`subtype`/`stopReason`/`apiErrorStatus` fields are
68
+ * lifted off the SDK's `result` message (see `PersistentClaudeSession`). They
69
+ * are what makes a SILENT turn attributable: `composed=0, said=false` is
70
+ * produced identically by the model choosing silence (`subtype: success`), the
71
+ * turn cap (`error_max_turns`) and a provider error (`apiErrorStatus: 429`).
72
+ * Absent on any turn that never reached a result boundary — undefined means
73
+ * "no result arrived", never zero.
74
+ */
65
75
  session?: {
66
76
  composedChars: number;
67
77
  sawResult: boolean;
68
78
  said: boolean;
79
+ durationMs?: number;
80
+ durationApiMs?: number;
81
+ numTurns?: number;
82
+ subtype?: string;
83
+ stopReason?: string;
84
+ apiErrorStatus?: number;
85
+ /** Prompt-cache state — `cacheReadTokens === 0` with a large
86
+ * `cacheCreationTokens` marks a COLD turn, which costs ~2x a warm one for
87
+ * reasons unrelated to the code under test. Without it, a latency figure
88
+ * in this file cannot be read honestly. */
89
+ cacheReadTokens?: number;
90
+ cacheCreationTokens?: number;
69
91
  };
70
92
  };
71
93
  export interface WorkerQueueDeps {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/claude-bridge",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "type": "module",
5
5
  "description": "AgentVault Claude Bridge \u2014 daemon for bridging a Claude agent into secure E2E-encrypted AgentVault 1:1 direct messages and rooms.",
6
6
  "main": "dist/index.js",