Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/client-runtime/src/state/threadInbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ describe("createInboxReturnTracker", () => {
});
it("stamps a thread when it stops working, but never on the first observation", () => {
const tracker = createInboxReturnTracker();
using stringify = vi.spyOn(JSON, "stringify");
const first = tracker.observe([thread("a", true), thread("b", false)]);
expect(stringify).toHaveBeenCalledTimes(1);
expect(first.returnedAt(thread("a", true))).toBeUndefined();
expect(first.returnedAt(thread("b", false))).toBeUndefined();

Expand Down
27 changes: 15 additions & 12 deletions packages/client-runtime/src/state/threadInbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function createInboxReturnTracker() {
const keyOf = (thread: ThreadKeyInput) => `${thread.environmentId}:${thread.id}`;
const states = new Map<
string,
{ working: boolean; deadline: number | null; placement: string }
{ working: boolean; deadline: number | null; placement: string | null }
>();
const returns = new Map<string, number>();
const listeners = new Set<() => void>();
Expand Down Expand Up @@ -184,17 +184,21 @@ export function createInboxReturnTracker() {
for (const thread of threads) {
const key = keyOf(thread);
present.add(key);
const placement = JSON.stringify([
thread.archivedAt,
thread.deletedAt,
thread.pinnedAt,
thread.settledOverride,
thread.settledAt,
thread.snoozedAt,
thread.snoozedUntil,
thread.activeOrderKey,
]);
const previous = states.get(key);
const actual = isThreadWorking(thread);
const placement =
actual || previous?.working
? JSON.stringify([
thread.archivedAt,
thread.deletedAt,
thread.pinnedAt,
thread.settledOverride,
thread.settledAt,
thread.snoozedAt,
thread.snoozedUntil,
thread.activeOrderKey,
])
: null;
const actionable =
thread.hasPendingApprovals ||
thread.hasPendingUserInput ||
Expand All @@ -210,7 +214,6 @@ export function createInboxReturnTracker() {
thread.pinnedAt != null ||
thread.settledOverride === "settled" ||
effectiveSnoozed(thread, { now: observedAt });
const actual = isThreadWorking(thread);
// Only shelf placement is held: execution state and attention requests stay authoritative.
const deadline =
!actual && previous?.working && !actionable && !moved && !excluded
Expand Down
Loading