fix(workspace-context): restore the no-unrepresented-commit gate after master merge
The master merge rewrote reconcileInstructionContext and dropped this branch's gate: when no transition survives rendering (tiny budgets produce notice-only text), emit nothing and commit nothing so the next pass retries. Restore it, align the inbox one-byte test with that contract (an unrepresentable change is held back, not committed at 1 byte), and move the nested-retry test's probe assertions to sync time where reconciliation now runs. Also restore master's markdown spec casts lost in an earlier merge.
This commit is contained in:
@@ -162,7 +162,7 @@ describe('MarkdownText', () => {
|
|||||||
expect(() => tokenizer?.call({
|
expect(() => tokenizer?.call({
|
||||||
parser: { constructs: { attentionMarkers: {} } },
|
parser: { constructs: { attentionMarkers: {} } },
|
||||||
previous: null,
|
previous: null,
|
||||||
}, {}, () => undefined, () => undefined)).toThrow(
|
} as never, {} as never, () => undefined, () => undefined)).toThrow(
|
||||||
'micromark CommonMark attention markers are unavailable',
|
'micromark CommonMark attention markers are unavailable',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -405,6 +405,10 @@ export async function reconcileInstructionContext(
|
|||||||
}
|
}
|
||||||
if (items.length === 0) return undefined
|
if (items.length === 0) return undefined
|
||||||
const rendered = renderInstructionChanges(items, resolved.maxBytes)
|
const rendered = renderInstructionChanges(items, resolved.maxBytes)
|
||||||
|
// When no transition survived rendering (tiny budgets render notice-only
|
||||||
|
// text), emit nothing and commit nothing — the uncommitted versions make the
|
||||||
|
// next pass retry instead of spamming notice-only contexts.
|
||||||
|
if (rendered.text.length === 0 || rendered.changes.length === 0) return undefined
|
||||||
return {
|
return {
|
||||||
context: workspaceContextHook(rendered.text, rendered.changes),
|
context: workspaceContextHook(rendered.text, rendered.changes),
|
||||||
versionUpdates: retainedInstructionVersionUpdates(versionUpdates, rendered.changes),
|
versionUpdates: retainedInstructionVersionUpdates(versionUpdates, rendered.changes),
|
||||||
|
|||||||
@@ -3815,13 +3815,18 @@ describe('dynamic nested workspace context injection', () => {
|
|||||||
signal: testToolSignal,
|
signal: testToolSignal,
|
||||||
callId: CallId('read-tiny-budget-1'), name: 'read', arguments: { file_path: join('pkg', 'file.txt') }, agent,
|
callId: CallId('read-tiny-budget-1'), name: 'read', arguments: { file_path: join('pkg', 'file.txt') }, agent,
|
||||||
})
|
})
|
||||||
|
await syncWorkspaceContext(ctx, agent)
|
||||||
const second = await ctx.tools.execute({
|
const second = await ctx.tools.execute({
|
||||||
signal: testToolSignal,
|
signal: testToolSignal,
|
||||||
callId: CallId('read-tiny-budget-2'), name: 'read', arguments: { file_path: join('pkg', 'file.txt') }, agent,
|
callId: CallId('read-tiny-budget-2'), name: 'read', arguments: { file_path: join('pkg', 'file.txt') }, agent,
|
||||||
})
|
})
|
||||||
|
await syncWorkspaceContext(ctx, agent)
|
||||||
|
|
||||||
expect(first.additionalContexts).toBeUndefined()
|
expect(first.additionalContexts).toBeUndefined()
|
||||||
expect(second.additionalContexts).toBeUndefined()
|
expect(second.additionalContexts).toBeUndefined()
|
||||||
|
// Nothing was emitted, and the uncommitted version made the second sync
|
||||||
|
// probe the instruction file again — the retry.
|
||||||
|
expect(agent.inbox.nextStep).toHaveLength(0)
|
||||||
expect(fs.readTargets.filter(path => path === instructionPath)).toHaveLength(2)
|
expect(fs.readTargets.filter(path => path === instructionPath)).toHaveLength(2)
|
||||||
} finally {
|
} finally {
|
||||||
await ctx.fiber.dispose()
|
await ctx.fiber.dispose()
|
||||||
@@ -3916,7 +3921,7 @@ describe('workspace context inbox synchronization', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('keeps a dynamic change within a one-byte positive render budget', async () => {
|
it('holds back a dynamic change a one-byte positive render budget cannot represent', async () => {
|
||||||
const root = await tempRepo()
|
const root = await tempRepo()
|
||||||
const home = await tempRepo()
|
const home = await tempRepo()
|
||||||
const ctx = new Context()
|
const ctx = new Context()
|
||||||
@@ -3934,8 +3939,10 @@ describe('workspace context inbox synchronization', () => {
|
|||||||
|
|
||||||
await syncWorkspaceContext(ctx, agent)
|
await syncWorkspaceContext(ctx, agent)
|
||||||
|
|
||||||
expect(agent.inbox.nextStep).toHaveLength(1)
|
// One byte cannot semantically represent the transition, so nothing is
|
||||||
expect(Buffer.byteLength(blocksText(agent.inbox.nextStep[0]?.content), 'utf8')).toBeLessThanOrEqual(1)
|
// emitted and nothing commits — the uncommitted version retries on the
|
||||||
|
// next touch instead of committing state the model never saw.
|
||||||
|
expect(agent.inbox.nextStep).toHaveLength(0)
|
||||||
} finally {
|
} finally {
|
||||||
await ctx.fiber.dispose()
|
await ctx.fiber.dispose()
|
||||||
await rm(root, { recursive: true, force: true })
|
await rm(root, { recursive: true, force: true })
|
||||||
|
|||||||
Reference in New Issue
Block a user