Skip to content

Commit 5aab4bc

Browse files
anandgupta42claude
andcommitted
fix: remove double-deduction in isOverflow for non-limit.input models
Sentry correctly flagged that the non-limit.input path was subtracting both maxOutput AND reserved (20K buffer), causing compaction to trigger 20K tokens too early for most production models. Simplified both paths to use a single headroom = Math.max(reserved, maxOutput). For default configs (maxOutput=32K > buffer=20K), this matches the original upstream behavior while preserving the P0 fix for limit.input models. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 599537e commit 5aab4bc

2 files changed

Lines changed: 18 additions & 16 deletions

File tree

packages/altimate-code/src/session/compaction.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,8 @@ export namespace SessionCompaction {
8484

8585
const maxOutput = ProviderTransform.maxOutputTokens(input.model)
8686
const reserved = config.compaction?.reserved ?? COMPACTION_BUFFER
87-
const usable = input.model.limit.input
88-
? input.model.limit.input - Math.max(reserved, maxOutput)
89-
: context - maxOutput - reserved
87+
const headroom = Math.max(reserved, maxOutput)
88+
const usable = (input.model.limit.input ?? context) - headroom
9089
return count >= usable
9190
}
9291

packages/altimate-code/test/session/compaction-loop.test.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,9 @@ describe("session.compaction.isOverflow boundary conditions", () => {
409409
await Instance.provide({
410410
directory: tmp.path,
411411
fn: async () => {
412-
// context=100K, output=32K → usable = 100K - 32K - 20K(buffer) = 48K
412+
// context=100K, output=32K → headroom = max(20K, 32K) = 32K → usable = 68K
413413
const model = createModel({ context: 100_000, output: 32_000 })
414-
const tokens = { input: 48_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
414+
const tokens = { input: 68_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
415415
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
416416
},
417417
})
@@ -423,8 +423,8 @@ describe("session.compaction.isOverflow boundary conditions", () => {
423423
directory: tmp.path,
424424
fn: async () => {
425425
const model = createModel({ context: 100_000, output: 32_000 })
426-
// usable = 100K - 32K - 20K = 48K; count = 47999
427-
const tokens = { input: 47_999, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
426+
// headroom = max(20K, 32K) = 32K → usable = 68K; count = 67999
427+
const tokens = { input: 67_999, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
428428
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
429429
},
430430
})
@@ -436,12 +436,13 @@ describe("session.compaction.isOverflow boundary conditions", () => {
436436
directory: tmp.path,
437437
fn: async () => {
438438
const model = createModel({ context: 100_000, output: 32_000 })
439-
// total=50K > usable=48K → overflow
439+
// headroom = max(20K, 32K) = 32K → usable = 68K
440+
// total=70K > usable=68K → overflow
440441
// component sum would be 10K (not overflow) — total should take precedence
441442
const tokens = {
442443
input: 5_000, output: 5_000, reasoning: 0,
443444
cache: { read: 0, write: 0 },
444-
total: 50_000,
445+
total: 70_000,
445446
}
446447
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
447448
},
@@ -454,9 +455,10 @@ describe("session.compaction.isOverflow boundary conditions", () => {
454455
directory: tmp.path,
455456
fn: async () => {
456457
const model = createModel({ context: 100_000, output: 32_000 })
457-
// sum = 10K + 5K + 20K + 15K = 50K > usable 48K
458+
// headroom = max(20K, 32K) = 32K → usable = 68K
459+
// sum = 30K + 10K + 20K + 15K = 75K > usable 68K
458460
const tokens = {
459-
input: 10_000, output: 5_000, reasoning: 0,
461+
input: 30_000, output: 10_000, reasoning: 0,
460462
cache: { read: 20_000, write: 15_000 },
461463
}
462464
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
@@ -502,10 +504,10 @@ describe("session.compaction.isOverflow boundary conditions", () => {
502504
await Instance.provide({
503505
directory: tmp.path,
504506
fn: async () => {
505-
// context=200K, output=32K, reserved=50K → usable=200K-32K-50K=118K
507+
// context=200K, output=32K, reserved=50K → headroom=max(50K,32K)=50K → usable=150K
506508
const model = createModel({ context: 200_000, output: 32_000 })
507-
// 120K > 118K → overflow
508-
const tokens = { input: 120_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
509+
// 151K > 150K → overflow
510+
const tokens = { input: 151_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
509511
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
510512
},
511513
})
@@ -523,9 +525,10 @@ describe("session.compaction.isOverflow boundary conditions", () => {
523525
await Instance.provide({
524526
directory: tmp.path,
525527
fn: async () => {
526-
// input=200K, output=32K, reserved=50K → reserved=max(50K,32K)=50K → usable=150K
528+
// input=200K, output=32K, reserved=50K → headroom=max(50K,32K)=50K → usable=150K
527529
const model = createModel({ context: 200_000, input: 200_000, output: 32_000 })
528-
const tokens = { input: 150_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
530+
// 151K > 150K → overflow
531+
const tokens = { input: 151_000, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }
529532
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
530533
},
531534
})

0 commit comments

Comments
 (0)