Skip to content

Commit 22a4ebe

Browse files
committed
fix(runtime): cache unresolved historical results
1 parent 58b3895 commit 22a4ebe

2 files changed

Lines changed: 9 additions & 2 deletions

File tree

‎packages/runtime/src/__tests__/stream-graph-schedule-reconcile.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ describe('stream graph schedule reconciliation', () => {
113113
},
114114
],
115115
});
116+
let resolveCalls = 0;
116117
const result = await reconcileAgentGraphSchedule({
117118
topology: topology(),
118119
controlStore,
@@ -122,6 +123,7 @@ describe('stream graph schedule reconciliation', () => {
122123
maxNewActivations: 1,
123124
observeGraph: (currentTopology) => observation.read(currentTopology),
124125
resolveSelectedResultInputs: async () => {
126+
resolveCalls += 1;
125127
throw new Error('source epoch runtime events are unreadable');
126128
},
127129
renderPrompt: ({ work }) => work.instruction,
@@ -130,6 +132,7 @@ describe('stream graph schedule reconciliation', () => {
130132
assert.equal(result.status, 'waiting');
131133
assert.equal(result.failures.length, 0);
132134
assert.equal(result.dispatches.length, 0);
135+
assert.equal(resolveCalls, 1);
133136
assert.deepEqual(
134137
result.deferredWork.map((item) => ({
135138
reason: item.reason,

‎packages/runtime/src/stream-graph-schedule-reconcile.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,8 @@ function missingWorkInputIds(
513513
];
514514
}
515515

516-
/** Resolved historical records keyed by source graph id, then result id. */
517-
type SelectedResultCache = Map<string, Map<string, AgentGraphRecord>>;
516+
/** Historical resolution attempts keyed by source graph id, then result id. */
517+
type SelectedResultCache = Map<string, Map<string, AgentGraphRecord | undefined>>;
518518

519519
/**
520520
* Resolves selected historical result inputs, isolating failures per source
@@ -557,6 +557,10 @@ async function resolveSelectedResultRecords(
557557
}
558558
const pending = group.filter((selected) => !cached.has(selected.resultId));
559559
if (pending.length === 0) continue;
560+
// Cache unsuccessful attempts for this reconciliation too. Repeated
561+
// snapshot reads must not replay a resolver that already failed or
562+
// returned records that violate its identity contract.
563+
pending.forEach((selected) => cached.set(selected.resultId, undefined));
560564
let records: readonly AgentGraphRecord[];
561565
try {
562566
records = await input.resolveSelectedResultInputs(pending);

0 commit comments

Comments
 (0)