diff --git a/src/shared/utils/clineAuth.ts b/src/shared/utils/clineAuth.ts index c8bab6214c..b923332fa0 100644 --- a/src/shared/utils/clineAuth.ts +++ b/src/shared/utils/clineAuth.ts @@ -13,6 +13,8 @@ import { randomUUID } from "node:crypto"; import { APP_CONFIG } from "../constants/appConfig"; const APP_VERSION = APP_CONFIG.version; +const DEFAULT_CLINE_CLIENT_TYPE = "omniroute"; +const INTERNAL_HEALTH_CHECK_CLIENT_TYPE = "omniroute-internal-health-check"; export interface ClineHeaderContext { taskId?: string; @@ -44,6 +46,12 @@ export function resolveClineTaskId(clientHeaders?: Record | null return getHeaderCaseInsensitive(clientHeaders, "x-task-id") ?? randomUUID(); } +function resolveClineClientType(clientHeaders?: Record | null): string | undefined { + return getHeaderCaseInsensitive(clientHeaders, "x-internal-test") === "combo-health-check" + ? INTERNAL_HEALTH_CHECK_CLIENT_TYPE + : undefined; +} + /** * Apply the required Cline billing headers with case-insensitive replacement. * These fields are authoritative in the official client and must win over @@ -58,12 +66,18 @@ export function applyClineProtocolHeaders( getHeaderCaseInsensitive(headers, "x-task-id") ?? randomUUID(); const clientVersion = cleanHeaderValue(context.clientVersion) ?? APP_VERSION; + const existingClientType = getHeaderCaseInsensitive(headers, "x-client-type"); + const clientType = + cleanHeaderValue(context.clientType) ?? + (existingClientType === INTERNAL_HEALTH_CHECK_CLIENT_TYPE + ? INTERNAL_HEALTH_CHECK_CLIENT_TYPE + : DEFAULT_CLINE_CLIENT_TYPE); const required: Record = { "HTTP-Referer": "https://cline.bot", "X-Title": "Cline", "User-Agent": `Cline/${clientVersion}`, "X-IS-MULTIROOT": context.isMultiRoot === true ? "true" : "false", - "X-CLIENT-TYPE": cleanHeaderValue(context.clientType) ?? "omniroute", + "X-CLIENT-TYPE": clientType, "X-CLIENT-VERSION": clientVersion, "X-PLATFORM": cleanHeaderValue(context.platform) ?? process.platform ?? "unknown", "X-PLATFORM-VERSION": cleanHeaderValue(context.platformVersion) ?? process.version ?? "unknown", @@ -159,7 +173,10 @@ export function applyClineAuthHeaders( clientHeaders: Record | null | undefined, isClinepass: boolean ): Record { - const context: ClineHeaderContext = { taskId: resolveClineTaskId(clientHeaders) }; + const context: ClineHeaderContext = { + taskId: resolveClineTaskId(clientHeaders), + clientType: resolveClineClientType(clientHeaders), + }; const built = isClinepass ? buildClinepassHeaders(credentials, effectiveKey, context) : buildClineHeaders(effectiveKey || credentials?.accessToken, {}, context); diff --git a/tests/unit/cline-workos-auth-token-shape.test.ts b/tests/unit/cline-workos-auth-token-shape.test.ts index 94c73148cd..ab637ac930 100644 --- a/tests/unit/cline-workos-auth-token-shape.test.ts +++ b/tests/unit/cline-workos-auth-token-shape.test.ts @@ -110,3 +110,16 @@ test("DefaultExecutor.buildHeaders uses the cline workos auth token shape", () = assert.equal(headers["X-Title"], "Cline"); assert.equal(headers["X-Task-ID"], "task-from-client"); }); + +test("DefaultExecutor labels internal health checks separately from user traffic", () => { + const executor = new DefaultExecutor("cline"); + const headers = executor.buildHeaders({ apiKey: "tok-abc" }, true, { + "X-Internal-Test": "combo-health-check", + }); + + assert.equal(headers["X-CLIENT-TYPE"], "omniroute-internal-health-check"); + + // BaseExecutor reapplies the required protocol headers immediately before dispatch. + applyClineProtocolHeaders(headers, { taskId: headers["X-Task-ID"] }); + assert.equal(headers["X-CLIENT-TYPE"], "omniroute-internal-health-check"); +});