Skip to content

Commit 792912a

Browse files
brandonleungclaude
andauthored
chore(ci): remove the unreachable --ci legacy gateway fallback (#1247)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 662f54d commit 792912a

15 files changed

Lines changed: 31 additions & 257 deletions

scripts/smoke-test-ci.sh

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
#
66
# Prerequisites:
77
# - POSTHOG_PERSONAL_API_KEY env var (or in .env): a personal API key (phx_)
8-
# or a wizard-app OAuth access token (pha_), which is what the CI bot uses.
9-
# The env name stays the same for either so the secret rotates in place.
8+
# - WIZARD_CI_GATEWAY_TOKEN_FILE: path to a file holding the AI gateway key
109
# - A wizard-workbench repo checked out (for the test app), pointed to by:
1110
# - WIZARD_WORKBENCH_ROOT=/path/to/wizard-workbench
1211
# or
@@ -17,9 +16,8 @@
1716
# ./scripts/smoke-test-ci.sh basic-integration/next-js/15-pages-router-saas
1817
#
1918
# Examples:
20-
# # With the key inline (a phx_ personal key or a pha_ wizard-app token):
19+
# # With API key inline:
2120
# POSTHOG_PERSONAL_API_KEY=phx_your_key_here ./scripts/smoke-test-ci.sh
22-
# POSTHOG_PERSONAL_API_KEY=pha_wizard_app_token ./scripts/smoke-test-ci.sh
2321
#
2422
# # With project ID override:
2523
# POSTHOG_PERSONAL_API_KEY=phx_your_key_here POSTHOG_PROJECT_ID=12345 ./scripts/smoke-test-ci.sh

src/lib/__tests__/agent-interface.test.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ describe('buildAgentEnv header shape', () => {
607607
const flags = { 'wizard-orchestrator': 'test' };
608608

609609
it('sends one properties blob and no per-key or bedrock headers', () => {
610-
const encoded = buildAgentEnv(metadata, flags, { teamId: 42 });
610+
const encoded = buildAgentEnv(metadata, flags, 42);
611611
const [name, json] = encoded.split(': ', 2);
612612
expect(name).toBe('X-PostHog-Properties');
613613
// Fallback is native in the gateway's routing chain, and the run tags ride
@@ -622,14 +622,6 @@ describe('buildAgentEnv header shape', () => {
622622
expect(encoded).not.toContain('x-posthog-use-bedrock-fallback');
623623
expect(encoded).not.toContain('X-POSTHOG-PROPERTY-');
624624
});
625-
626-
it('sends per-key headers and the bedrock opt-in on the legacy gateway', () => {
627-
const encoded = buildAgentEnv(metadata, flags, { legacy: true });
628-
expect(encoded).toContain('x-posthog-use-bedrock-fallback: true');
629-
expect(encoded).toContain('X-POSTHOG-PROPERTY-run_id: r1');
630-
expect(encoded).toContain('X-POSTHOG-FLAG-WIZARD-ORCHESTRATOR: test');
631-
expect(encoded).not.toContain('X-PostHog-Properties');
632-
});
633625
});
634626

635627
describe('subprocess gateway credentials', () => {

src/lib/__tests__/gateway-session.test.ts

Lines changed: 1 addition & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from '@lib/gateway-session';
1313
import type { HostResolution } from '@lib/host-resolution';
1414
import { ErrorCodes } from '@lib/errors';
15-
import { setLegacyGatewayFallback } from '@lib/legacy-gateway';
1615
import { WizardError } from '@utils/wizard-abort';
1716
import { analytics } from '@utils/analytics';
1817
import { logToFile } from '@utils/debug';
@@ -46,10 +45,7 @@ const renderArg = (a: unknown): string => {
4645
const loggedLines = () =>
4746
vi.mocked(logToFile).mock.calls.map((call) => call.map(renderArg).join(' '));
4847

49-
const host = {
50-
region: 'us',
51-
apiHost: 'https://us.posthog.com',
52-
} as unknown as HostResolution;
48+
const host = { apiHost: 'https://us.posthog.com' } as unknown as HostResolution;
5349

5450
describe('gatewayAuth', () => {
5551
const fetchMock = vi.fn();
@@ -574,91 +570,6 @@ describe('gatewayAuth', () => {
574570
).rejects.toBeInstanceOf(GatewayMintRefused);
575571
});
576572

577-
describe('CI legacy fallback', () => {
578-
const refused = (status: number) => ({
579-
ok: false,
580-
status,
581-
json: () => Promise.resolve({}),
582-
});
583-
584-
beforeEach(() => setLegacyGatewayFallback(true));
585-
afterEach(() => setLegacyGatewayFallback(false));
586-
587-
it('stays on the legacy gateway when the mint does not take the credential', async () => {
588-
// A personal API key 401s at the mint; the legacy gateway authenticates it itself.
589-
fetchMock.mockResolvedValue(refused(401));
590-
const auth = await gatewayAuth(host, 'phx_personal', 'integration');
591-
expect(auth).toMatchObject({
592-
gatewayUrl: 'https://gateway.us.posthog.com/wizard',
593-
token: 'phx_personal',
594-
legacy: true,
595-
});
596-
expect(isPastRefresh(auth)).toBe(false);
597-
});
598-
599-
it('picks the legacy gateway for the region, or the local one for a dev host', async () => {
600-
fetchMock.mockResolvedValue(refused(401));
601-
const urlFor = async (region: string, apiHost: string) => {
602-
resetGatewaySession();
603-
const h = { region, apiHost } as unknown as HostResolution;
604-
return (await gatewayAuth(h, 'phx_personal', 'integration')).gatewayUrl;
605-
};
606-
expect(await urlFor('eu', 'https://eu.i.posthog.com')).toBe(
607-
'https://gateway.eu.posthog.com/wizard',
608-
);
609-
expect(await urlFor('us', 'http://localhost:8010')).toBe(
610-
'http://localhost:3308/wizard',
611-
);
612-
expect(await urlFor('us', 'http://host.docker.internal:8010')).toBe(
613-
'http://host.docker.internal:3308/wizard',
614-
);
615-
});
616-
617-
it('stays on the legacy gateway when the instance has no mint', async () => {
618-
fetchMock.mockResolvedValue(refused(404));
619-
const auth = await gatewayAuth(host, 'phx_personal', 'integration');
620-
expect(auth.legacy).toBe(true);
621-
});
622-
623-
it('caches the fallback instead of re-asking the mint per caller', async () => {
624-
fetchMock.mockResolvedValue(refused(401));
625-
await gatewayAuth(host, 'phx_personal', 'integration');
626-
await gatewayAuth(host, 'phx_personal', 'integration');
627-
expect(fetchMock).toHaveBeenCalledTimes(1);
628-
});
629-
630-
it('still fails a policy refusal', async () => {
631-
// 403/429/400 are decisions about the run, which the legacy gateway would not enforce.
632-
fetchMock.mockResolvedValue(refused(403));
633-
await expect(
634-
gatewayAuth(host, 'phx_personal', 'integration'),
635-
).rejects.toBeInstanceOf(GatewayMintRefused);
636-
});
637-
638-
it('still mints when the mint accepts the credential', async () => {
639-
fetchMock.mockResolvedValue({
640-
ok: true,
641-
json: () =>
642-
Promise.resolve({
643-
token: 'phe_minted',
644-
expires_at: new Date(Date.now() + 3600_000).toISOString(),
645-
gateway_url: 'https://gateway.us.posthog.com',
646-
}),
647-
});
648-
const auth = await gatewayAuth(host, 'pha_app', 'integration');
649-
expect(auth.token).toBe('phe_minted');
650-
expect(auth.legacy).toBeUndefined();
651-
});
652-
653-
it('does not fall back outside CI', async () => {
654-
setLegacyGatewayFallback(false);
655-
fetchMock.mockResolvedValue(refused(401));
656-
await expect(
657-
gatewayAuth(host, 'phx_personal', 'integration'),
658-
).rejects.toBeInstanceOf(GatewayMintRefused);
659-
});
660-
});
661-
662573
it("names the run's program in the mint request", async () => {
663574
fetchMock.mockResolvedValue({
664575
ok: true,

src/lib/agent/__tests__/tutorial-run-tags.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,14 @@ describe('buildTutorialRunTags', () => {
4848
const encoded = buildAgentEnv(
4949
buildTutorialRunTags({ programId: 'mcp-tutorial' }),
5050
{},
51-
{},
5251
);
5352

5453
expect(encoded).toContain('X-PostHog-Properties: ');
5554
expect(encoded).toContain('"program_id":"mcp-tutorial"');
5655
});
5756

5857
it('sends only product attribution when there is no program', () => {
59-
const encoded = buildAgentEnv(buildTutorialRunTags({}), {}, {});
58+
const encoded = buildAgentEnv(buildTutorialRunTags({}), {});
6059

6160
expect(encoded).toBe('X-PostHog-Properties: {"ai_product":"wizard"}');
6261
});

src/lib/agent/agent-interface.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import {
3030
import { wizardAbort, WizardError } from '@utils/wizard-abort';
3131
import { createCustomHeaders } from '@utils/custom-headers';
3232
import type { HostResolution } from '@lib/host-resolution';
33-
import { legacyGatewayHeaders } from '@lib/legacy-gateway';
3433
import {
3534
buildWizardPropertiesBlob,
3635
gatewayAuth,
@@ -397,25 +396,18 @@ export function isWarlockDisabled(): boolean {
397396
/**
398397
* Build ANTHROPIC_CUSTOM_HEADERS for the SDK subprocess: the run's metadata and
399398
* flags as one `X-PostHog-Properties` JSON blob. Bedrock fallback is native to
400-
* the gateway, so there is no opt-in header. The CI fallback sends the legacy
401-
* gateway's shape instead.
399+
* the gateway, so there is no opt-in header.
402400
*/
403401
export function buildAgentEnv(
404402
wizardMetadata: Record<string, string>,
405403
wizardFlags: Record<string, string>,
406-
auth: Pick<GatewayAuth, 'teamId' | 'legacy'>,
404+
teamId?: number,
407405
): string {
408406
const headers = createCustomHeaders();
409-
const shaped = auth.legacy
410-
? legacyGatewayHeaders(wizardMetadata, wizardFlags)
411-
: {
412-
'X-PostHog-Properties': buildWizardPropertiesBlob(
413-
wizardMetadata,
414-
wizardFlags,
415-
auth.teamId,
416-
),
417-
};
418-
for (const [key, value] of Object.entries(shaped)) headers.add(key, value);
407+
headers.add(
408+
'X-PostHog-Properties',
409+
buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId),
410+
);
419411
const encoded = headers.encode();
420412
logToFile('ANTHROPIC_CUSTOM_HEADERS', encoded);
421413
return encoded;
@@ -570,7 +562,6 @@ export async function initializeAgent(
570562
baseURL: current.gatewayUrl,
571563
authToken: current.token,
572564
teamId: current.teamId,
573-
legacy: current.legacy,
574565
wizardMetadata: triageMetadata,
575566
wizardFlags: config.wizardFlags ?? {},
576567
};
@@ -1064,7 +1055,7 @@ export async function runAgent(
10641055
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(
10651056
agentConfig.wizardMetadata ?? {},
10661057
agentConfig.wizardFlags ?? {},
1067-
agentConfig.gatewayAuth,
1058+
agentConfig.gatewayAuth.teamId,
10681059
),
10691060
},
10701061
canUseTool: (toolName: string, input: unknown) => {

src/lib/agent/mcp-prompt-streaming.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ export async function* runMcpPromptViaSdk(args: {
385385
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(
386386
wizardMetadata ?? {},
387387
{},
388-
auth,
388+
auth.teamId,
389389
),
390390
},
391391
},

src/lib/agent/runner/harness/pi/__tests__/gateway.test.ts

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,6 @@ describe('buildGatewayProvider transport', () => {
5858
expect(baseUrl).toBe('https://ai-gateway.us.posthog.com/v1');
5959
});
6060

61-
it('routes openai models over chat completions on the legacy gateway', () => {
62-
const { api, baseUrl } = buildGatewayProvider({
63-
...base,
64-
gatewayUrl: 'https://gateway.us.posthog.com/wizard',
65-
legacy: true,
66-
modelId: 'openai/gpt-5.6-terra',
67-
});
68-
expect(api).toBe('openai-completions');
69-
expect(baseUrl).toBe('https://gateway.us.posthog.com/wizard/v1');
70-
});
71-
7261
it('routes anthropic models over anthropic-messages without /v1', () => {
7362
const { api, baseUrl } = buildGatewayProvider({
7463
...base,
@@ -95,20 +84,6 @@ describe('buildGatewayHeaders', () => {
9584
expect(headers['x-posthog-use-bedrock-fallback']).toBeUndefined();
9685
expect(headers['X-POSTHOG-PROPERTY-run_id']).toBeUndefined();
9786
});
98-
99-
it('carries per-key headers and the bedrock opt-in on the legacy gateway', () => {
100-
const headers = buildGatewayHeaders(
101-
{ run_id: 'r1' },
102-
{ 'wizard-orchestrator': 'test', unrelated: 'x' },
103-
42,
104-
true,
105-
);
106-
expect(headers['X-POSTHOG-PROPERTY-run_id']).toBe('r1');
107-
expect(headers['X-POSTHOG-FLAG-WIZARD-ORCHESTRATOR']).toBe('test');
108-
expect(headers['X-POSTHOG-FLAG-UNRELATED']).toBeUndefined();
109-
expect(headers['x-posthog-use-bedrock-fallback']).toBe('true');
110-
expect(headers['X-PostHog-Properties']).toBeUndefined();
111-
});
11287
});
11388

11489
describe('isGatewayAuthRejection', () => {

src/lib/agent/runner/harness/pi/gateway.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
isPastRefresh,
1212
type GatewayAuth,
1313
} from '@lib/gateway-session';
14-
import { legacyGatewayHeaders } from '@lib/legacy-gateway';
1514
import {
1615
modelCapabilities,
1716
type ThinkingLevel,
@@ -36,10 +35,10 @@ export type GatewayApi =
3635
* OpenAI models take the Responses API because OpenAI rejects function tools
3736
* combined with `reasoning_effort` on chat completions and every task sends both.
3837
*/
39-
export function gatewayApiFor(modelId: string, legacy?: boolean): GatewayApi {
40-
if (!modelId.startsWith('openai/')) return 'anthropic-messages';
41-
// The legacy gateway routes openai models through chat completions itself.
42-
return legacy ? 'openai-completions' : 'openai-responses';
38+
export function gatewayApiFor(modelId: string): GatewayApi {
39+
return modelId.startsWith('openai/')
40+
? 'openai-responses'
41+
: 'anthropic-messages';
4342
}
4443

4544
/**
@@ -52,19 +51,14 @@ export function buildGatewayHeaders(
5251
wizardMetadata: Record<string, string>,
5352
wizardFlags: Record<string, string>,
5453
teamId?: number,
55-
legacy?: boolean,
5654
): Record<string, string> {
5755
return {
5856
'anthropic-beta': 'context-1m-2025-08-07',
59-
...(legacy
60-
? legacyGatewayHeaders(wizardMetadata, wizardFlags)
61-
: {
62-
'X-PostHog-Properties': buildWizardPropertiesBlob(
63-
wizardMetadata,
64-
wizardFlags,
65-
teamId,
66-
),
67-
}),
57+
'X-PostHog-Properties': buildWizardPropertiesBlob(
58+
wizardMetadata,
59+
wizardFlags,
60+
teamId,
61+
),
6862
};
6963
}
7064

@@ -73,8 +67,6 @@ export interface GatewayProviderInputs {
7367
accessToken: string;
7468
/** Customer team for the properties blob (from the mint response). */
7569
teamId?: number;
76-
/** Set only by the CI fallback in legacy-gateway.ts. */
77-
legacy?: boolean;
7870
wizardMetadata: Record<string, string>;
7971
wizardFlags: Record<string, string>;
8072
modelId: string;
@@ -90,9 +82,8 @@ export interface GatewayProviderInputs {
9082
* callers (scan triage) hand it straight to `completeSimple`.
9183
*/
9284
export function buildGatewayModel(inputs: GatewayProviderInputs) {
93-
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId, legacy } =
94-
inputs;
95-
const api = gatewayApiFor(modelId, legacy);
85+
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;
86+
const api = gatewayApiFor(modelId);
9687
return {
9788
id: modelId,
9889
name: `${modelId} (PostHog Gateway)`,
@@ -108,7 +99,7 @@ export function buildGatewayModel(inputs: GatewayProviderInputs) {
10899
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
109100
contextWindow: 1_000_000,
110101
maxTokens: 64_000,
111-
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId, legacy),
102+
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId),
112103
};
113104
}
114105

@@ -123,8 +114,8 @@ export function buildGatewayProvider(inputs: GatewayProviderInputs): {
123114
gatewayUrl: string;
124115
baseUrl: string;
125116
} {
126-
const { gatewayUrl, accessToken, modelId, effort, legacy } = inputs;
127-
const api = gatewayApiFor(modelId, legacy);
117+
const { gatewayUrl, accessToken, modelId, effort } = inputs;
118+
const api = gatewayApiFor(modelId);
128119
// One resolution point for the model's traits and the run's effort override.
129120
// pi clamps whatever comes out of here against the levels this spec declares,
130121
// so a level the spec doesn't carry is silently reduced by the session.

src/lib/agent/runner/harness/pi/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,6 @@ export const piBackend: AgentHarness = {
263263
gatewayUrl: current.gatewayUrl,
264264
accessToken: current.token,
265265
teamId: current.teamId,
266-
legacy: current.legacy,
267266
wizardMetadata: boot.wizardMetadata,
268267
wizardFlags: boot.wizardFlags,
269268
modelId,

src/lib/agent/runner/harness/pi/task.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@ export async function runPiTask(inputs: TaskRunInputs): Promise<AgentResult> {
230230
gatewayUrl: current.gatewayUrl,
231231
accessToken: current.token,
232232
teamId: current.teamId,
233-
legacy: current.legacy,
234233
wizardMetadata: boot.wizardMetadata,
235234
wizardFlags: boot.wizardFlags,
236235
modelId,

0 commit comments

Comments
 (0)