@astralform/js 6.0.2 → 6.0.4

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.cjs CHANGED
@@ -2758,15 +2758,15 @@ var StreamManager = class {
2758
2758
  try {
2759
2759
  const jobs = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/jobs`);
2760
2760
  if (stopReplay()) return false;
2761
- const completedJobs = jobs.filter(
2762
- (j) => j.status === "completed" && j.job_id !== activeJobId
2761
+ const replayableJobs = jobs.filter(
2762
+ (j) => j.job_id !== activeJobId
2763
2763
  );
2764
2764
  const userMessages = this.session.messages.filter(
2765
2765
  (m) => m.role === "user"
2766
2766
  );
2767
2767
  const runningJob = activeJobId ? jobs.find((j) => j.job_id === activeJobId) : void 0;
2768
2768
  const plan = planRestore({
2769
- completedJobs: completedJobs.map((j) => ({
2769
+ completedJobs: replayableJobs.map((j) => ({
2770
2770
  job_id: j.job_id,
2771
2771
  message_id: j.message_id
2772
2772
  })),
@@ -2774,27 +2774,38 @@ var StreamManager = class {
2774
2774
  job_id: runningJob.job_id,
2775
2775
  message_id: runningJob.message_id
2776
2776
  },
2777
- // Completed jobs PLUS the ones still going. A send landing in the
2778
- // probe window has a running job, so its prompt is claimed and does
2779
- // not read as a steer replayed over the bubble the live send already
2780
- // rendered. Failed and cancelled jobs are deliberately NOT claimed:
2781
- // they produce no `turn` step, so claiming them would delete the
2782
- // user's prompt from the restore entirely rather than show it as a
2783
- // steer.
2784
- claimedMessageIds: jobs.filter((j) => j.status !== "failed" && j.status !== "cancelled").map((j) => j.message_id),
2777
+ // EVERY job, which is the same set the replay walk gets. The claim set
2778
+ // answers one question "will some turn step already draw this prompt?"
2779
+ // so it is a RESTATEMENT of the walk, and the two drifting apart is
2780
+ // what produces either a missing bubble or a doubled one.
2781
+ //
2782
+ // Failed and cancelled were excluded here for exactly one reason: they
2783
+ // produced no turn step, which is the bug fixed above. Now that they do,
2784
+ // the exclusion has no case left to describe.
2785
+ //
2786
+ // Being precise about what this change does and does not do: it is not
2787
+ // load-bearing TODAY. `planRestore` anchors a prompt at the index its
2788
+ // job links to and advances the cursor past it, so a message claimed by
2789
+ // a job inside the walk is never offered to the steer branch anyway —
2790
+ // the two spellings agree on current inputs. It is here because the
2791
+ // invariant is what keeps them agreeing: narrow the walk again without
2792
+ // narrowing this, and the prompts of the jobs dropped from it go with
2793
+ // them, silently. Deriving both from `jobs` makes that impossible to
2794
+ // get half-right.
2795
+ claimedMessageIds: jobs.map((j) => j.message_id),
2785
2796
  userMessages: userMessages.map((m) => ({
2786
2797
  id: m.id,
2787
2798
  content: m.content
2788
2799
  }))
2789
2800
  });
2790
2801
  const eventLists = await Promise.all(
2791
- completedJobs.map(
2802
+ replayableJobs.map(
2792
2803
  (job) => this.session.client.getConversationEvents(conversationId, job.job_id).catch(() => [])
2793
2804
  )
2794
2805
  );
2795
2806
  if (stopReplay()) return false;
2796
2807
  const eventsByJobId = new Map(
2797
- completedJobs.map((job, i) => [job.job_id, eventLists[i] ?? []])
2808
+ replayableJobs.map((job, i) => [job.job_id, eventLists[i] ?? []])
2798
2809
  );
2799
2810
  for (const step of plan) {
2800
2811
  if (stopReplay()) return false;
@@ -2816,11 +2827,15 @@ var StreamManager = class {
2816
2827
  );
2817
2828
  }
2818
2829
  if (stopReplay()) return false;
2819
- if (completedJobs.length > 0) {
2830
+ this.emit({ type: "restoreSettled", conversationId });
2831
+ const versionCount = replayableJobs.filter(
2832
+ (j) => j.status === "completed"
2833
+ ).length;
2834
+ if (versionCount > 0) {
2820
2835
  this.emit({
2821
2836
  type: "versionsReady",
2822
2837
  conversationId,
2823
- count: completedJobs.length
2838
+ count: versionCount
2824
2839
  });
2825
2840
  }
2826
2841
  } catch {