mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-29 21:42:57 +00:00
fix(core): respect automatic compaction opt-out on overflow (#45036)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
This commit is contained in:
parent
61dd296161
commit
b79cad5ec8
5 changed files with 35 additions and 2 deletions
|
|
@ -103,6 +103,7 @@ export type Outcome =
|
|||
| Pick<SessionMessage.CompactionFailed, "status" | "error">
|
||||
|
||||
export interface Interface extends State.Transformable<Draft> {
|
||||
readonly enabled: () => boolean
|
||||
readonly required: (input: RequiredInput) => boolean
|
||||
readonly compact: (input: AutoInput) => Effect.Effect<Outcome>
|
||||
readonly compactManual: (input: ManualInput) => Effect.Effect<Outcome>
|
||||
|
|
@ -405,6 +406,7 @@ const make = (dependencies: Dependencies) => {
|
|||
return Service.of({
|
||||
transform: state.transform,
|
||||
reload: state.reload,
|
||||
enabled: () => state.get().auto,
|
||||
required,
|
||||
compact,
|
||||
compactManual,
|
||||
|
|
|
|||
|
|
@ -508,6 +508,7 @@ const layer = Layer.effect(
|
|||
// restart the step instead of surfacing the provider error.
|
||||
if (
|
||||
recoverOverflow &&
|
||||
compaction.enabled() &&
|
||||
!publisher.record().outputStarted &&
|
||||
isContextOverflowFailure(overflowFailure ?? streamFailure) &&
|
||||
(yield* restore(compaction.compact(compactionInput))).status === "completed"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { Session } from "@opencode-ai/core/session"
|
|||
import { Snapshot } from "@opencode-ai/core/snapshot"
|
||||
import { SessionEvent } from "@opencode-ai/core/session/event"
|
||||
import { SessionContext } from "@opencode-ai/core/session/context"
|
||||
import { SessionCompaction } from "@opencode-ai/core/session/compaction"
|
||||
import { SessionInbox } from "@opencode-ai/core/session/inbox"
|
||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||
import { SessionModelRequest } from "@opencode-ai/core/session/model-request"
|
||||
|
|
@ -458,6 +459,7 @@ const it = testEffect(
|
|||
Config.node,
|
||||
Snapshot.node,
|
||||
SessionContext.node,
|
||||
SessionCompaction.node,
|
||||
SessionModelRequest.node,
|
||||
SessionRunnerLLM.node,
|
||||
SessionExecution.node,
|
||||
|
|
@ -2560,6 +2562,34 @@ describe("SessionRunnerLLM", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("does not recover provider context overflow when automatic compaction is disabled", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setupOverflowRecovery
|
||||
const compaction = yield* SessionCompaction.Service
|
||||
yield* compaction.transform((draft) => draft.configure({ auto: false }))
|
||||
yield* TestLLM.push(
|
||||
[LLMEvent.providerError({ message: "prompt too long", classification: "context-overflow" })],
|
||||
TestLLM.text("Must not compact", "text-unexpected-summary"),
|
||||
TestLLM.text("Must not retry", "text-unexpected-retry"),
|
||||
)
|
||||
yield* admit(session, "Continue")
|
||||
expect((yield* session.resume(sessionID).pipe(Effect.flip)).message).toBe("prompt too long")
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(yield* session.context(sessionID)).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: "assistant",
|
||||
finish: "error",
|
||||
error: expect.objectContaining({ message: "prompt too long" }),
|
||||
}),
|
||||
)
|
||||
expect(yield* session.context(sessionID)).not.toContainEqual(expect.objectContaining({ type: "compaction" }))
|
||||
expect(yield* recordedEventTypes(sessionID)).not.toContain(
|
||||
Bus.versionedType(SessionEvent.Compaction.Started.type, 1),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("recovers from provider context overflow without a configured context limit", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setupOverflowRecovery
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Add `compaction` to any [OpenCode configuration file](/config):
|
|||
|
||||
| Field | Default | V2 behavior |
|
||||
| ------------- | ------: | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `auto` | `true` | Runs the preflight context-size check. It does not disable manual compaction or one-shot provider-overflow recovery. |
|
||||
| `auto` | `true` | Enables preflight context-size checks and one-shot provider-overflow recovery. Disabling it does not affect manual compaction. |
|
||||
| `keep.tokens` | `15000` | Approximate number of tokens from the newest serialized conversation context to retain beside the summary. |
|
||||
| `buffer` | `20000` | Safety reserve below an explicit input limit. Without one, it is the minimum context reserve and the model output allowance wins when larger. |
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Before each Step, the runner estimates the complete model-visible request agains
|
|||
|
||||
The full transcript remains durable. Active model history after the compaction boundary contains the summary and retained recent context; provider-native continuation state does not cross that boundary.
|
||||
|
||||
If the provider reports context overflow before durable assistant output or tool execution, the runner may perform one overflow-triggered compaction and rebuild the same logical Step. A second overflow or any overflow after durable output is terminal.
|
||||
If automatic compaction is enabled and the provider reports context overflow before durable assistant output or tool execution, the runner may perform one overflow-triggered compaction and rebuild the same logical Step. A second overflow, any overflow after durable output, or an overflow when automatic compaction is disabled is terminal.
|
||||
|
||||
## Durable Events Are Session-Scoped
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue