diff --git a/packages/core/src/config/compaction.ts b/packages/core/src/config/compaction.ts index 3c5960c835..8d4fb822b8 100644 --- a/packages/core/src/config/compaction.ts +++ b/packages/core/src/config/compaction.ts @@ -7,9 +7,13 @@ export class Keep extends Schema.Class("ConfigV2.Compaction.Keep")({ tokens: NonNegativeInt.pipe(Schema.optional), }) {} +export class BufferPercent extends Schema.Class("ConfigV2.Compaction.BufferPercent")({ + percent: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(100)), +}) {} + export class Info extends Schema.Class("ConfigV2.Compaction")({ auto: Schema.Boolean.pipe(Schema.optional), prune: Schema.Boolean.pipe(Schema.optional), keep: Keep.pipe(Schema.optional), - buffer: NonNegativeInt.pipe(Schema.optional), + buffer: Schema.Union([NonNegativeInt, BufferPercent]).pipe(Schema.optional), }) {} diff --git a/packages/core/src/session/compaction.ts b/packages/core/src/session/compaction.ts index 4b21ff348f..82ec2051ff 100644 --- a/packages/core/src/session/compaction.ts +++ b/packages/core/src/session/compaction.ts @@ -52,7 +52,7 @@ type Entry = { type Settings = { readonly auto: boolean - readonly buffer: number + readonly buffer: number | { readonly percent: number } readonly tokens: number } @@ -227,9 +227,10 @@ export const make = (dependencies: Dependencies) => { const context = input.model.route.defaults.limits?.context if (context === undefined || context <= 0) return false const output = input.request.generation?.maxTokens ?? input.model.route.defaults.limits?.output ?? 0 + const buffer = typeof config.buffer === "number" ? config.buffer : context * (config.buffer.percent / 100) if ( estimate({ system: input.request.system, messages: input.request.messages, tools: input.request.tools }) <= - context - Math.max(output, config.buffer) + context - Math.max(output, buffer) ) return false return yield* compactAfterOverflow(input) diff --git a/packages/core/test/config/config.test.ts b/packages/core/test/config/config.test.ts index c3c42cab30..383d99b5b1 100644 --- a/packages/core/test/config/config.test.ts +++ b/packages/core/test/config/config.test.ts @@ -4,6 +4,7 @@ import { describe, expect } from "bun:test" import { Effect, Layer, Schema } from "effect" import { FastCheck } from "effect/testing" import { Config } from "@opencode-ai/core/config" +import { ConfigCompaction } from "@opencode-ai/core/config/compaction" import { ConfigProvider } from "@opencode-ai/core/config/provider" import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" import { LayerNode } from "@opencode-ai/core/effect/layer-node" @@ -52,6 +53,16 @@ const provider = { } describe("Config", () => { + it.effect("accepts token and percentage compaction buffers", () => + Effect.sync(() => { + expect(Schema.decodeUnknownSync(ConfigCompaction.Info)({ buffer: 20_000 }).buffer).toBe(20_000) + expect(Schema.decodeUnknownSync(ConfigCompaction.Info)({ buffer: { percent: 10 } }).buffer).toEqual({ + percent: 10, + }) + expect(() => Schema.decodeUnknownSync(ConfigCompaction.Info)({ buffer: { percent: 101 } })).toThrow() + }), + ) + it.effect("returns the latest defined scalar from priority-ordered documents", () => Effect.sync(() => { const entries = [ diff --git a/packages/core/test/session-runner.test.ts b/packages/core/test/session-runner.test.ts index 0515d55cf5..9f5ff53beb 100644 --- a/packages/core/test/session-runner.test.ts +++ b/packages/core/test/session-runner.test.ts @@ -217,7 +217,7 @@ const config = Layer.succeed( type: "document", info: new Config.Info({ compaction: new ConfigCompaction.Info({ - buffer: 3_000, + buffer: new ConfigCompaction.BufferPercent({ percent: 75 }), keep: new ConfigCompaction.Keep({ tokens: 1_000 }), }), }),