fix(core): honor compaction agent model for summaries (#53276)

Co-authored-by: Padure Sergio <70955746+sergiopadure@users.noreply.github.com>
This commit is contained in:
Aiden Cline
2026-10-04 23:20:24 -05:00
committed by GitHub
Unverified
parent 30f4119459
commit cb389aa679
4 changed files with 37 additions and 12 deletions
+25 -10
View File
@@ -19,9 +19,11 @@ import type { SessionCompactionResult } from "@opencode/plugin/effect/session"
import type { SessionError } from "@opencode/schema/session-error"
import { makeLocationNode } from "@opencode/util/effect/app-node"
import { Context, Effect, Layer, Result, Stream } from "effect"
import { Agent } from "../agent.js"
import { Bus } from "../bus.js"
import { Database } from "../database/database.js"
import { llmClient } from "../effect/app-node-platform.js"
import { Model } from "../model.js"
import { State } from "../state.js"
import { Token } from "../util/token.js"
import type { SessionContext } from "./context.js"
@@ -30,6 +32,7 @@ import { SessionHistory } from "./history.js"
import type { SessionMessage } from "./message.js"
import { SessionModelRequest } from "./model-request.js"
import { SessionProviderContext } from "./provider-context.js"
import { SessionRunnerModel } from "./runner/model.js"
import { SessionRunnerRetry } from "./runner/retry.js"
import { toLLMMessages } from "./runner/to-llm-message.js"
import { contentFilterError, toSessionError } from "./to-session-error.js"
@@ -181,8 +184,11 @@ const LEGACY_HEADING = "## Additional Context"
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const agents = yield* Agent.Service
const bus = yield* Bus.Service
const llm = yield* LLMClient.Service
const catalog = yield* Model.Service
const models = yield* SessionRunnerModel.Service
const db = (yield* Database.Service).db
const requests = yield* SessionModelRequest.Service
@@ -202,24 +208,33 @@ export const layer = Layer.effect(
// Only the user compacts when automatic compaction is off, overflow included.
if (trigger.reason !== "manual" && !settings.auto) return { status: "skipped" }
const ceiling = calculateCeiling(context.model.limit, settings.buffer)
if (trigger.reason === "auto" && !due(context, ceiling)) return { status: "skipped" }
if (trigger.reason === "auto" && !due(context, calculateCeiling(context.model.limit, settings.buffer)))
return { status: "skipped" }
const native = context.model.compaction?.type === "native"
const agent = native ? undefined : yield* agents.get(Agent.ID.make("compaction"))
const model =
(agent?.model &&
(yield* models
.resolve({ ...context.session, model: agent.model }, catalog.available)
.pipe(Effect.orElseSucceed(() => undefined)))) ??
context.model
const ceiling = calculateCeiling(model.limit, settings.buffer)
// An unknown window never triggers auto compaction, but the compaction request still needs a size to aim for.
const cap = Number.isFinite(ceiling)
? ceiling
: calculateCeiling({ ...context.model.limit, context: UNKNOWN_WINDOW }, settings.buffer)
: calculateCeiling({ ...model.limit, context: UNKNOWN_WINDOW }, settings.buffer)
// The provider just rejected this context, so the estimate ran low; the first attempt already aims below it.
const budget =
trigger.reason === "overflow" ? Math.min(cap, Math.floor(estimateContext(context) * SHRINK_STEPS[0])) : cap
const compaction =
context.model.compaction?.type === "native"
? compactNatively(trigger, budget, settings.keep)
: summarize(trigger, budget, settings.keep)
const selected = model === context.model ? trigger : { ...trigger, context: { ...context, model } }
const compaction = native
? compactNatively(selected, budget, settings.keep)
: summarize(selected, budget, settings.keep)
return yield* compaction.pipe(
Effect.matchEffect({
onSuccess: (result) => publish(trigger, result),
onFailure: (failure) => publish(trigger, failure),
onSuccess: (result) => publish(selected, result),
onFailure: (failure) => publish(selected, failure),
}),
)
})
@@ -662,7 +677,7 @@ export const layer = Layer.effect(
export const node = makeLocationNode({
service: Service,
layer,
deps: [Bus.node, Database.node, llmClient, SessionModelRequest.node],
deps: [Agent.node, Bus.node, Database.node, llmClient, Model.node, SessionModelRequest.node, SessionRunnerModel.node],
})
/** History loads from the latest completed compaction, so a previous one is always the first message. */
@@ -46,6 +46,7 @@ const it = testEffect(
}),
),
Config.node.replace(config),
Location.node.replace(Location.boundNode({ directory: AbsolutePath.make("/tmp") })),
]),
),
)
@@ -18,6 +18,7 @@ import { SessionRunnerModel } from "@opencode/core/session/runner/model"
import { SessionTable } from "@opencode/core/session/sql"
import { SessionStore } from "@opencode/core/session/store"
import { Session } from "@opencode/core/session"
import { Location } from "@opencode/core/location"
import { Project } from "@opencode/core/project"
import { ProjectTable } from "@opencode/core/project/sql"
import { App } from "@opencode/core/app"
@@ -87,7 +88,11 @@ const it = testEffect(
SessionModelRequest.node,
PluginHooks.node,
]),
[Bus.node.replace(Bus.configured({ persist: true })), llmClient.replace(client)],
[
Bus.node.replace(Bus.configured({ persist: true })),
llmClient.replace(client),
Location.node.replace(Location.boundNode({ directory: AbsolutePath.make("/project") })),
],
),
)
@@ -8,6 +8,7 @@ import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder"
import { llmClient } from "@opencode/core/effect/app-node-platform"
import { Instructions } from "@opencode/core/instructions/index"
import { PluginHooks } from "@opencode/core/plugin/hooks"
import { Location } from "@opencode/core/location"
import { Project } from "@opencode/core/project"
import { ProjectTable } from "@opencode/core/project/sql"
import { AbsolutePath } from "@opencode/core/schema"
@@ -40,7 +41,10 @@ const it = testEffect(
PluginHooks.node,
llmClient,
]),
[Bus.node.replace(Bus.configured({ persist: true }))],
[
Bus.node.replace(Bus.configured({ persist: true })),
Location.node.replace(Location.boundNode({ directory: AbsolutePath.make("/project") })),
],
),
)