Files
oh-my-pi/packages/coding-agent/test/tools/browser-stealth-targets.test.ts
T
can1357 d4317d3d20 feat(ai): consolidated OpenAI-family streaming and add OpenRouter API support
This change introduces a new `openrouter` API type and extensively refactors OpenAI-family streaming providers, centralizing shared logic and improving robustness.

Key changes include:
- **Unified OpenAI-family Logic:** Consolidated core utilities, compat resolution, request shaping, and stream processing into `openai-shared.ts`, reducing duplication across `openai-completions`, `openai-responses`, and `openai-codex-responses`.
- **OpenRouter API Type:** Introduced a dedicated `openrouter` API type with dual-surface compatibility, allowing it to dispatch requests as either OpenAI Chat Completions or Responses.
- **Enhanced Provider Integration:**
    - Improved Perplexity search to leverage shared OpenAI streaming transports, including API-key fallback to OpenRouter and support for Perplexity's Responses API.
    - Integrated xAI-specific logic directly into the shared `stream.ts` dispatch, removing the dedicated `xai-responses` provider.
    - Refined credential parsing for Google Gemini CLI and handling of Azure deployment names.
- **Robustness & Consistency:** Improved error handling for Codex, standardized output token parameter resolution, and ensured consistent application of reasoning suppression across all Chat Completions dialects.
- **New Documentation:** Added `provider-endpoint-constraints.md` to detail endpoint-specific behaviors and quirks for various providers.
- **Telemetry & Debugging:** Extended telemetry propagation to advisor calls and overflow compaction tasks. Improved debugging for Codex WebSocket failures and stream error messages.
- **Tooling & Security:** Updated browser stealth scripts to prevent detection and added a new `ts-no-inline-cast-access` TTSR rule.
2026-06-17 21:36:48 +02:00

229 lines
6.1 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import {
buildStealthInjectionScriptForTest,
configureUserAgentTargetsForTest,
targetSupportsUserAgentOverrideForTest,
} from "@oh-my-pi/pi-coding-agent/tools/browser/launch";
import type { Browser, CDPSession, Target } from "puppeteer-core";
type SentCommand = {
method: string;
params?: Record<string, unknown>;
};
class FakeSession {
readonly commands: SentCommand[] = [];
detached = false;
readonly #delayMs: number;
constructor(delayMs = 0) {
this.#delayMs = delayMs;
}
async send(method: string, params?: Record<string, unknown>): Promise<unknown> {
this.commands.push({ method, params });
if (this.#delayMs > 0) await Bun.sleep(this.#delayMs);
return {};
}
async detach(): Promise<void> {
this.detached = true;
}
on(): void {}
connection(): { session: () => null } {
return { session: () => null };
}
}
class FakeTarget {
readonly session: FakeSession;
createCalls = 0;
readonly #type: string;
constructor(type: string, delayMs = 0) {
this.#type = type;
this.session = new FakeSession(delayMs);
}
type(): string {
return this.#type;
}
async createCDPSession(): Promise<CDPSession> {
this.createCalls++;
return this.session as unknown as CDPSession;
}
}
class FakeBrowser {
readonly browserTarget = new FakeTarget("browser");
readonly #targets: FakeTarget[];
constructor(targets: FakeTarget[]) {
this.#targets = targets;
}
target(): Target {
return this.browserTarget as unknown as Target;
}
targets(): Target[] {
return this.#targets as unknown as Target[];
}
}
const override = {
userAgent: "Mozilla/5.0 Chrome/142.0.0.0 Safari/537.36",
acceptLanguage: "en-US,en",
platform: "Win32",
userAgentMetadata: {
brands: [{ brand: "Chromium", version: "142" }],
fullVersion: "142.0.0.0",
platform: "Windows",
platformVersion: "10.0.0",
architecture: "x86",
model: "",
mobile: false,
},
};
describe("browser stealth bootstrap", () => {
it("uses documentElement as the iframe container when document.head is unavailable", () => {
type NativeWindow = Pick<
typeof globalThis,
| "Function"
| "Object"
| "setTimeout"
| "Math"
| "Event"
| "Promise"
| "Blob"
| "Proxy"
| "Intl"
| "Date"
| "Reflect"
>;
type FakeContainer = {
appendChild(node: FakeIframe): void;
removeChild(node: FakeIframe): void;
};
type FakeIframe = {
contentWindow: NativeWindow;
parentNode: FakeContainer | null;
style: { display?: string };
};
const appended: FakeIframe[] = [];
const removed: FakeIframe[] = [];
const documentElement: FakeContainer = {
appendChild(node) {
appended.push(node);
node.parentNode = documentElement;
},
removeChild(node) {
removed.push(node);
node.parentNode = null;
},
};
const nativeWindow: NativeWindow = {
Function,
Object,
setTimeout,
Math,
Event,
Promise,
Blob,
Proxy,
Intl,
Date,
Reflect,
};
const iframe: FakeIframe = { contentWindow: nativeWindow, parentNode: null, style: {} };
const createdTags: string[] = [];
const document = {
head: null,
documentElement,
createElement(tagName: string) {
createdTags.push(tagName);
return iframe;
},
};
const run = new Function("document", buildStealthInjectionScriptForTest([]));
run(document);
expect(createdTags).toEqual(["iframe"]);
expect(iframe.style.display).toBe("none");
expect(appended).toEqual([iframe]);
expect(removed).toEqual([iframe]);
expect(iframe.parentNode).toBeNull();
});
it("caches Reflect methods before any stealth scripts run", () => {
const script = buildStealthInjectionScriptForTest();
expect(script).toContain("const Reflect_get = nativeWindow.Reflect.get");
expect(script).toContain("const Reflect_apply = nativeWindow.Reflect.apply");
expect(script).not.toContain("Reflect" + ".get(");
expect(script).not.toContain("Reflect.apply(");
});
});
describe("browser stealth target setup", () => {
it("attempts user-agent override for page-like existing targets and skips non-page worker/browser targets", async () => {
const page = new FakeTarget("page");
const webview = new FakeTarget("webview");
const backgroundPage = new FakeTarget("background_page");
const serviceWorker = new FakeTarget("service_worker");
const sharedWorker = new FakeTarget("shared_worker");
const browserTarget = new FakeTarget("browser");
const other = new FakeTarget("other");
const browser = new FakeBrowser([
page,
webview,
backgroundPage,
serviceWorker,
sharedWorker,
browserTarget,
other,
]);
await configureUserAgentTargetsForTest(browser as unknown as Browser, { browserSession: null, override });
expect(page.createCalls).toBe(1);
expect(webview.createCalls).toBe(1);
expect(backgroundPage.createCalls).toBe(1);
expect(serviceWorker.createCalls).toBe(0);
expect(sharedWorker.createCalls).toBe(0);
expect(browserTarget.createCalls).toBe(0);
expect(other.createCalls).toBe(0);
expect(page.session.detached).toBe(true);
expect(webview.session.detached).toBe(true);
expect(backgroundPage.session.detached).toBe(true);
});
it("classifies only targets with page surfaces as user-agent override targets", () => {
const supportedTypes = ["page", "webview", "background_page"];
const skippedTypes = ["browser", "service_worker", "shared_worker", "other"];
for (const type of supportedTypes) {
expect(targetSupportsUserAgentOverrideForTest({ type: () => type } as unknown as Target)).toBe(true);
}
for (const type of skippedTypes) {
expect(targetSupportsUserAgentOverrideForTest({ type: () => type } as unknown as Target)).toBe(false);
}
});
it("gives a slow page-like target a bounded but non-trivial window to receive user-agent override", async () => {
const slowPage = new FakeTarget("page", 200);
const browser = new FakeBrowser([slowPage]);
const started = performance.now();
await configureUserAgentTargetsForTest(browser as unknown as Browser, { browserSession: null, override }, 50);
const elapsed = performance.now() - started;
expect(elapsed).toBeGreaterThanOrEqual(45);
expect(elapsed).toBeLessThan(500);
});
});