diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index 6fd225dbb6..7b813b1226 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Enforce configurable active-context ceilings for compaction and preserve large-window request-shape stability across turns and session branches. + ### Breaking Changes ### Added diff --git a/packages/agent/src/changes.md b/packages/agent/src/changes.md index 70b0c90623..efb1b23e82 100644 --- a/packages/agent/src/changes.md +++ b/packages/agent/src/changes.md @@ -1,5 +1,24 @@ # Changes +## 2026-08-23 - Harness compaction honors an active-context ceiling + +### What changed + +- `packages/agent/src/harness/compaction/compaction.ts` carries the optional `maxContextTokens` setting and applies it in the public `shouldCompact()` helper, bounded by the physical context window and reserve. + +### Why + +- Public harness consumers configuring a smaller active budget on a large-context model otherwise continued to compact only near the physical window limit. + +### Why an extension could not handle it + +- The exported harness threshold helper is evaluated by agent-core consumers outside the coding-agent extension runtime. + +### Expected merge conflict zones + +- LOW: `packages/agent/src/harness/compaction/compaction.ts` compaction settings and `shouldCompact()`. + + ## 2026-08-20 - End the turn when idle after completed Cursor tools ### What changed diff --git a/packages/agent/src/harness/compaction/compaction.ts b/packages/agent/src/harness/compaction/compaction.ts index 905941d83c..716dca7c98 100644 --- a/packages/agent/src/harness/compaction/compaction.ts +++ b/packages/agent/src/harness/compaction/compaction.ts @@ -152,6 +152,8 @@ export interface CompactionSettings { reserveTokens: number; /** Approximate recent-context tokens to keep after compaction. */ keepRecentTokens: number; + /** Explicit active context ceiling override. */ + maxContextTokens?: number; } /** Default compaction settings used by the harness. */ @@ -246,7 +248,11 @@ export function estimateContextTokens(messages: AgentMessage[]): ContextUsageEst /** Return whether context usage exceeds the configured compaction threshold. */ export function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings): boolean { if (!settings.enabled) return false; - return contextTokens > contextWindow - settings.reserveTokens; + const activeCeiling = + settings.maxContextTokens && settings.maxContextTokens > 0 + ? Math.min(contextWindow - settings.reserveTokens, settings.maxContextTokens) + : contextWindow - settings.reserveTokens; + return contextTokens > activeCeiling; } const ESTIMATED_IMAGE_CHARS = 4800; diff --git a/packages/agent/test/harness/compaction.test.ts b/packages/agent/test/harness/compaction.test.ts index c5021fd53e..827f9b7732 100644 --- a/packages/agent/test/harness/compaction.test.ts +++ b/packages/agent/test/harness/compaction.test.ts @@ -178,6 +178,8 @@ describe("harness compaction", () => { expect(shouldCompact(95000, 100000, settings)).toBe(true); expect(shouldCompact(89000, 100000, settings)).toBe(false); expect(shouldCompact(95000, 100000, { ...settings, enabled: false })).toBe(false); + expect(shouldCompact(45_000, 100_000, { ...settings, maxContextTokens: 40_000 })).toBe(true); + expect(shouldCompact(39_000, 100_000, { ...settings, maxContextTokens: 40_000 })).toBe(false); }); it("finds a cut point based on token differences", () => { diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 26fb82ceb3..78b517e03f 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Enforce configurable active-context ceilings for compaction and preserve large-window request-shape stability across turns and session branches. + ### Breaking Changes ### Fixed diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index d56b0ad489..c9ce5474bd 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -5453,7 +5453,7 @@ export class AgentSession { usageMessage?.role === "assistant" && this._isAssistantFromBeforeLatestCompaction(usageMessage) ? estimateMessagesTokens(providerMessages) : estimate.tokens; - return contextTokens > model.contextWindow - settings.reserveTokens; + return shouldCompact(contextTokens, model.contextWindow, settings); }; if (!settings.enabled || !isOversized()) return; diff --git a/packages/coding-agent/src/core/changes.md b/packages/coding-agent/src/core/changes.md index f2456f767c..0f15205abd 100644 --- a/packages/coding-agent/src/core/changes.md +++ b/packages/coding-agent/src/core/changes.md @@ -1,5 +1,42 @@ # changes +## 2026-08-24 - Enforce the active compaction ceiling during final provider admission + +### What changed + +- `packages/coding-agent/src/core/agent-session.ts` now routes the final assembled-context admission check through the shared `shouldCompact()` policy instead of comparing only against the physical model window minus reserve tokens. + +### Why + +- Turn-local custom messages can push a request above the configured or large-model default active ceiling after the earlier persisted-context check. The final admission path must enforce the same ceiling before sending the provider request. + +### Why an extension could not handle it + +- Final provider admission is a private `AgentSession` guard that runs after context assembly and before dispatch; extensions cannot replace that core oversized-request decision. + +### Expected merge conflict zones + +- LOW: `packages/coding-agent/src/core/agent-session.ts` around `_enforceFinalProviderAdmission()` and its `isOversized` closure. + +## 2026-08-23 - Preserve explicit compaction budget configuration + +### What changed + +- `packages/coding-agent/src/core/settings-manager.ts` accepts and returns `compaction.maxContextTokens`, and records whether `keepRecentTokens` was explicitly configured rather than normalized from the legacy 20k fallback. + +### Why + +- Runtime policy needs to distinguish an intentional 20k retention override from an omitted setting so large-context models receive the new 35k default without discarding user configuration. + +### Why an extension could not handle it + +- Settings parsing and normalization occur in core before extension contexts receive the resolved compaction settings. + +### Expected merge conflict zones + +- LOW: `packages/coding-agent/src/core/settings-manager.ts` compaction settings interface and getters. + + ## 2026-08-22 - Retarget OpenAI automatic defaults to GPT-5.6 Sol ### What changed diff --git a/packages/coding-agent/src/core/compaction/changes.md b/packages/coding-agent/src/core/compaction/changes.md index f99eb8c2d2..9e6c2a4be5 100644 --- a/packages/coding-agent/src/core/compaction/changes.md +++ b/packages/coding-agent/src/core/compaction/changes.md @@ -1,5 +1,24 @@ # changes.md — compaction +## 2026-08-23 - Core compaction enforces configurable active-context ceilings + +### What changed + +- `packages/coding-agent/src/core/compaction/compaction.ts` adds `maxContextTokens` and explicit-retention metadata to compaction settings, and `shouldCompact()` caps large-context sessions at the resolved active budget. + +### Why + +- Physical model windows can be much larger than the stable request budget, so threshold decisions need a separate active-context ceiling while retaining user overrides. + +### Why an extension could not handle it + +- Core admission and queue recovery call `shouldCompact()` before extension compaction hooks can replace the threshold decision. + +### Expected merge conflict zones + +- MEDIUM: `packages/coding-agent/src/core/compaction/compaction.ts` settings and `shouldCompact()`. + + ## 2026-08-20 - Ignore implausible billed usage for compaction threshold ### What changed diff --git a/packages/coding-agent/src/core/compaction/compaction.ts b/packages/coding-agent/src/core/compaction/compaction.ts index 48300f76f5..d9b185d486 100644 --- a/packages/coding-agent/src/core/compaction/compaction.ts +++ b/packages/coding-agent/src/core/compaction/compaction.ts @@ -187,6 +187,9 @@ export interface CompactionSettings { enabled: boolean; reserveTokens: number; keepRecentTokens: number; + /** Whether keepRecentTokens was explicitly configured rather than normalized from a fallback. */ + keepRecentTokensConfigured?: boolean; + maxContextTokens?: number; speculativeEnabled?: boolean; speculativeFraction?: number; speculativeCooldownMs?: number; @@ -339,7 +342,12 @@ export function estimateContextTokens(messages: AgentMessage[]): ContextUsageEst */ export function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings): boolean { if (!settings.enabled) return false; - return contextTokens > contextWindow - settings.reserveTokens; + const isLarge = contextWindow >= 500_000; + const defaultCeiling = isLarge ? 384_000 : Math.max(0, contextWindow - settings.reserveTokens); + const configuredCeiling = + settings.maxContextTokens && settings.maxContextTokens > 0 ? settings.maxContextTokens : defaultCeiling; + const maxActive = Math.min(Math.max(0, contextWindow - settings.reserveTokens), configuredCeiling); + return contextTokens > maxActive; } // ============================================================================ diff --git a/packages/coding-agent/src/core/extensions/builtin/compaction/changes.md b/packages/coding-agent/src/core/extensions/builtin/compaction/changes.md index 379774d329..717184110a 100644 --- a/packages/coding-agent/src/core/extensions/builtin/compaction/changes.md +++ b/packages/coding-agent/src/core/extensions/builtin/compaction/changes.md @@ -1,5 +1,28 @@ # Builtin compaction extension changes +## 2026-08-23 - Active-budget policy and branch-scoped reduction latch + +### What changed + +- `packages/coding-agent/src/core/extensions/builtin/compaction/policy.ts` resolves a 384k active ceiling and 35k retention default for large-context models while honoring explicit overrides. +- `packages/coding-agent/src/core/extensions/builtin/compaction/speculative.ts` carries explicit-retention metadata into compaction preparation. +- `packages/coding-agent/src/core/extensions/builtin/compaction/context-reduction.ts` adds a sticky generation latch so request-shape reduction remains stable until compaction. +- `packages/coding-agent/src/core/extensions/builtin/compaction/index.ts` releases that latch when session-tree navigation changes the active branch and bumps it after accepted compaction. + +### Why + +- Large physical windows can exceed stable request budgets, and threshold oscillation or branch navigation must not leave request shaping stuck on history from a different active branch. + +### Why an extension could not handle it + +- This is the builtin compaction extension's own policy and context-rewrite lifecycle; no outer extension can safely coordinate its private speculative jobs and reduction latch. + +### Expected merge conflict zones + +- MEDIUM: `policy.ts` threshold/retention resolution, `speculative.ts` preparation settings, and `index.ts` session/context handlers. +- LOW: `context-reduction.ts` latch helper. + + ## Skip Cursor compaction while the session is not idle (2026-08-19) Blocking and generated apply refuse `cursor` / `cursor-cli-oauth` when `!ctx.isIdle()`. Mid-run Cursor compact poisons `conversationId`. Idle `agent_end` / `pre_prompt` still compact. diff --git a/packages/coding-agent/src/core/extensions/builtin/compaction/context-reduction.ts b/packages/coding-agent/src/core/extensions/builtin/compaction/context-reduction.ts index 287f5f2096..244f837d58 100644 --- a/packages/coding-agent/src/core/extensions/builtin/compaction/context-reduction.ts +++ b/packages/coding-agent/src/core/extensions/builtin/compaction/context-reduction.ts @@ -144,19 +144,59 @@ export const BUILTIN_CONTEXT_REDUCTION_OPTIONS: ReduceContextOptions = { export const BUILTIN_CONTEXT_REDUCTION_GATE_RATIO = 0.5; +export interface ContextPressure { + activeTokens: number | null; + requestBodyBytes: number | null; + nonReclaimableTokens?: number | null; + generation: number; +} + +export interface ContextReductionLatch { + isLatched: () => boolean; + engage: () => void; + release: () => void; + getGeneration: () => number; + bumpGeneration: () => void; +} + +export function createContextReductionLatch(): ContextReductionLatch { + let latched = false; + let generation = 0; + return { + isLatched: () => latched, + engage: () => { + latched = true; + }, + release: () => { + latched = false; + }, + getGeneration: () => generation, + bumpGeneration: () => { + generation += 1; + latched = false; + }, + }; +} + export interface ShouldApplyContextReductionInput { usageTokens: number | null; contextWindow: number; gateRatio?: number; isProviderNativeCompactionPath?: boolean; + latch?: ContextReductionLatch; } export function shouldApplyContextReduction(input: ShouldApplyContextReductionInput): boolean { - const gate = input.gateRatio ?? BUILTIN_CONTEXT_REDUCTION_GATE_RATIO; if (input.isProviderNativeCompactionPath === true) return false; + if (input.latch?.isLatched()) return true; if (input.usageTokens === null) return false; if (input.contextWindow <= 0) return false; - return input.usageTokens >= input.contextWindow * gate; + const gate = input.gateRatio ?? BUILTIN_CONTEXT_REDUCTION_GATE_RATIO; + const shouldEngage = input.usageTokens >= input.contextWindow * gate; + if (shouldEngage && input.latch) { + input.latch.engage(); + } + return shouldEngage; } function approxTextTokens(text: string): number { diff --git a/packages/coding-agent/src/core/extensions/builtin/compaction/index.ts b/packages/coding-agent/src/core/extensions/builtin/compaction/index.ts index 4746fee113..18b784161c 100644 --- a/packages/coding-agent/src/core/extensions/builtin/compaction/index.ts +++ b/packages/coding-agent/src/core/extensions/builtin/compaction/index.ts @@ -15,6 +15,7 @@ import * as checkpointState from "./checkpoint-state.ts"; import * as breaker from "./circuit-breaker.ts"; import { BUILTIN_CONTEXT_REDUCTION_OPTIONS, + createContextReductionLatch, reduceContextMessages, shouldApplyContextReduction, } from "./context-reduction.ts"; @@ -193,6 +194,7 @@ export default function compactionExtension( const lanePolicy = createCompactionLanePolicy(); const restorationDirectiveState = checkpointState.createRestorationDirectiveState(); const emergencyPruneLatch = createEmergencyPruneLatch(); + const contextReductionLatch = createContextReductionLatch(); const degradationState = createDegradationMonitorState(); const restorationState = state.restoration ?? restoration.createRestorationTrackerState(); state = { ...state, restoration: restorationState }; @@ -717,6 +719,7 @@ export default function compactionExtension( }); pi.on("model_select", (event, ctx) => { + contextReductionLatch.bumpGeneration(); if (lanePolicy.disablesSenpiCompaction(ctx)) { invalidateSpeculativeCompaction(ctx); return; @@ -746,10 +749,15 @@ export default function compactionExtension( } }); + pi.on("session_tree", () => { + contextReductionLatch.bumpGeneration(); + }); + pi.on("session_compact", async (event: SessionCompactEvent, ctx) => { const compactEvent = event; invalidateSpeculativeCompaction(ctx); if (compactEvent.accepted) { + contextReductionLatch.bumpGeneration(); persistAcceptedMetadata(compactEvent.requestId); const branchEntries = ctx.sessionManager.getBranch(); const firstKeptIndex = branchEntries.findIndex( @@ -874,6 +882,7 @@ export default function compactionExtension( contextWindow, isProviderNativeCompactionPath: isOpenAiRemoteCompactionModel(ctx.model) || lanePolicy.disablesSenpiCompaction(ctx), + latch: contextReductionLatch, }) ? reduceContextMessages(event.messages, BUILTIN_CONTEXT_REDUCTION_OPTIONS).messages : event.messages; diff --git a/packages/coding-agent/src/core/extensions/builtin/compaction/policy.ts b/packages/coding-agent/src/core/extensions/builtin/compaction/policy.ts index c4e46368e8..d95174ff49 100644 --- a/packages/coding-agent/src/core/extensions/builtin/compaction/policy.ts +++ b/packages/coding-agent/src/core/extensions/builtin/compaction/policy.ts @@ -9,12 +9,65 @@ const YIELD_ADJUSTMENT_RATIO = 0.05; const MIN_EFFECTIVE_KEEP_RECENT_TOKENS = 1024; export const SPECULATIVE_FRACTION = 0.75; +export const DEFAULT_1M_CEILING = 384_000; +export const DEFAULT_1M_KEEP_RECENT = 35_000; +export const DEFAULT_STANDARD_KEEP_RECENT = 20_000; +export const DEFAULT_WARMUP_FRACTION = 0.75; +export const DEFAULT_TARGET_ACTIVE_FRACTION = 0.6; +export const DEFAULT_RESERVE_TOKENS = 16_384; +export const LARGE_WINDOW_THRESHOLD = 500_000; + +export interface ContextBudgetPolicy { + physicalContextWindow: number; + maxActiveContextTokens: number; + keepRecentTokens: number; + warmupFraction: number; + targetActiveFraction: number; + reserveTokens: number; + emergencyHardLimitTokens: number; +} export interface CompactionYield { savedTokens: number; tokensBefore: number; } +export function isLargeContextModel(contextWindow: number): boolean { + return contextWindow >= LARGE_WINDOW_THRESHOLD; +} + +export function resolveContextBudgetPolicy( + contextWindow: number, + settings?: Partial, +): ContextBudgetPolicy { + const isLarge = isLargeContextModel(contextWindow); + const reserveTokens = settings?.reserveTokens ?? DEFAULT_RESERVE_TOKENS; + const defaultCeiling = isLarge ? DEFAULT_1M_CEILING : Math.max(0, contextWindow - reserveTokens); + const configuredCeiling = + settings?.maxContextTokens && settings.maxContextTokens > 0 ? settings.maxContextTokens : defaultCeiling; + + const maxActiveContextTokens = Math.min(Math.max(0, contextWindow - reserveTokens), configuredCeiling); + + const defaultKeepRecent = isLarge ? DEFAULT_1M_KEEP_RECENT : DEFAULT_STANDARD_KEEP_RECENT; + const keepRecentTokens = + settings?.keepRecentTokensConfigured === false + ? defaultKeepRecent + : (settings?.keepRecentTokens ?? defaultKeepRecent); + const warmupFraction = settings?.speculativeFraction ?? DEFAULT_WARMUP_FRACTION; + const targetActiveFraction = DEFAULT_TARGET_ACTIVE_FRACTION; + const emergencyHardLimitTokens = Math.max(0, contextWindow - Math.floor(reserveTokens / 2)); + + return { + physicalContextWindow: contextWindow, + maxActiveContextTokens, + keepRecentTokens, + warmupFraction, + targetActiveFraction, + reserveTokens, + emergencyHardLimitTokens, + }; +} + function clampThresholdRatio(ratio: number): number { return Math.min(MAX_ADAPTIVE_THRESHOLD_RATIO, Math.max(MIN_ADAPTIVE_THRESHOLD_RATIO, ratio)); } @@ -84,14 +137,32 @@ export function computeEffectiveThreshold(contextWindow: number, lastYield?: Com return clampThresholdRatio(ratio); } +export function computeEffectiveBlockingThresholdTokens( + contextWindow: number, + settings?: Partial, + lastYield?: CompactionYield | number, +): number { + const ratio = computeEffectiveThreshold(contextWindow, lastYield); + const ratioTokens = Math.floor(contextWindow * ratio); + if (isLargeContextModel(contextWindow) || (settings?.maxContextTokens && settings.maxContextTokens > 0)) { + const policy = resolveContextBudgetPolicy(contextWindow, settings); + return Math.min(ratioTokens, policy.maxActiveContextTokens); + } + return ratioTokens; +} + export function computeEffectiveKeepRecentTokens( setting: number, contextWindow: number, thresholdRatio: number, margin = 0.05, + settingConfigured = true, ): number { + const isLarge = isLargeContextModel(contextWindow); + const defaultForModel = isLarge ? DEFAULT_1M_KEEP_RECENT : DEFAULT_STANDARD_KEEP_RECENT; + const effectiveSetting = settingConfigured ? setting : defaultForModel; const capped = Math.floor(contextWindow * (1 - thresholdRatio - margin)); - return Math.min(setting, Math.max(MIN_EFFECTIVE_KEEP_RECENT_TOKENS, capped)); + return Math.min(effectiveSetting, Math.max(MIN_EFFECTIVE_KEEP_RECENT_TOKENS, capped)); } export function shouldStartSpeculativeCompaction( @@ -104,8 +175,10 @@ export function shouldStartSpeculativeCompaction( return false; } - const fraction = settings.speculativeFraction ?? SPECULATIVE_FRACTION; - return usage.tokens >= contextWindow * computeEffectiveThreshold(contextWindow, lastYield) * fraction; + const policy = resolveContextBudgetPolicy(contextWindow, settings); + const blockingThreshold = computeEffectiveBlockingThresholdTokens(contextWindow, settings, lastYield); + const warmupThreshold = Math.floor(blockingThreshold * policy.warmupFraction); + return usage.tokens >= warmupThreshold; } export function isAtHardLimit( @@ -127,5 +200,6 @@ export function shouldTriggerCompaction( return false; } - return usage.tokens >= contextWindow * computeEffectiveThreshold(contextWindow, lastYield); + const blockingThreshold = computeEffectiveBlockingThresholdTokens(contextWindow, settings, lastYield); + return usage.tokens >= blockingThreshold; } diff --git a/packages/coding-agent/src/core/extensions/builtin/compaction/speculative.ts b/packages/coding-agent/src/core/extensions/builtin/compaction/speculative.ts index 161361d598..7c2e46b541 100644 --- a/packages/coding-agent/src/core/extensions/builtin/compaction/speculative.ts +++ b/packages/coding-agent/src/core/extensions/builtin/compaction/speculative.ts @@ -434,7 +434,13 @@ export function createSpeculativeCompactionSnapshot( const thresholdRatio = computeEffectiveThreshold(contextWindow); const preparation = prepareCompaction(branchEntries, { ...settings, - keepRecentTokens: computeEffectiveKeepRecentTokens(settings.keepRecentTokens, contextWindow, thresholdRatio), + keepRecentTokens: computeEffectiveKeepRecentTokens( + settings.keepRecentTokens, + contextWindow, + thresholdRatio, + undefined, + settings.keepRecentTokensConfigured !== false, + ), }); if (!preparation) return undefined; diff --git a/packages/coding-agent/src/core/settings-manager.ts b/packages/coding-agent/src/core/settings-manager.ts index 27989619cb..1c96be91e7 100644 --- a/packages/coding-agent/src/core/settings-manager.ts +++ b/packages/coding-agent/src/core/settings-manager.ts @@ -32,7 +32,8 @@ export const DEFAULT_PROVIDER_STREAM_RETRY_TIMEOUT_MS = 30_000; export interface CompactionSettings { enabled?: boolean; // default: true reserveTokens?: number; // default: 16384 - keepRecentTokens?: number; // default: 20000 + keepRecentTokens?: number; // default: model-specific (35000 for large-context models, otherwise 20000) + maxContextTokens?: number; // default: 384000 for large-context models, otherwise contextWindow - reserveTokens speculativeEnabled?: boolean; // default: true speculativeFraction?: number; // default: 0.75 speculativeCooldownMs?: number; // default: 30000 @@ -1270,6 +1271,8 @@ export class SettingsManager { enabled: boolean; reserveTokens: number; keepRecentTokens: number; + keepRecentTokensConfigured: boolean; + maxContextTokens?: number; speculativeEnabled: boolean; speculativeFraction: number; speculativeCooldownMs: number; @@ -1284,6 +1287,8 @@ export class SettingsManager { enabled: this.getCompactionEnabled(), reserveTokens: this.getCompactionReserveTokens(), keepRecentTokens: this.getCompactionKeepRecentTokens(), + keepRecentTokensConfigured: this.settings.compaction?.keepRecentTokens !== undefined, + maxContextTokens: this.settings.compaction?.maxContextTokens, speculativeEnabled: this.settings.compaction?.speculativeEnabled ?? true, speculativeFraction: this.settings.compaction?.speculativeFraction ?? 0.75, speculativeCooldownMs: this.settings.compaction?.speculativeCooldownMs ?? 30000, diff --git a/packages/coding-agent/test/compaction.test.ts b/packages/coding-agent/test/compaction.test.ts index c1d65c8401..6cd3a1a7b5 100644 --- a/packages/coding-agent/test/compaction.test.ts +++ b/packages/coding-agent/test/compaction.test.ts @@ -203,10 +203,18 @@ type BeforeAgentStartHandler = ( ) => Promise<{ systemPrompt?: string } | undefined> | { systemPrompt?: string } | undefined; type ModelSelectHandler = (event: ModelSelectEvent, ctx: ExtensionContext) => Promise | unknown; type MessageEndHandler = (event: MessageEndEvent, ctx: ExtensionContext) => Promise | unknown; +type ContextHandler = (event: { type: "context"; messages: AgentMessage[] }, ctx: ExtensionContext) => unknown; +type SessionTreeHandler = (event: { + type: "session_tree"; + newLeafId: string | null; + oldLeafId: string | null; +}) => unknown; interface CapturedCompactionHandlers { beforeAgentStart: BeforeAgentStartHandler; + context: ContextHandler; messageEnd: MessageEndHandler; modelSelect: ModelSelectHandler; + sessionTree: SessionTreeHandler; } function captureBeforeAgentStartHandler(options?: { @@ -235,17 +243,31 @@ function captureBeforeAgentStartHandler(options?: { function captureCompactionHandlers(): CapturedCompactionHandlers { let beforeAgentStart: BeforeAgentStartHandler | undefined; + let context: ContextHandler | undefined; let messageEnd: MessageEndHandler | undefined; let modelSelect: ModelSelectHandler | undefined; + let sessionTree: SessionTreeHandler | undefined; const api: ExtensionAPI = Object.assign(Object.create(null), { cwd: "/tmp/senpi-compaction-test", - on: (event: string, currentHandler: BeforeAgentStartHandler | MessageEndHandler | ModelSelectHandler) => { + on: ( + event: string, + currentHandler: + | BeforeAgentStartHandler + | ContextHandler + | MessageEndHandler + | ModelSelectHandler + | SessionTreeHandler, + ) => { if (event === "before_agent_start") { beforeAgentStart = currentHandler as BeforeAgentStartHandler; + } else if (event === "context") { + context = currentHandler as ContextHandler; } else if (event === "message_end") { messageEnd = currentHandler as MessageEndHandler; } else if (event === "model_select") { modelSelect = currentHandler as ModelSelectHandler; + } else if (event === "session_tree") { + sessionTree = currentHandler as SessionTreeHandler; } }, appendEntry: vi.fn(), @@ -255,10 +277,10 @@ function captureCompactionHandlers(): CapturedCompactionHandlers { }); compactionExtension(api); - if (!beforeAgentStart || !messageEnd || !modelSelect) { + if (!beforeAgentStart || !context || !messageEnd || !modelSelect || !sessionTree) { throw new Error("builtin compaction handlers were not registered"); } - return { beforeAgentStart, messageEnd, modelSelect }; + return { beforeAgentStart, context, messageEnd, modelSelect, sessionTree }; } function createExtensionContext(overrides: Partial): ExtensionContext { @@ -271,6 +293,7 @@ function createExtensionContext(overrides: Partial): Extension isProjectTrusted: () => true, sessionManager: Object.assign(Object.create(null), { getEntries: () => [], + getBranch: () => [], }) as ExtensionContext["sessionManager"], modelRegistry: {} as ExtensionContext["modelRegistry"], model: undefined, @@ -590,6 +613,7 @@ describe("shouldCompact", () => { expect(shouldCompact(95000, 100000, settings)).toBe(true); expect(shouldCompact(89000, 100000, settings)).toBe(false); + expect(shouldCompact(45_000, 100_000, { ...settings, maxContextTokens: 40_000 })).toBe(true); }); it("should return false when disabled", () => { @@ -1196,6 +1220,33 @@ describe("builtin compaction extension threshold regressions", () => { expect(order).toEqual(["begin-extension", "auth-start", "apply-called", "hook-returned"]); }); + it("releases the sticky context-reduction latch when the active session branch changes", () => { + const handlers = captureCompactionHandlers(); + let usageTokens = 501_000; + const longAnswer = "historical answer ".repeat(500); + const recentAnswer = "recent protected answer ".repeat(700); + const messages = [ + createUserMessage("branch payload"), + createAssistantMessage(longAnswer), + createUserMessage("recent prompt"), + createAssistantMessage(recentAnswer), + ]; + const ctx = createExtensionContext({ + model: createAnthropicModel("claude-large", 1_000_000), + getContextUsage: () => ({ tokens: usageTokens, contextWindow: 1_000_000, percent: usageTokens / 10_000 }), + }); + + handlers.context({ type: "context", messages }, ctx); + usageTokens = 100_000; + const stillLatched = handlers.context({ type: "context", messages }, ctx) as { messages: AgentMessage[] }; + const latchedText = JSON.stringify(stillLatched.messages); + expect(latchedText).not.toContain(longAnswer); + + handlers.sessionTree({ type: "session_tree", oldLeafId: "old", newLeafId: "new" }); + const afterNavigation = handlers.context({ type: "context", messages }, ctx) as { messages: AgentMessage[] }; + expect(JSON.stringify(afterNavigation.messages)).toContain(longAnswer); + }); + it("drops speculative compaction when a model switch happens before a blocking compaction route", async () => { await expectSpeculativeCompactionInvalidatedBy(async (handlers, ctx, previousModel, nextModel) => { // given diff --git a/packages/coding-agent/test/compaction/adaptive-threshold.test.ts b/packages/coding-agent/test/compaction/adaptive-threshold.test.ts index 9d610750ec..fc223e5caf 100644 --- a/packages/coding-agent/test/compaction/adaptive-threshold.test.ts +++ b/packages/coding-agent/test/compaction/adaptive-threshold.test.ts @@ -5,6 +5,7 @@ import { afterEach, beforeAll, describe, expect, it } from "vitest"; import { DEFAULT_COMPACTION_SETTINGS } from "../../src/core/compaction/index.ts"; import { computeAdaptiveThresholdRatio, + computeEffectiveBlockingThresholdTokens, computeEffectiveKeepRecentTokens, computeEffectiveThreshold, isAtHardLimit, @@ -43,6 +44,32 @@ beforeAll(() => { }); describe("compaction policy: adaptive threshold ratio", () => { + describe("Given the fixture transitions to a 1M-context model", () => { + it("Then the active ceiling is 384k and speculative warmup starts at 288k", () => { + const modelChange = adaptiveFixtureEntries.find( + (entry) => entry.type === "model_change" && entry.modelId === "faux-1m-active-ceiling", + ); + expect(modelChange).toBeDefined(); + + const settings = { ...DEFAULT_COMPACTION_SETTINGS, keepRecentTokensConfigured: false }; + expect(computeEffectiveBlockingThresholdTokens(1_000_000, settings)).toBe(384_000); + expect( + shouldStartSpeculativeCompaction( + { tokens: 287_999, contextWindow: 1_000_000, percent: null }, + 1_000_000, + settings, + ), + ).toBe(false); + expect( + shouldStartSpeculativeCompaction( + { tokens: 288_000, contextWindow: 1_000_000, percent: null }, + 1_000_000, + settings, + ), + ).toBe(true); + }); + }); + describe("Given a faux model with context window 16000", () => { describe("When the adaptive threshold ratio is computed for that window", () => { it("Then the ratio equals 0.45", () => { diff --git a/packages/coding-agent/test/compaction/context-reduction.test.ts b/packages/coding-agent/test/compaction/context-reduction.test.ts index f2ad45b0d1..3bf16a531d 100644 --- a/packages/coding-agent/test/compaction/context-reduction.test.ts +++ b/packages/coding-agent/test/compaction/context-reduction.test.ts @@ -4,6 +4,7 @@ import { describe, expect, it } from "vitest"; import { clearOldToolResults, collapseConsecutiveToolResults, + createContextReductionLatch, microCompactAssistantText, reduceContextMessages, shouldApplyContextReduction, @@ -335,4 +336,82 @@ describe("compaction context reduction behavior", () => { }); }); }); + + describe("Sticky generation latch and prefix hash stability", () => { + it("latches context reduction once engaged and preserves historical prefix shape across threshold oscillations", () => { + const { + createContextReductionLatch, + shouldApplyContextReduction, + } = require("../../src/core/extensions/builtin/compaction/context-reduction.ts"); + const latch = createContextReductionLatch(); + const contextWindow = 1_000_000; + + // Turn 1: 501k (>= 500k gate) -> engages and latches + const engaged1 = shouldApplyContextReduction({ + usageTokens: 501_000, + contextWindow, + latch, + }); + expect(engaged1).toBe(true); + expect(latch.isLatched()).toBe(true); + + // Turn 2: usage dips to 499k (< 500k gate), but latch is ON -> stays engaged + const engaged2 = shouldApplyContextReduction({ + usageTokens: 499_000, + contextWindow, + latch, + }); + expect(engaged2).toBe(true); + expect(latch.isLatched()).toBe(true); + + // Turn 3: usage rises to 505k -> stays engaged + const engaged3 = shouldApplyContextReduction({ + usageTokens: 505_000, + contextWindow, + latch, + }); + expect(engaged3).toBe(true); + expect(latch.isLatched()).toBe(true); + + // Compaction accepted & persisted -> generation bumps and latch resets + latch.bumpGeneration(); + expect(latch.isLatched()).toBe(false); + expect(latch.getGeneration()).toBe(1); + + // After compaction, usage is at 100k -> should NOT engage + const engagedAfter = shouldApplyContextReduction({ + usageTokens: 100_000, + contextWindow, + latch, + }); + expect(engagedAfter).toBe(false); + expect(latch.isLatched()).toBe(false); + }); + + it("resets latch when navigating to another session branch", () => { + const latch = createContextReductionLatch(); + const contextWindow = 1_000_000; + + // Latch engaged on large branch + shouldApplyContextReduction({ + usageTokens: 550_000, + contextWindow, + latch, + }); + expect(latch.isLatched()).toBe(true); + + // User navigates to shorter branch (session_tree event triggers bumpGeneration) + latch.bumpGeneration(); + expect(latch.isLatched()).toBe(false); + + // Shorter branch with 200k usage (< 500k gate) does not run reduction + const engaged = shouldApplyContextReduction({ + usageTokens: 200_000, + contextWindow, + latch, + }); + expect(engaged).toBe(false); + expect(latch.isLatched()).toBe(false); + }); + }); }); diff --git a/packages/coding-agent/test/compaction/policy.test.ts b/packages/coding-agent/test/compaction/policy.test.ts new file mode 100644 index 0000000000..4e1c27dd56 --- /dev/null +++ b/packages/coding-agent/test/compaction/policy.test.ts @@ -0,0 +1,113 @@ +import { describe, expect, it } from "vitest"; +import { + computeEffectiveBlockingThresholdTokens, + computeEffectiveKeepRecentTokens, + DEFAULT_1M_KEEP_RECENT, + resolveContextBudgetPolicy, + shouldStartSpeculativeCompaction, + shouldTriggerCompaction, +} from "../../src/core/extensions/builtin/compaction/policy.ts"; +import type { ContextUsage } from "../../src/core/extensions/types.ts"; + +function usage(tokens: number, contextWindow: number): ContextUsage { + return { + tokens, + contextWindow, + percent: (tokens / contextWindow) * 100, + }; +} + +describe("ContextBudgetPolicy & Compaction Thresholds (Phase 0-3 Matrices)", () => { + const defaultSettings = { + enabled: true, + reserveTokens: 16_384, + keepRecentTokens: 20_000, + keepRecentTokensConfigured: false, + }; + + describe("Case A: 200k model compatibility", () => { + it("does not force 384k ceiling on 200k models", () => { + const policy = resolveContextBudgetPolicy(200_000, defaultSettings); + expect(policy.physicalContextWindow).toBe(200_000); + expect(policy.maxActiveContextTokens).toBe(200_000 - 16_384); + expect(policy.keepRecentTokens).toBe(20_000); + + const blocking = computeEffectiveBlockingThresholdTokens(200_000, defaultSettings); + // 200k * 0.65 = 130k (< 183.6k maxActive) + expect(blocking).toBe(130_000); + + // 120k < 130k -> no trigger + expect(shouldTriggerCompaction(usage(120_000, 200_000), 200_000, defaultSettings)).toBe(false); + // 135k >= 130k -> trigger + expect(shouldTriggerCompaction(usage(135_000, 200_000), 200_000, defaultSettings)).toBe(true); + }); + }); + + describe("Case B & C: 1M model warmup (speculative) threshold around 288k", () => { + it("triggers speculative compaction at 288k (75% of 384k)", () => { + const policy = resolveContextBudgetPolicy(1_000_000, { enabled: true, reserveTokens: 16_384 }); + expect(policy.maxActiveContextTokens).toBe(384_000); + expect(policy.keepRecentTokens).toBe(DEFAULT_1M_KEEP_RECENT); // 35,000 + + const blocking = computeEffectiveBlockingThresholdTokens(1_000_000, defaultSettings); + expect(blocking).toBe(384_000); + + // 287k (< 288k) -> warmup 직전 + expect(shouldStartSpeculativeCompaction(usage(287_000, 1_000_000), 1_000_000, defaultSettings)).toBe(false); + // 289k (>= 288k) -> warmup 시작 + expect(shouldStartSpeculativeCompaction(usage(289_000, 1_000_000), 1_000_000, defaultSettings)).toBe(true); + }); + }); + + describe("Case D & E: 1M model blocking compaction threshold at 384k", () => { + it("caps blocking threshold at 384k despite 65% ratio being 650k", () => { + const blocking = computeEffectiveBlockingThresholdTokens(1_000_000, defaultSettings); + expect(blocking).toBe(384_000); + + // 383k -> blocking 직전 + expect(shouldTriggerCompaction(usage(383_000, 1_000_000), 1_000_000, defaultSettings)).toBe(false); + // 385k -> blocking compaction 요구 + expect(shouldTriggerCompaction(usage(385_000, 1_000_000), 1_000_000, defaultSettings)).toBe(true); + }); + }); + + describe("Case F: Base footprint 155k + recent 35k post-compaction headroom", () => { + it("does not immediately re-trigger compaction after compacting to ~190k", () => { + const postCompactTokens = 155_000 + 35_000; // 190,000 + expect(shouldTriggerCompaction(usage(postCompactTokens, 1_000_000), 1_000_000, defaultSettings)).toBe(false); + expect(shouldStartSpeculativeCompaction(usage(postCompactTokens, 1_000_000), 1_000_000, defaultSettings)).toBe( + false, + ); + }); + }); + + describe("User overrides prioritization", () => { + it("preserves explicit zero keepRecentTokens during preparation", () => { + const thresholdRatio = 0.65; + expect(computeEffectiveKeepRecentTokens(0, 1_000_000, thresholdRatio, 0.05, true)).toBe(0); + }); + + it("respects explicit maxContextTokens and keepRecentTokens over defaults", () => { + const customSettings = { + enabled: true, + reserveTokens: 20_000, + keepRecentTokens: 40_000, + keepRecentTokensConfigured: true, + maxContextTokens: 450_000, + speculativeFraction: 0.8, + }; + + const policy = resolveContextBudgetPolicy(1_000_000, customSettings); + expect(policy.maxActiveContextTokens).toBe(450_000); + expect(policy.keepRecentTokens).toBe(40_000); + expect(policy.warmupFraction).toBe(0.8); + + const blocking = computeEffectiveBlockingThresholdTokens(1_000_000, customSettings); + expect(blocking).toBe(450_000); + + // 360k = 450k * 0.80 + expect(shouldStartSpeculativeCompaction(usage(359_000, 1_000_000), 1_000_000, customSettings)).toBe(false); + expect(shouldStartSpeculativeCompaction(usage(361_000, 1_000_000), 1_000_000, customSettings)).toBe(true); + }); + }); +}); diff --git a/packages/coding-agent/test/fixtures/compaction/README.md b/packages/coding-agent/test/fixtures/compaction/README.md index b01552fcfa..dde0f669a6 100644 --- a/packages/coding-agent/test/fixtures/compaction/README.md +++ b/packages/coding-agent/test/fixtures/compaction/README.md @@ -12,7 +12,7 @@ Per-feature fixtures establish a **behavioral contract** between each subsystem | # | Directory | File | Purpose | Entries | |---|-----------|------|---------|---------| -| 1 | `adaptive-threshold/` | `16k-near-threshold.jsonl` | Context near 16k limit, triggers proactive compaction | 7 | +| 1 | `adaptive-threshold/` | `16k-near-threshold.jsonl` | Context near 16k limit plus a 1M model transition that exercises the 384k active ceiling and 288k warmup | 8 | | 2 | `per-turn-cap/` | `four-back-to-back-compactions.jsonl` | Four compactions in one turn, tests absolute-cap admission | 11 | | 3 | `circuit-breaker/` | `three-failures-then-success.jsonl` | Three failed compactions then recovery | 11 | | 4 | `pre-prune/` | `oversized-with-pairs.jsonl` | Interleaved tool_call/tool_result with large content | 20 | diff --git a/packages/coding-agent/test/fixtures/compaction/adaptive-threshold/16k-near-threshold.jsonl b/packages/coding-agent/test/fixtures/compaction/adaptive-threshold/16k-near-threshold.jsonl index 7e78cc7eae..3b38c8663a 100644 --- a/packages/coding-agent/test/fixtures/compaction/adaptive-threshold/16k-near-threshold.jsonl +++ b/packages/coding-agent/test/fixtures/compaction/adaptive-threshold/16k-near-threshold.jsonl @@ -4,4 +4,5 @@ {"type":"message","timestamp":"2025-01-15T20:00:03.000Z","message":{"role":"toolResult","toolCallId":"toolu_080","toolName":"read","content":[{"type":"text","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in rep"}],"timestamp":1705348803000}} {"type":"message","timestamp":"2025-01-15T20:00:04.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Now let me read the main configuration file."}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{"input":200,"output":12,"cacheRead":0,"cacheWrite":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"toolUse","timestamp":1705348804000}} {"type":"message","timestamp":"2025-01-15T20:00:05.000Z","message":{"role":"toolResult","toolCallId":"toolu_081","toolName":"read","content":[{"type":"text","text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in rep"}],"timestamp":1705348805000}} -{"type":"message","timestamp":"2025-01-15T20:00:06.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Context is approaching the 16k limit. I should summarize what we have found so far."}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{"input":400,"output":20,"cacheRead":0,"cacheWrite":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"endTurn","timestamp":1705348806000}} \ No newline at end of file +{"type":"message","timestamp":"2025-01-15T20:00:06.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Context is approaching the 16k limit. I should summarize what we have found so far."}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{"input":400,"output":20,"cacheRead":0,"cacheWrite":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"endTurn","timestamp":1705348806000}} +{"type":"model_change","timestamp":"2025-01-15T20:00:06.000Z","provider":"faux","modelId":"faux-1m-active-ceiling"} diff --git a/packages/coding-agent/test/settings-manager.test.ts b/packages/coding-agent/test/settings-manager.test.ts index 7c155eeaf6..6c192d327c 100644 --- a/packages/coding-agent/test/settings-manager.test.ts +++ b/packages/coding-agent/test/settings-manager.test.ts @@ -119,6 +119,26 @@ describe("SettingsManager", () => { }); }); + describe("compaction settings", () => { + it("preserves explicit context-budget overrides and marks normalized retention defaults", () => { + writeFileSync( + join(agentDir, "settings.json"), + JSON.stringify({ compaction: { maxContextTokens: 450_000, keepRecentTokens: 40_000 } }), + ); + + const configured = SettingsManager.create(projectDir, agentDir).getCompactionSettings(); + expect(configured.maxContextTokens).toBe(450_000); + expect(configured.keepRecentTokens).toBe(40_000); + expect(configured.keepRecentTokensConfigured).toBe(true); + + rmSync(join(agentDir, "settings.json")); + const normalized = SettingsManager.create(projectDir, agentDir).getCompactionSettings(); + expect(normalized.keepRecentTokens).toBe(20_000); + expect(normalized.keepRecentTokensConfigured).toBe(false); + expect(normalized.maxContextTokens).toBeUndefined(); + }); + }); + describe("preserves externally added settings", () => { it("should preserve enabledModels when changing thinking level", async () => { // Create initial settings file