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
3 changes: 2 additions & 1 deletion packages/core/src/session/compaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Token } from "../util/token"

const DEFAULT_BUFFER = 20_000
const DEFAULT_KEEP_TOKENS = 8_000
const OUTPUT_TOKEN_MAX = 32_000
const TOOL_OUTPUT_MAX_CHARS = 2_000
const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response.
<template>
Expand Down Expand Up @@ -320,7 +321,7 @@ const make = (dependencies: Dependencies) => {
message.type === "assistant" && message.tokens !== undefined,
)
if (!last) return false
const output = input.model.route.defaults.limits?.output ?? 0
const output = Math.min(input.model.route.defaults.limits?.output ?? 0, OUTPUT_TOKEN_MAX)
const used =
last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
if (used <= 0) return false
Expand Down
24 changes: 24 additions & 0 deletions packages/core/test/session-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ const compactModel = Model.make({
provider: "fake",
route: OpenAIChat.route.with({ limits: { context: 4_000, output: 50 } }),
})
const fullOutputModel = Model.make({
id: "full-output",
provider: "fake",
route: OpenAIChat.route.with({ limits: { context: 262_144, output: 262_144 } }),
})
const undersizedContextModel = Model.make({
id: "undersized-context",
provider: "fake",
Expand Down Expand Up @@ -1865,6 +1870,25 @@ describe("SessionRunnerLLM", () => {
}),
)

it.effect("does not compact immediately when the advertised output limit fills the context", () =>
Effect.gen(function* () {
const session = yield* setup
currentModel = fullOutputModel
response = reply.textWithUsage("Earlier answer", "text-full-output-first", 9_500)
yield* admit(session, "Earlier question")
yield* session.resume(sessionID)

requests.length = 0
response = reply.text("Continued", "text-full-output-final")
yield* admit(session, "Continue")
yield* session.resume(sessionID)

expect(requests).toHaveLength(1)
expect(userTexts(requests[0])).toContain("Continue")
expect(yield* session.context(sessionID)).not.toContainEqual(expect.objectContaining({ type: "compaction" }))
}),
)

it.effect("stops after required automatic compaction fails", () =>
Effect.gen(function* () {
const session = yield* setup
Expand Down
Loading