@bivy/bivy 0.17.3-staging.18 → 0.17.3-staging.19

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/server.js CHANGED
@@ -1941,10 +1941,13 @@ const dedupeSessionNew = (requestId, create) => sessionNewDedupe.run(requestId,
1941
1941
  // generic key->promise cache as above, reused for a different key) — see
1942
1942
  // issue #154's queued follow-ups. A client that isn't sure whether a queued
1943
1943
  // item's send actually reached the node before the socket dropped (see
1944
- // AppController.retryStuckFollowups) resends it verbatim after reconnecting;
1944
+ // FollowupCoordinator.retrySending) resends it verbatim after reconnecting;
1945
1945
  // this makes that safe by collapsing a retried clientMessageId onto the
1946
- // original broadcast + turn instead of double-prompting the runtime.
1947
- const promptDedupe = createSessionNewDedupe();
1946
+ // original broadcast + turn instead of double-prompting the runtime. The key is
1947
+ // kept for a day, not session.new's 10 minutes: a phone backgrounded mid-send
1948
+ // can reconnect long after the turn ended, and an expired key turned its
1949
+ // retry into a fresh, duplicate turn at the bottom of the chat.
1950
+ const promptDedupe = createSessionNewDedupe({ ttlMs: 24 * 60 * 60_000 });
1948
1951
  const dedupePrompt = (clientMessageId, run) => promptDedupe.run(clientMessageId, run);
1949
1952
  // Preview traffic has isolated per-view origins and a private gateway. Relay
1950
1953
  // delivery needs no listener; direct ingress is an optional operator override.
@@ -2910,7 +2913,7 @@ const RELAY_COMMANDS = {
2910
2913
  relay?.sendEvent({ type: "integrations.updated", integrations: integrations.list() });
2911
2914
  }
2912
2915
  },
2913
- async prompt(msg) {
2916
+ async prompt(msg, ctx) {
2914
2917
  const text = String(msg.text ?? "").trim();
2915
2918
  const { images, imageNotes, imageRefs, files } = attachmentsFrom(msg.attachments);
2916
2919
  if (!text && !images.length && !files.length)
@@ -2963,6 +2966,14 @@ const RELAY_COMMANDS = {
2963
2966
  eventLog.appendAttachments(record.id, promptText, [...imageRefs, ...fileRefs]);
2964
2967
  const agentPrompt = promptForAgent(record, promptText);
2965
2968
  const cmid = typeof msg.clientMessageId === "string" && msg.clientMessageId ? msg.clientMessageId : undefined;
2969
+ // A retry of a prompt we already took: the caller missed our echo (that is
2970
+ // why it retried), so acknowledge it again — to the caller only, since
2971
+ // other clients already rendered the first one. Without this the client
2972
+ // keeps the message "sending" and resends it on every reconnect.
2973
+ if (promptDedupe.has(cmid)) {
2974
+ ctx.reply({ type: "session.user_message", sessionId: record.id, text: promptText, clientMessageId: cmid, retry: true });
2975
+ return;
2976
+ }
2966
2977
  void dedupePrompt(cmid, async () => {
2967
2978
  broadcast({ type: "session.user_message", sessionId: record.id, text: promptText, clientMessageId: msg.clientMessageId });
2968
2979
  void sessionNamer.maybeNameSession(record, promptText);
@@ -38,5 +38,5 @@ export function createSessionNewDedupe(options = {}) {
38
38
  });
39
39
  return p;
40
40
  }
41
- return { run, size: () => inflight.size };
41
+ return { run, has: (requestId) => Boolean(requestId && inflight.has(requestId)), size: () => inflight.size };
42
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivy/bivy",
3
- "version": "0.17.3-staging.18",
3
+ "version": "0.17.3-staging.19",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0-only",
6
6
  "description": "Run coding agents on machines you own. Open-source, self-hostable agent workspace.",