Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ const InfoSchema = Schema.Struct({
description:
"Number of recent user turns, including their following assistant/tool responses, to keep verbatim during compaction (default: 2)",
}),
tail_tokens: Schema.optional(NonNegativeInt).annotate({
description: "Token budget for retained recent turn spans during compaction",
preserve_recent_tokens: Schema.optional(NonNegativeInt).annotate({
description: "Maximum number of tokens from recent turns to preserve verbatim after compaction",
}),
reserved: Schema.optional(NonNegativeInt).annotate({
description: "Token buffer for compaction. Leaves enough window to avoid overflow during compaction.",
Expand Down
15 changes: 9 additions & 6 deletions packages/opencode/src/session/compaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ export const PRUNE_MINIMUM = 20_000
export const PRUNE_PROTECT = 40_000
const PRUNE_PROTECTED_TOOLS = ["skill"]
const DEFAULT_TAIL_TURNS = 2
const MIN_TAIL_TOKENS = 2_000
const MAX_TAIL_TOKENS = 8_000
const MIN_PRESERVE_RECENT_TOKENS = 2_000
const MAX_PRESERVE_RECENT_TOKENS = 8_000
type Turn = {
start: number
end: number
id: MessageID
}

function tailBudget(input: { cfg: Config.Info; model: Provider.Model }) {
function preserveRecentBudget(input: { cfg: Config.Info; model: Provider.Model }) {
return (
input.cfg.compaction?.tail_tokens ??
Math.min(MAX_TAIL_TOKENS, Math.max(MIN_TAIL_TOKENS, Math.floor(usable(input) * 0.25)))
input.cfg.compaction?.preserve_recent_tokens ??
Math.min(
MAX_PRESERVE_RECENT_TOKENS,
Math.max(MIN_PRESERVE_RECENT_TOKENS, Math.floor(usable(input) * 0.25)),
)
)
}

Expand Down Expand Up @@ -134,7 +137,7 @@ export const layer: Layer.Layer<
}) {
const limit = input.cfg.compaction?.tail_turns ?? DEFAULT_TAIL_TURNS
if (limit <= 0) return { head: input.messages, tail_start_id: undefined }
const budget = tailBudget({ cfg: input.cfg, model: input.model })
const budget = preserveRecentBudget({ cfg: input.cfg, model: input.model })
const all = turns(input.messages)
if (!all.length) return { head: input.messages, tail_start_id: undefined }
const recent = all.slice(-limit)
Expand Down
16 changes: 8 additions & 8 deletions packages/opencode/test/session/compaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ describe("session.compaction.process", () => {
auto: false,
})

const rt = runtime("continue", Plugin.defaultLayer, wide(), cfg({ tail_turns: 2, tail_tokens: 10_000 }))
const rt = runtime("continue", Plugin.defaultLayer, wide(), cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }))
try {
const msgs = await svc.messages({ sessionID: session.id })
const parent = msgs.at(-1)?.info.id
Expand Down Expand Up @@ -954,7 +954,7 @@ describe("session.compaction.process", () => {
})
})

test("shrinks retained tail to fit tail token budget", async () => {
test("shrinks retained tail to fit preserve token budget", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
Expand All @@ -970,7 +970,7 @@ describe("session.compaction.process", () => {
auto: false,
})

const rt = runtime("continue", Plugin.defaultLayer, wide(), cfg({ tail_turns: 2, tail_tokens: 100 }))
const rt = runtime("continue", Plugin.defaultLayer, wide(), cfg({ tail_turns: 2, preserve_recent_tokens: 100 }))
try {
const msgs = await svc.messages({ sessionID: session.id })
const parent = msgs.at(-1)?.info.id
Expand Down Expand Up @@ -999,7 +999,7 @@ describe("session.compaction.process", () => {
})
})

test("falls back to full summary when even one recent turn exceeds tail budget", async () => {
test("falls back to full summary when even one recent turn exceeds preserve token budget", async () => {
await using tmp = await tmpdir({ git: true })
const stub = llm()
let captured = ""
Expand All @@ -1021,7 +1021,7 @@ describe("session.compaction.process", () => {
auto: false,
})

const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 1, tail_tokens: 20 }))
const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 1, preserve_recent_tokens: 20 }))
try {
const msgs = await svc.messages({ sessionID: session.id })
const parent = msgs.at(-1)?.info.id
Expand Down Expand Up @@ -1051,7 +1051,7 @@ describe("session.compaction.process", () => {
})
})

test("falls back to full summary when retained tail media exceeds tail budget", async () => {
test("falls back to full summary when retained tail media exceeds preserve token budget", async () => {
await using tmp = await tmpdir({ git: true })
const stub = llm()
let captured = ""
Expand Down Expand Up @@ -1082,7 +1082,7 @@ describe("session.compaction.process", () => {
auto: false,
})

const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 1, tail_tokens: 100 }))
const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 1, preserve_recent_tokens: 100 }))
try {
const msgs = await svc.messages({ sessionID: session.id })
const parent = msgs.at(-1)?.info.id
Expand Down Expand Up @@ -1544,7 +1544,7 @@ describe("session.compaction.process", () => {
auto: false,
})

const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 2, tail_tokens: 10_000 }))
const rt = liveRuntime(stub.layer, wide(), cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }))
try {
let msgs = await svc.messages({ sessionID: session.id })
let parent = msgs.at(-1)?.info.id
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1648,9 +1648,9 @@ export type Config = {
*/
tail_turns?: number
/**
* Token budget for retained recent turn spans during compaction
* Maximum number of tokens from recent turns to preserve verbatim after compaction
*/
tail_tokens?: number
preserve_recent_tokens?: number
/**
* Token buffer for compaction. Leaves enough window to avoid overflow during compaction.
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -11878,8 +11878,8 @@
"minimum": 0,
"maximum": 9007199254740991
},
"tail_tokens": {
"description": "Token budget for retained recent turn spans during compaction",
"preserve_recent_tokens": {
"description": "Maximum number of tokens from recent turns to preserve verbatim after compaction",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
Expand Down
Loading