diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 64ae801d18f..91365368f42 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -48,6 +48,10 @@ export namespace Flag { export const OPENCODE_EXPERIMENTAL_MARKDOWN = truthy("OPENCODE_EXPERIMENTAL_MARKDOWN") export const OPENCODE_MODELS_URL = process.env["OPENCODE_MODELS_URL"] export const OPENCODE_MODELS_PATH = process.env["OPENCODE_MODELS_PATH"] + export const OPENCODE_EXPERIMENTAL_COMPACTION_PRESERVE_PREFIX = truthy( + "OPENCODE_EXPERIMENTAL_COMPACTION_PRESERVE_PREFIX", + ) + export const OPENCODE_EXPERIMENTAL_COMPACTION_PROMPT = process.env["OPENCODE_EXPERIMENTAL_COMPACTION_PROMPT"] function number(key: string) { const value = process.env[key] diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index fb382530291..b722ae9a0e3 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -14,6 +14,9 @@ import { fn } from "@/util/fn" import { Agent } from "@/agent/agent" import { Plugin } from "@/plugin" import { Config } from "@/config/config" +import { Flag } from "../flag/flag" +import { SystemPrompt } from "./system" +import { InstructionPrompt } from "./instruction" export namespace SessionCompaction { const log = Log.create({ service: "session.compaction" }) @@ -97,7 +100,8 @@ export namespace SessionCompaction { auto: boolean }) { const userMessage = input.messages.findLast((m) => m.info.id === input.parentID)!.info as MessageV2.User - const agent = await Agent.get("compaction") + const usePrefixCache = Flag.OPENCODE_EXPERIMENTAL_COMPACTION_PRESERVE_PREFIX + const agent = usePrefixCache ? await Agent.get(userMessage.agent) : await Agent.get("compaction") const model = agent.model ? await Provider.getModel(agent.model.providerID, agent.model.modelID) : await Provider.getModel(userMessage.model.providerID, userMessage.model.modelID) @@ -132,22 +136,38 @@ export namespace SessionCompaction { model, abort: input.abort, }) + const session = usePrefixCache ? await Session.get(input.sessionID) : undefined + let tools = {} + let system: string[] = [] + if (usePrefixCache && session) { + tools = await SessionPrompt.resolveTools({ + agent, + model, + session, + tools: userMessage.tools, + processor, + bypassAgentCheck: false, + messages: input.messages, + }) + system = [...(await SystemPrompt.environment(model)), ...(await InstructionPrompt.system())] + } // Allow plugins to inject context or replace compaction prompt const compacting = await Plugin.trigger( "experimental.session.compacting", { sessionID: input.sessionID }, { context: [], prompt: undefined }, ) - const defaultPrompt = + const defaultPrompt = Flag.OPENCODE_EXPERIMENTAL_COMPACTION_PROMPT ?? "Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation." + const promptText = compacting.prompt ?? [defaultPrompt, ...compacting.context].join("\n\n") - const result = await processor.process({ + let result = await processor.process({ user: userMessage, agent, abort: input.abort, sessionID: input.sessionID, - tools: {}, - system: [], + tools, + system, messages: [ ...MessageV2.toModelMessages(input.messages, model), { @@ -163,6 +183,10 @@ export namespace SessionCompaction { model, }) + // ignore compact-flag for usePrefixCache + // needsCompact is currently set before context recalc and we don't utilize remove-tools-trick + result = usePrefixCache && result == "compact" ? "continue" : result + if (result === "continue" && input.auto) { const continueMsg = await Session.updateMessage({ id: Identifier.ascending("message"), diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 94eabdef7f4..c7812fe125c 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -647,7 +647,7 @@ export namespace SessionPrompt { return Provider.defaultModel() } - async function resolveTools(input: { + export async function resolveTools(input: { agent: Agent.Info model: Provider.Model session: Session.Info