| … | … | @@ -656,9 +657,106 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make | |
| 750 | + | if (yield* hasTarget()) return; | |
| 751 | + | for (const row of visible) { | |
| 752 | + | if (row.item.deferredWork === undefined) continue; | |
| 753 | + | const result = yield* loadWork(row.sourceItemId); | |
đźź High state/threads.ts:753
A targeted loadEarlier(messageId) can return an error here without issuing the conversation-history request at line 810, leaving an available older message—and its citation—unloaded if any unrelated deferred-work page fails. This also downloads every visible deferred group first, even though messages cannot be in deferred work; avoid expanding unrelated work before paging conversation history.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @packages/client-runtime/src/state/threads.ts around line 753: |
| 2 | |
| 3 | A targeted `loadEarlier(messageId)` can return an error here without issuing the conversation-history request at line 810, leaving an available older message—and its citation—unloaded if any unrelated deferred-work page fails. This also downloads every visible deferred group first, even though messages cannot be in deferred work; avoid expanding unrelated work before paging conversation history. |
Note
Generated by GPT 6.1 Sol
Fixed in a7111d40e8. Targeted history loading now uses the existing conversation-first path without expanding unrelated deferred groups. The regression test makes work requests fail with HTTP 503 and verifies that the target message still loads.
🟢 Low
With deferWork, getThreadSnapshotWindow can return an empty history even when deferred candidates remain: candidates is compacted, but the slice offsets still use the pre-deferral anchorIndex, so the slice starts past the end and prompt context is omitted. Use candidates.length for the post-deferral start and row-budget offsets.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/server/src/orchestration-v2/ProjectionStore.ts around line 7950: |
| 2 | |
| 3 | With `deferWork`, `getThreadSnapshotWindow` can return an empty history even when deferred candidates remain: `candidates` is compacted, but the slice offsets still use the pre-deferral `anchorIndex`, so the slice starts past the end and prompt context is omitted. Use `candidates.length` for the post-deferral start and row-budget offsets. |
Note
Generated by GPT 6.1 Sol
Fixed in a7111d40e8. The in-memory window now calculates both the start offset and latest-turn size from the compacted candidates. A regression test reproduced the empty window before the fix and now keeps its deferred anchor.
| … | … | @@ -3123,14 +3173,43 @@ export const layer: Layer.Layer<ProjectionStoreV2, never, SqlClient.SqlClient> = | |
| 3129 | 3180 | ON item.rowid = retained.item_rowid | |
| 3181 | + | LEFT JOIN deferred_work deferred ON deferred.run_id = item.run_id | |
| 3182 | + | AND deferred.first_ordinal = item.ordinal | |
| 3183 | + | LEFT JOIN orchestration_v2_projection_turn_items tail | |
đźź High orchestration-v2/ProjectionStore.ts:3183
When deferred work ends on a tied ordinal, this join returns the retained item multiple times with different deferredWork.cursor values, so the snapshot contains duplicate item IDs and ambiguous expansion cursors. Because (thread_id, ordinal) is not unique, select the tail deterministically by (ordinal, turn_item_id) and join using its unique turn_item_id.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/server/src/orchestration-v2/ProjectionStore.ts around line 3183: |
| 2 | |
| 3 | When deferred work ends on a tied ordinal, this join returns the retained item multiple times with different `deferredWork.cursor` values, so the snapshot contains duplicate item IDs and ambiguous expansion cursors. Because `(thread_id, ordinal)` is not unique, select the tail deterministically by `(ordinal, turn_item_id)` and join using its unique `turn_item_id`. |
Note
Generated by GPT 6.1 Sol
Fixed in a7111d40e8. The tail join now selects one turn_item_id deterministically at the last ordinal. The existing SQL paging test now includes tied tail ordinals and verifies a single anchor plus complete expansion without duplicate IDs.