@bivy/bivy 0.18.3-staging.1 → 0.18.3-staging.2

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.
@@ -321,7 +321,9 @@ export class AgentService {
321
321
  // state onto that frame so the mirror is correct even for a runtime that
322
322
  // mutates messages/sessionFile exactly at agent_end (no prior message_end
323
323
  // delta) — the "set before agent_end" invariant in process.ts.
324
- const authoritative = event.type === "agent_end";
324
+ // Item boundaries can revise an existing transcript entry without changing
325
+ // its count. Forward that revision before the daemon persists/replays it.
326
+ const authoritative = event.type === "agent_end" || event.type === "message_boundary" || event.type === "message_end";
325
327
  const snapshot = this.snapshotDelta(svc, authoritative);
326
328
  const message = snapshot ? { t: "event", event, snapshot } : { t: "event", event };
327
329
  conn.send(message);
@@ -169,6 +169,7 @@ class ProtocolSession {
169
169
  resumeRef;
170
170
  started = false;
171
171
  assistantText = "";
172
+ turnMessageIndex;
172
173
  /** A protocol agent can produce several discrete assistant messages in one
173
174
  * turn (Codex commentary items are the common case). After a
174
175
  * `message.boundary`, separate the next item's text in the cumulative stream
@@ -530,6 +531,18 @@ class ProtocolSession {
530
531
  if (pending)
531
532
  this.turnContent.push({ type: "text", text: pending });
532
533
  }
534
+ /** Publish a stable transcript entry at item boundaries, while keeping the
535
+ * live text cumulative. Replace this entry as the turn grows so reconnects
536
+ * retain commentary without duplicating it at completion. */
537
+ snapshotAssistantTurn(content) {
538
+ if (this.turnMessageIndex === undefined) {
539
+ this.turnMessageIndex = this.messages.length;
540
+ this.messages.push({ role: "assistant", content, id: randomUUID(), timestamp: Date.now() });
541
+ }
542
+ else {
543
+ this.messages[this.turnMessageIndex] = { ...this.messages[this.turnMessageIndex], content };
544
+ }
545
+ }
533
546
  /**
534
547
  * Fold assistant text that arrives after the turn was sealed (session.done)
535
548
  * onto the last persisted assistant message — the ACP end_turn race (see the
@@ -646,6 +659,7 @@ class ProtocolSession {
646
659
  if (this.turnContent[this.turnContent.length - 1]?.type !== "bivy_message_boundary") {
647
660
  this.turnContent.push({ type: "bivy_message_boundary" });
648
661
  }
662
+ this.snapshotAssistantTurn([...this.turnContent]);
649
663
  this.emit({ type: "message_boundary", message: { role: "assistant", content: this.assistantText } });
650
664
  this.assistantItemBoundary = true;
651
665
  }
@@ -690,12 +704,12 @@ class ProtocolSession {
690
704
  if (hadTools) {
691
705
  this.flushPendingTurnText();
692
706
  if (this.turnContent.length)
693
- this.messages.push({ role: "assistant", content: this.turnContent, timestamp: Date.now() });
707
+ this.snapshotAssistantTurn([...this.turnContent]);
694
708
  if (this.turnToolResults.length)
695
709
  this.messages.push({ role: "user", content: this.turnToolResults, timestamp: Date.now() });
696
710
  }
697
711
  else if (this.assistantText) {
698
- this.messages.push(message);
712
+ this.snapshotAssistantTurn(this.assistantText);
699
713
  }
700
714
  this.emit({ type: "message_end", message });
701
715
  this.streaming = false;
@@ -720,12 +734,12 @@ class ProtocolSession {
720
734
  if (hadTools) {
721
735
  this.flushPendingTurnText();
722
736
  if (this.turnContent.length)
723
- this.messages.push({ role: "assistant", content: this.turnContent, timestamp: Date.now() });
737
+ this.snapshotAssistantTurn([...this.turnContent]);
724
738
  if (this.turnToolResults.length)
725
739
  this.messages.push({ role: "user", content: this.turnToolResults, timestamp: Date.now() });
726
740
  }
727
741
  else if (this.assistantText) {
728
- this.messages.push({ role: "assistant", content: this.assistantText, timestamp: Date.now() });
742
+ this.snapshotAssistantTurn(this.assistantText);
729
743
  }
730
744
  // Append a terminal error marker in the shape store-render + terminalTurnError
731
745
  // recognize (stopReason "error" + errorMessage), so the failure itself
@@ -935,6 +949,7 @@ class ProtocolSession {
935
949
  }
936
950
  this.messages.push({ role: "user", content: prompt, timestamp: Date.now() });
937
951
  this.streaming = true;
952
+ this.turnMessageIndex = undefined;
938
953
  this.assistantText = "";
939
954
  this.assistantItemBoundary = false;
940
955
  this.reasoningText = "";
package/dist/server.js CHANGED
@@ -7720,8 +7720,9 @@ function attachSessionListeners(record) {
7720
7720
  transcripts.persistToolActivityFromEvent(record, event);
7721
7721
  // Snapshot the base transcript (prompts + replies) alongside the tool/thinking
7722
7722
  // sidecars. turn_start captures the just-added user prompt (so a crash mid-turn
7723
- // still keeps it); message_end/turn_end capture the assistant reply.
7724
- if (event.type === "turn_start" || event.type === "message_end" || event.type === "turn_end") {
7723
+ // still keeps it); item boundaries capture commentary during work, and
7724
+ // message_end/turn_end capture the assistant reply.
7725
+ if (event.type === "turn_start" || event.type === "message_boundary" || event.type === "message_end" || event.type === "turn_end") {
7725
7726
  transcripts.persistTranscriptSnapshot(record);
7726
7727
  }
7727
7728
  // A finalized assistant message may reference a remote image via markdown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivy/bivy",
3
- "version": "0.18.3-staging.1",
3
+ "version": "0.18.3-staging.2",
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.",