@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.d.cts CHANGED
@@ -629,6 +629,8 @@ interface TeamSummary {
629
629
  interface TeamAgentSummary {
630
630
  id: string;
631
631
  name: string;
632
+ /** Human-readable label for pickers, when set (wire: `display_name`). Falls back to `name`. */
633
+ displayName?: string | null;
632
634
  teamId: string;
633
635
  createdAt: string;
634
636
  updatedAt: string;
@@ -1517,6 +1519,20 @@ type StreamManagerEvent = {
1517
1519
  type: "versionsReady";
1518
1520
  conversationId: string;
1519
1521
  count: number;
1522
+ } | {
1523
+ /**
1524
+ * A history replay ran to the end — emitted for EVERY restored
1525
+ * conversation, whatever its jobs' statuses. This is the signal to
1526
+ * rehydrate per-turn state (attachment chips, composer modes, goal
1527
+ * runs) from the jobs endpoint. It exists separately from
1528
+ * ``versionsReady`` because that one is completed-only by contract
1529
+ * (a version is an answer to switch to), and a conversation whose
1530
+ * only turns were stopped or failed still needs this pass — gating
1531
+ * rehydration on ``versionsReady`` left such conversations
1532
+ * permanently chip-less.
1533
+ */
1534
+ type: "restoreSettled";
1535
+ conversationId: string;
1520
1536
  };
1521
1537
  type EventHandler = (event: StreamManagerEvent) => void;
1522
1538
  declare class StreamManager {
package/dist/index.d.ts CHANGED
@@ -629,6 +629,8 @@ interface TeamSummary {
629
629
  interface TeamAgentSummary {
630
630
  id: string;
631
631
  name: string;
632
+ /** Human-readable label for pickers, when set (wire: `display_name`). Falls back to `name`. */
633
+ displayName?: string | null;
632
634
  teamId: string;
633
635
  createdAt: string;
634
636
  updatedAt: string;
@@ -1517,6 +1519,20 @@ type StreamManagerEvent = {
1517
1519
  type: "versionsReady";
1518
1520
  conversationId: string;
1519
1521
  count: number;
1522
+ } | {
1523
+ /**
1524
+ * A history replay ran to the end — emitted for EVERY restored
1525
+ * conversation, whatever its jobs' statuses. This is the signal to
1526
+ * rehydrate per-turn state (attachment chips, composer modes, goal
1527
+ * runs) from the jobs endpoint. It exists separately from
1528
+ * ``versionsReady`` because that one is completed-only by contract
1529
+ * (a version is an answer to switch to), and a conversation whose
1530
+ * only turns were stopped or failed still needs this pass — gating
1531
+ * rehydration on ``versionsReady`` left such conversations
1532
+ * permanently chip-less.
1533
+ */
1534
+ type: "restoreSettled";
1535
+ conversationId: string;
1520
1536
  };
1521
1537
  type EventHandler = (event: StreamManagerEvent) => void;
1522
1538
  declare class StreamManager {
package/dist/index.js CHANGED
@@ -2711,15 +2711,15 @@ var StreamManager = class {
2711
2711
  try {
2712
2712
  const jobs = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/jobs`);
2713
2713
  if (stopReplay()) return false;
2714
- const completedJobs = jobs.filter(
2715
- (j) => j.status === "completed" && j.job_id !== activeJobId
2714
+ const replayableJobs = jobs.filter(
2715
+ (j) => j.job_id !== activeJobId
2716
2716
  );
2717
2717
  const userMessages = this.session.messages.filter(
2718
2718
  (m) => m.role === "user"
2719
2719
  );
2720
2720
  const runningJob = activeJobId ? jobs.find((j) => j.job_id === activeJobId) : void 0;
2721
2721
  const plan = planRestore({
2722
- completedJobs: completedJobs.map((j) => ({
2722
+ completedJobs: replayableJobs.map((j) => ({
2723
2723
  job_id: j.job_id,
2724
2724
  message_id: j.message_id
2725
2725
  })),
@@ -2727,27 +2727,38 @@ var StreamManager = class {
2727
2727
  job_id: runningJob.job_id,
2728
2728
  message_id: runningJob.message_id
2729
2729
  },
2730
- // Completed jobs PLUS the ones still going. A send landing in the
2731
- // probe window has a running job, so its prompt is claimed and does
2732
- // not read as a steer replayed over the bubble the live send already
2733
- // rendered. Failed and cancelled jobs are deliberately NOT claimed:
2734
- // they produce no `turn` step, so claiming them would delete the
2735
- // user's prompt from the restore entirely rather than show it as a
2736
- // steer.
2737
- claimedMessageIds: jobs.filter((j) => j.status !== "failed" && j.status !== "cancelled").map((j) => j.message_id),
2730
+ // EVERY job, which is the same set the replay walk gets. The claim set
2731
+ // answers one question "will some turn step already draw this prompt?"
2732
+ // so it is a RESTATEMENT of the walk, and the two drifting apart is
2733
+ // what produces either a missing bubble or a doubled one.
2734
+ //
2735
+ // Failed and cancelled were excluded here for exactly one reason: they
2736
+ // produced no turn step, which is the bug fixed above. Now that they do,
2737
+ // the exclusion has no case left to describe.
2738
+ //
2739
+ // Being precise about what this change does and does not do: it is not
2740
+ // load-bearing TODAY. `planRestore` anchors a prompt at the index its
2741
+ // job links to and advances the cursor past it, so a message claimed by
2742
+ // a job inside the walk is never offered to the steer branch anyway —
2743
+ // the two spellings agree on current inputs. It is here because the
2744
+ // invariant is what keeps them agreeing: narrow the walk again without
2745
+ // narrowing this, and the prompts of the jobs dropped from it go with
2746
+ // them, silently. Deriving both from `jobs` makes that impossible to
2747
+ // get half-right.
2748
+ claimedMessageIds: jobs.map((j) => j.message_id),
2738
2749
  userMessages: userMessages.map((m) => ({
2739
2750
  id: m.id,
2740
2751
  content: m.content
2741
2752
  }))
2742
2753
  });
2743
2754
  const eventLists = await Promise.all(
2744
- completedJobs.map(
2755
+ replayableJobs.map(
2745
2756
  (job) => this.session.client.getConversationEvents(conversationId, job.job_id).catch(() => [])
2746
2757
  )
2747
2758
  );
2748
2759
  if (stopReplay()) return false;
2749
2760
  const eventsByJobId = new Map(
2750
- completedJobs.map((job, i) => [job.job_id, eventLists[i] ?? []])
2761
+ replayableJobs.map((job, i) => [job.job_id, eventLists[i] ?? []])
2751
2762
  );
2752
2763
  for (const step of plan) {
2753
2764
  if (stopReplay()) return false;
@@ -2769,11 +2780,15 @@ var StreamManager = class {
2769
2780
  );
2770
2781
  }
2771
2782
  if (stopReplay()) return false;
2772
- if (completedJobs.length > 0) {
2783
+ this.emit({ type: "restoreSettled", conversationId });
2784
+ const versionCount = replayableJobs.filter(
2785
+ (j) => j.status === "completed"
2786
+ ).length;
2787
+ if (versionCount > 0) {
2773
2788
  this.emit({
2774
2789
  type: "versionsReady",
2775
2790
  conversationId,
2776
- count: completedJobs.length
2791
+ count: versionCount
2777
2792
  });
2778
2793
  }
2779
2794
  } catch {