import { createServer } from "node:http"; import type { AddressInfo } from "node:net"; import { expect, test } from "@playwright/test"; import { captureScreenshot, completeOnboarding, openUserSettings, rpc, signup } from "./helpers"; const LOCAL_MODEL_ID = "rakazo-e2e-local"; const LOCAL_MODEL_REPLY = "OpenAI-compatible endpoint verified end to end."; test("custom connections persist reasoning support and bot thinking", async ({ page, }, testInfo) => { const stamp = Date.now(); const userName = `Reasoning ${stamp}`; await signup(page, `reasoning-model-${stamp}@rakazo.test`, "password12", userName); await completeOnboarding(page); await openUserSettings(page, "models"); await page.getByPlaceholder("Search providers").fill("openai-compatible"); await page.getByRole("button", { name: /OpenAI-compatible/ }).click(); await page.getByLabel("OpenAI-compatible server URL").fill("http://127.0.0.1:8090/v1"); await page.getByLabel("Model id").fill("arbitrary-model"); await expect(page.getByRole("checkbox", { name: "Supports thinking" })).toBeHidden(); await expect(page.getByRole("checkbox", { name: "Supports images" })).toBeHidden(); await page.getByText("Advanced", { exact: true }).click(); await page.getByRole("checkbox", { name: "Supports thinking" }).check(); await page.getByRole("combobox", { name: "Reasoning effort", exact: true }).selectOption("low"); await page.getByLabel("Maximum output tokens").fill("8192"); await page.getByLabel("Context limit").fill("65536"); await page.getByRole("checkbox", { name: "Supports images" }).check(); await page.getByLabel("Maximum images per request").fill("1"); await captureScreenshot(page, testInfo, "openai-compatible-thinking-connection"); await page.getByRole("button", { name: "Save", exact: true }).click(); await expect(page.getByText("Saved.", { exact: true })).toBeVisible(); const credentials = await rpc< Array<{ modelId?: string; reasoning?: boolean; thinkingLevel?: string | null; maxTokens?: number; contextWindow?: number; supportsImages?: boolean; maxImagesPerPrompt?: number; }> >(page, "models/credentials", {}); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.reasoning).toBe(true); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.thinkingLevel).toBe( "low", ); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.maxTokens).toBe(8192); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.contextWindow).toBe( 65536, ); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.supportsImages).toBe( true, ); expect(credentials.find((entry) => entry.modelId === "arbitrary-model")?.maxImagesPerPrompt).toBe( 1, ); await page.reload(); await openUserSettings(page, "models"); await page.getByText("Advanced", { exact: true }).click(); await expect(page.getByRole("checkbox", { name: "Supports thinking" })).toBeChecked(); await expect(page.getByRole("combobox", { name: "Reasoning effort", exact: true })).toHaveValue( "low", ); await expect(page.getByLabel("Maximum output tokens")).toHaveValue("8192"); await expect(page.getByLabel("Context limit")).toHaveValue("65536"); await expect(page.getByRole("checkbox", { name: "Supports images" })).toBeChecked(); await expect(page.getByLabel("Maximum images per request")).toHaveValue("1"); await page.getByLabel("Maximum images per request").fill(""); await page.getByRole("button", { name: "Save", exact: true }).click(); await expect(page.getByText("Saved.", { exact: true })).toBeVisible(); const clearedCredentials = await rpc>( page, "models/credentials", {}, ); expect( clearedCredentials.find((entry) => entry.modelId === "arbitrary-model")?.maxImagesPerPrompt, ).toBeUndefined(); await page.getByRole("button", { name: "Close model settings" }).click(); await page.locator("main").getByRole("button", { name: "Chief", exact: true }).click(); const settings = page.getByTestId("bot-settings"); await expect(settings).toBeVisible(); const advanced = settings.getByTestId("bot-settings-advanced"); await advanced.evaluate((element) => { (element as HTMLDetailsElement).open = true; }); // NativeSelect sits inside a wrapping