Skip to content
Draft
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
28 changes: 28 additions & 0 deletions src/lib/agent/__tests__/auto-compact-window.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, it, expect } from 'vitest';
import { AGENT_AUTO_COMPACT_WINDOW } from '@lib/constants';

/**
* Guards the fix for the 2026-07-09 cost regression: the agent enables the
* 1M-context beta, so auto-compaction only bounds per-generation input cost
* when `settings.autoCompactWindow` pins a smaller working window.
*
* The SDK validates this setting as an int in [100_000, 1_000_000] and
* *silently drops* out-of-range values (`.catch(void 0)`), which would revert
* to deferring compaction to the 1M ceiling — reintroducing the regression
* with no error. Keep the constant inside the accepted band, and well under
* the 1M physical window so compaction has room to run.
*/
describe('AGENT_AUTO_COMPACT_WINDOW', () => {
const SDK_MIN = 100_000;
const SDK_MAX = 1_000_000;

it('is an integer the SDK will accept (not silently dropped)', () => {
expect(Number.isInteger(AGENT_AUTO_COMPACT_WINDOW)).toBe(true);
expect(AGENT_AUTO_COMPACT_WINDOW).toBeGreaterThanOrEqual(SDK_MIN);
expect(AGENT_AUTO_COMPACT_WINDOW).toBeLessThanOrEqual(SDK_MAX);
});

it('stays well below the 1M physical window so compaction has headroom', () => {
expect(AGENT_AUTO_COMPACT_WINDOW).toBeLessThan(SDK_MAX);
});
});
10 changes: 9 additions & 1 deletion src/lib/agent/agent-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
WIZARD_ORCHESTRATOR_FLAG_KEY,
WIZARD_USER_AGENT,
DEFAULT_AGENT_MODEL,
CONTEXT_1M_BETA,
AGENT_AUTO_COMPACT_WINDOW,
} from '@lib/constants';
import {
type AdditionalFeature,
Expand Down Expand Up @@ -964,7 +966,13 @@ export async function runAgent(
model: agentConfig.model,
cwd: agentConfig.workingDirectory,
permissionMode: 'acceptEdits',
betas: ['context-1m-2025-08-07'],
betas: [CONTEXT_1M_BETA],
// The 1M beta gives compaction room to run without overflowing on
// large projects, but on its own it lets the working context (and the
// per-turn input we're billed for) grow toward 1M once the gateway
// honors the beta. Pin the auto-compact window so compaction fires at a
// bounded size, keeping per-generation input near the pre-1M band.
settings: { autoCompactWindow: AGENT_AUTO_COMPACT_WINDOW },
mcpServers: agentConfig.mcpServers,
agents: {
'general-purpose': {
Expand Down
11 changes: 8 additions & 3 deletions src/lib/agent/mcp-prompt-streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

import type { AgentChunk } from '@ui/tui/services/mcp-suggested-prompts-services';
import type { Credentials } from '@lib/wizard-session';
import { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@lib/constants';
import {
DEFAULT_AGENT_MODEL,
WIZARD_USER_AGENT,
CONTEXT_1M_BETA,
} from '@lib/constants';
import { HostResolution, mcpUrlFor } from '@lib/host-resolution';
import { logToFile } from '@utils/debug';
import { buildAgentEnv } from '@lib/agent/agent-interface';
Expand Down Expand Up @@ -265,8 +269,9 @@ export async function* runMcpPromptViaSdk(args: {
permissionMode: 'acceptEdits',
maxTurns: MAX_TURNS,
// Match agent-interface.ts — the 1M context beta is what keeps
// resumed follow-up sessions from truncating after a few turns.
betas: ['context-1m-2025-08-07'],
// resumed follow-up sessions from truncating after a few turns. This
// flow is bounded by maxTurns above, so it needs no autoCompactWindow.
betas: [CONTEXT_1M_BETA],
// Only load project-level skills/settings. Without this the SDK
// defaults to ['user', 'project'] and a user's
// `~/.claude/settings.json` (apiKeyHelper / env block) can
Expand Down
5 changes: 4 additions & 1 deletion src/lib/agent/runner/harness/anthropic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ Both entry points are implemented:
user's OAuth token (`CLAUDE_CODE_OAUTH_TOKEN` + `ANTHROPIC_BASE_URL`).
Bedrock fallback via `x-posthog-use-bedrock-fallback: true`.
- **Context window:** 1M-context beta (`context-1m-2025-08-07`) so large
projects don't overflow during compaction.
projects don't overflow during compaction. The billed working context is
bounded separately by `settings.autoCompactWindow` (`AGENT_AUTO_COMPACT_WINDOW`,
200K) — auto-compaction fires at that size rather than deferring to the 1M
ceiling, keeping per-generation input cost near the pre-1M band.
- **Custom headers:** wizard flags (`X-POSTHOG-FLAG-*`) and metadata
(`X-POSTHOG-PROPERTY-*`) piggyback on every gateway request for tracing.
- **Model routing:** `AgentConfig.modelOverride` accepts any gateway model id
Expand Down
5 changes: 4 additions & 1 deletion src/lib/agent/runner/harness/pi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
POSTHOG_PROPERTY_HEADER_PREFIX,
WIZARD_REMARK_EVENT_NAME,
WIZARD_USER_AGENT,
CONTEXT_1M_BETA,
} from '@lib/constants';
import { analytics } from '@utils/analytics';
import { AgentErrorType } from '@lib/agent/agent-interface';
Expand Down Expand Up @@ -153,7 +154,9 @@ function buildGatewayHeaders(
'x-posthog-use-bedrock-fallback': 'true',
// 1M context window, same as the anthropic edition — pi otherwise runs at
// 200k and overflows on larger projects (the post-run compaction failures).
'anthropic-beta': 'context-1m-2025-08-07',
// Note: pi drives its own compaction (pi-coding-agent), so the anthropic
// edition's `autoCompactWindow` cost guard does not apply here.
'anthropic-beta': CONTEXT_1M_BETA,
};
for (const [key, value] of Object.entries(wizardMetadata)) {
const name = key.startsWith(POSTHOG_PROPERTY_HEADER_PREFIX)
Expand Down
21 changes: 21 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ export const GPT5_4_MODEL = 'openai/gpt-5.4';
*/
export const GPT5_MINI_MODEL = 'openai/gpt-5-mini';

/**
* Anthropic 1M-context beta. Enabled on the agent so a run has physical
* headroom for compaction to succeed on large projects — but it does NOT set
* the working-context size the model actually pays for on every turn; that is
* `AGENT_AUTO_COMPACT_WINDOW` below.
*/
export const CONTEXT_1M_BETA = 'context-1m-2025-08-07';

/**
* Working-context ceiling (tokens) at which the SDK auto-compacts, passed via
* `Options.settings.autoCompactWindow`. Decoupled from the physical window: the
* 1M beta ({@link CONTEXT_1M_BETA}) gives compaction room to run, while this
* keeps the per-turn input the run is billed for near the ~110-200K band.
*
* Without it, once the gateway honors the 1M beta the SDK defers compaction to
* ~1M, so a long linear run's context climbs past 600K and per-generation cost
* balloons (the 2026-07-09 spend regression). Must stay within the SDK's
* accepted range (100K-1M).
*/
export const AGENT_AUTO_COMPACT_WINDOW = 200_000;

// ── Agent runner routing axes ────────────────────────────────────────

/**
Expand Down
Loading