/**
 * Which CLI is calling, from its User-Agent.
 *
 * The proxy already computed a client label for trace spans, but it only
 * distinguished `claude-cli/` from `ai/` and dropped the result into an OTel
 * attribute. Nothing persisted it, so usage could be attributed to an account
 * but never to the tool that spent it — the question a pooled-subscription
 * operator actually asks.
 *
 * Two rules keep this honest as the roster grows:
 *
 * - **Only prefixes observed in real traffic appear here.** A guessed mapping
 *   that never matches is indistinguishable from one that works, and silently
 *   files a client under the wrong name if the guess collides.
 * - **The raw header is persisted alongside the derived name.** An unrecognised
 *   client is then still attributable by its own User-Agent rather than
 *   collapsing into one bucket with every other unknown.
 */
/**
 * Deliberately NOT mapped, and why each was ruled out.
 *
 * These two strings are unrelated to each other. They are grouped only because
 * both were candidates for a Copilot mapping at some point, and neither can
 * carry one.
 *
 * - `OpenAI/JS 5.20.1` — Copilot CLI's actual User-Agent, and the problem is
 *   that it is not Copilot's alone: it is the stock OpenAI JS SDK string, sent
 *   by every caller of that SDK. Mapping it would file unrelated OpenAI-SDK
 *   traffic under Copilot's name, which is worse than leaving it unattributed.
 *   Copilot also sends `x-initiator` and `x-interaction-type`, but neither is
 *   exclusive to it either, so it stays `unknown` and remains traceable
 *   through the stored raw header.
 *
 * - `Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)` — not a
 *   CLI's User-Agent at all, and in particular NOT Copilot's. It is what
 *   `curl` sends on a machine whose `~/.curlrc` sets `user-agent`, so every
 *   curl-driven caller on such a host shares it: scripts, agents, health
 *   probes. It accounted for the largest single block of `unknown` rows in the
 *   log this table was measured against, which is exactly what made it
 *   tempting.
 *
 *   Recorded because the first pass got this wrong in a way worth naming. The
 *   string was seen arriving at two capture servers during a Copilot CLI run
 *   and a Gemini CLI run, and was written up as "sent by both CLIs". It was
 *   sent by neither: it was the aliveness `curl` fired at each capture server
 *   moments before the CLI was pointed at it, picking up that host's curlrc.
 *   The request paths gave it away on review — the Gemini-side hit was a bare
 *   `GET /v1beta/models`, which is the probe's URL and not one the CLI
 *   requests. An identical unusual string arriving from two unrelated clients
 *   is evidence of shared tooling, never a property of either client.
 */
/**
 * The client names this table can produce.
 *
 * Exported so a test can check the roster of CLIs the proxy configures against
 * the roster it can actually name. Those two lists drifted apart silently once
 * already: five configurators shipped while the table still knew only Claude
 * Code, and nothing failed, because an unattributed client looks exactly like
 * a quiet one.
 */
export declare function getMappedClientNames(): ReadonlySet<string>;
/**
 * Derive a stable client name, or "unknown" when the header is absent or
 * unrecognised. Never throws: attribution must not be able to fail a request.
 */
export declare function detectProxyClient(userAgent: string | undefined): string;
/** Read the User-Agent case-insensitively and bound it for storage. */
export declare function readUserAgent(headers: Record<string, string> | undefined): string | undefined;
/** The pair every proxy engine attaches to its request log entry. */
export declare function buildClientAttribution(headers: Record<string, string> | undefined): {
    clientApp: string;
    userAgent?: string;
};
