@1presence/bridge 0.44.0 → 0.46.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/claude.js CHANGED
@@ -161,6 +161,27 @@ function describeCliFailure(apiErrorText, authFailure) {
161
161
  }
162
162
  return 'Local Mode stopped unexpectedly. Please try again.';
163
163
  }
164
+ /**
165
+ * Copy for an actionable rate-limit notice. The SDK emits `rate_limit_event`
166
+ * whenever rate-limit info CHANGES — including the routine `allowed` case on
167
+ * (nearly) every turn — so the caller must drop `allowed` and only invoke this
168
+ * for `allowed_warning` / `rejected`. `resetsAt` is a Unix timestamp; the SDK
169
+ * uses seconds, but we accept ms too in case that changes upstream.
170
+ */
171
+ function formatRateLimitNotice(status, resetsAt) {
172
+ const when = typeof resetsAt === 'number' && resetsAt > 0
173
+ ? new Date(resetsAt < 1e12 ? resetsAt * 1000 : resetsAt)
174
+ .toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })
175
+ : null;
176
+ if (status === 'rejected') {
177
+ return when
178
+ ? `Pausing for an upstream rate limit — resumes around ${when}.`
179
+ : 'Pausing briefly for an upstream rate limit, then continuing…';
180
+ }
181
+ return when
182
+ ? `Approaching your usage limit — window resets around ${when}.`
183
+ : 'Approaching your usage limit for this period.';
184
+ }
164
185
  // ─── Prompt construction ─────────────────────────────────────────────────────────
165
186
  //
166
187
  // The gateway pushes the FULL conversation (sanitised via @presence/shared
@@ -292,6 +313,27 @@ export function spawnClaude(params) {
292
313
  // credentials in the Keychain), not an API key that would bill a separate
293
314
  // account. Options.env REPLACES the subprocess env, so spread the rest through.
294
315
  const { ANTHROPIC_API_KEY: _stripped, ...safeEnv } = process.env;
316
+ // Claude Code truncates "large" MCP tool results (token count over
317
+ // MAX_MCP_OUTPUT_TOKENS, default 25,000) one of two ways, gated by
318
+ // ENABLE_MCP_LARGE_OUTPUT_FILES:
319
+ // • default (feature ON): the full result is written to a tool-results/*.json
320
+ // file and the model is handed a `<persisted-output>` stub telling it to Read
321
+ // the file. Local Mode disables every built-in tool (`tools: []` below), so
322
+ // the model has no Read — it reaches for vault_read, which resolves the local
323
+ // path against the GCS prefix and fails ("No such object"). Unrecoverable.
324
+ // • OFF: the result is inline-truncated to the cap — graceful degradation the
325
+ // model can actually work with.
326
+ // Hosted mode pipes results straight to the Anthropic SDK with no truncation, so
327
+ // this breaks Local Mode only — a parity bug. Fix on two fronts: force the
328
+ // file-save path off so the unrecoverable failure mode is impossible, and raise
329
+ // the cap so legitimate large results (skill bodies, vault reads) pass inline
330
+ // instead of truncating. Operator overrides (env already set) win on both.
331
+ if (!safeEnv['ENABLE_MCP_LARGE_OUTPUT_FILES']) {
332
+ safeEnv['ENABLE_MCP_LARGE_OUTPUT_FILES'] = 'false';
333
+ }
334
+ if (!safeEnv['MAX_MCP_OUTPUT_TOKENS']) {
335
+ safeEnv['MAX_MCP_OUTPUT_TOKENS'] = '200000';
336
+ }
295
337
  const pinnedModel = getBridgeModel();
296
338
  // Process one translated raw stream-json event: bookkeeping + forward. Mirrors
297
339
  // the old CLI stdout parser so the gateway/accumulator see identical shapes.
@@ -557,9 +599,16 @@ export function spawnClaude(params) {
557
599
  break;
558
600
  }
559
601
  case 'rate_limit_event': {
560
- // SDK surfaces upstream rate-limit pauses; it retries internally.
561
- // Admin-only ephemeral notice jargon is fine in Local Mode.
562
- onNotice?.('Claude Code is pausing briefly for an upstream rate limit, then continuing…');
602
+ // The SDK emits this whenever rate-limit info CHANGES including the
603
+ // routine `allowed` case on (nearly) every turn, which previously
604
+ // spammed a phantom "pausing" notice (see vault/Bugs.md). Only surface
605
+ // a notice when the user is actually warned or throttled.
606
+ const info = m.rate_limit_info;
607
+ const status = info?.status;
608
+ if (status === 'allowed_warning' || status === 'rejected') {
609
+ // Admin-only ephemeral notice — jargon is fine in Local Mode.
610
+ onNotice?.(formatRateLimitNotice(status, info?.resetsAt));
611
+ }
563
612
  break;
564
613
  }
565
614
  // Everything else (partial messages, status, hooks, notifications,
package/dist/index.js CHANGED
@@ -327,6 +327,8 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
327
327
  // Ephemeral, non-persisted thread notice (admin-only Local Mode). Relayed
328
328
  // by the gateway to the PWA SSE stream as a `notice` AgentEvent; it does
329
329
  // NOT go through the turn accumulator, so it never lands in history.
330
+ // Log it too: anything the user sees in chat must have a bridge-log trail.
331
+ console.log(`[${new Date().toLocaleTimeString()}] ⚠ notice: ${message}`);
330
332
  if (currentWs?.readyState === WebSocket.OPEN) {
331
333
  currentWs.send(JSON.stringify({ type: 'notice', conversationId, message }));
332
334
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.44.0",
3
+ "version": "0.46.0",
4
4
  "description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
5
5
  "type": "module",
6
6
  "bin": {