Skip to content

Commit 02bdc5d

Browse files
committed
fix(agent-core-v2): probe blob existence with a stat, not a directory listing
turnRecorded always answered false for turns whose snapshots lived under the file-history/ prefix directory: BlobStoreService.has listed the scope directory (a shallow readdir) and exact-matched the nested key against top-level entries, so keyed blobs were never found and the changes endpoint reported recorded=false for exactly the turns that had edits. Stat the key through storage.size instead, and pin the turn-recorded assertions against a real node-fs home so the harness covers the production layout.
1 parent 4870556 commit 02bdc5d

2 files changed

Lines changed: 9 additions & 4 deletions

File tree

packages/agent-core-v2/src/persistence/backends/node-fs/blobStoreService.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ export class BlobStoreService implements IBlobStore {
2626
}
2727

2828
async has(scope: string, key: string): Promise<boolean> {
29-
const keys = await this.storage.list(scope, key);
30-
return keys.includes(key);
29+
return (await this.storage.size(scope, key)) !== undefined;
3130
}
3231

3332
async delete(scope: string, key: string): Promise<void> {

packages/agent-core-v2/test/features/fileHistory/fileHistory.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import type { RunnableToolExecution } from '#/tool/toolContract';
3737
import { createFakeHostFs } from '../../tools/fixtures/fake-exec';
3838
import { stubToolExecutorEvents, type ToolExecutorEventStubs } from '../../agent/toolExecutor/stubs';
3939
import { registerTestAgentWire, registerTestEventDispatcher, testWireScope } from '../../wire/stubs';
40-
import { createTestAgent } from '../../harness';
40+
import { createTestAgent, homeDirServices } from '../../harness';
4141

4242
const SCOPE = 'wire';
4343
const KEY = 'file-history-test';
@@ -486,9 +486,10 @@ describe('AgentFileHistoryService', () => {
486486
describe('file history through real scripted turns', () => {
487487
it('checkpoints edits across turns and serves exact per-turn changes', async () => {
488488
const dir = await mkdtemp(join(tmpdir(), 'file-history-e2e-'));
489+
const home = await mkdtemp(join(tmpdir(), 'file-history-home-'));
489490
const file = join(dir, 'notes.txt');
490491
await writeFile(file, 'alpha\nbeta\n');
491-
const ctx = createTestAgent();
492+
const ctx = createTestAgent(homeDirServices(home));
492493
try {
493494
await ctx.rpc.setPermission({ mode: 'yolo' });
494495

@@ -536,9 +537,14 @@ describe('file history through real scripted turns', () => {
536537
{ path: file, status: 'modified', additions: 1, deletions: 1 },
537538
]);
538539
expect(await service.changes(1)).toEqual([]);
540+
541+
expect(await service.turnRecorded(0)).toBe(true);
542+
expect(await service.turnRecorded(1)).toBe(false);
543+
expect(await service.turnRecorded(99)).toBe(false);
539544
} finally {
540545
await ctx.dispose();
541546
await rm(dir, { recursive: true, force: true });
547+
await rm(home, { recursive: true, force: true });
542548
}
543549
});
544550

0 commit comments

Comments
 (0)