mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-21 06:02:13 +00:00
175 lines
5.3 KiB
TypeScript
175 lines
5.3 KiB
TypeScript
import type { RuntimeVersionEnv } from "../version.js";
|
|
import { resolveRuntimeServiceVersion } from "../version.js";
|
|
import { normalizeProviderId } from "./model-selection.js";
|
|
|
|
export type ProviderAttributionVerification =
|
|
| "vendor-documented"
|
|
| "vendor-hidden-api-spec"
|
|
| "vendor-sdk-hook-only"
|
|
| "internal-runtime";
|
|
|
|
export type ProviderAttributionHook =
|
|
| "request-headers"
|
|
| "default-headers"
|
|
| "user-agent-extra"
|
|
| "custom-user-agent";
|
|
|
|
export type ProviderAttributionPolicy = {
|
|
provider: string;
|
|
enabledByDefault: boolean;
|
|
verification: ProviderAttributionVerification;
|
|
hook?: ProviderAttributionHook;
|
|
docsUrl?: string;
|
|
reviewNote?: string;
|
|
product: string;
|
|
version: string;
|
|
headers?: Record<string, string>;
|
|
};
|
|
|
|
export type ProviderAttributionIdentity = Pick<ProviderAttributionPolicy, "product" | "version">;
|
|
|
|
const OPENCLAW_ATTRIBUTION_PRODUCT = "OpenClaw";
|
|
const OPENCLAW_ATTRIBUTION_ORIGINATOR = "openclaw";
|
|
|
|
export function resolveProviderAttributionIdentity(
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionIdentity {
|
|
return {
|
|
product: OPENCLAW_ATTRIBUTION_PRODUCT,
|
|
version: resolveRuntimeServiceVersion(env),
|
|
};
|
|
}
|
|
|
|
function buildOpenRouterAttributionPolicy(
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy {
|
|
const identity = resolveProviderAttributionIdentity(env);
|
|
return {
|
|
provider: "openrouter",
|
|
enabledByDefault: true,
|
|
verification: "vendor-documented",
|
|
hook: "request-headers",
|
|
docsUrl: "https://openrouter.ai/docs/app-attribution",
|
|
reviewNote: "Documented app attribution headers. Verified in OpenClaw runtime wrapper.",
|
|
...identity,
|
|
headers: {
|
|
"HTTP-Referer": "https://openclaw.ai",
|
|
"X-OpenRouter-Title": identity.product,
|
|
"X-OpenRouter-Categories": "cli-agent",
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildOpenAIAttributionPolicy(
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy {
|
|
const identity = resolveProviderAttributionIdentity(env);
|
|
return {
|
|
provider: "openai",
|
|
enabledByDefault: true,
|
|
verification: "vendor-hidden-api-spec",
|
|
hook: "request-headers",
|
|
reviewNote:
|
|
"OpenAI native traffic supports hidden originator/User-Agent attribution. Verified against the Codex wire contract.",
|
|
...identity,
|
|
headers: {
|
|
originator: OPENCLAW_ATTRIBUTION_ORIGINATOR,
|
|
"User-Agent": `${OPENCLAW_ATTRIBUTION_ORIGINATOR}/${identity.version}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildOpenAICodexAttributionPolicy(
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy {
|
|
const identity = resolveProviderAttributionIdentity(env);
|
|
return {
|
|
provider: "openai-codex",
|
|
enabledByDefault: true,
|
|
verification: "vendor-hidden-api-spec",
|
|
hook: "request-headers",
|
|
reviewNote:
|
|
"OpenAI Codex ChatGPT-backed traffic supports the same hidden originator/User-Agent attribution contract.",
|
|
...identity,
|
|
headers: {
|
|
originator: OPENCLAW_ATTRIBUTION_ORIGINATOR,
|
|
"User-Agent": `${OPENCLAW_ATTRIBUTION_ORIGINATOR}/${identity.version}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildSdkHookOnlyPolicy(
|
|
provider: string,
|
|
hook: ProviderAttributionHook,
|
|
reviewNote: string,
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy {
|
|
return {
|
|
provider,
|
|
enabledByDefault: false,
|
|
verification: "vendor-sdk-hook-only",
|
|
hook,
|
|
reviewNote,
|
|
...resolveProviderAttributionIdentity(env),
|
|
};
|
|
}
|
|
|
|
export function listProviderAttributionPolicies(
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy[] {
|
|
return [
|
|
buildOpenRouterAttributionPolicy(env),
|
|
buildOpenAIAttributionPolicy(env),
|
|
buildOpenAICodexAttributionPolicy(env),
|
|
buildSdkHookOnlyPolicy(
|
|
"anthropic",
|
|
"default-headers",
|
|
"Anthropic JS SDK exposes defaultHeaders, but app attribution is not yet verified.",
|
|
env,
|
|
),
|
|
buildSdkHookOnlyPolicy(
|
|
"google",
|
|
"user-agent-extra",
|
|
"Google GenAI JS SDK exposes userAgentExtra/httpOptions, but provider-side attribution is not yet verified.",
|
|
env,
|
|
),
|
|
buildSdkHookOnlyPolicy(
|
|
"groq",
|
|
"default-headers",
|
|
"Groq JS SDK exposes defaultHeaders, but app attribution is not yet verified.",
|
|
env,
|
|
),
|
|
buildSdkHookOnlyPolicy(
|
|
"mistral",
|
|
"custom-user-agent",
|
|
"Mistral JS SDK exposes a custom userAgent option, but app attribution is not yet verified.",
|
|
env,
|
|
),
|
|
buildSdkHookOnlyPolicy(
|
|
"together",
|
|
"default-headers",
|
|
"Together JS SDK exposes defaultHeaders, but app attribution is not yet verified.",
|
|
env,
|
|
),
|
|
];
|
|
}
|
|
|
|
export function resolveProviderAttributionPolicy(
|
|
provider?: string | null,
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): ProviderAttributionPolicy | undefined {
|
|
const normalized = normalizeProviderId(provider ?? "");
|
|
return listProviderAttributionPolicies(env).find((policy) => policy.provider === normalized);
|
|
}
|
|
|
|
export function resolveProviderAttributionHeaders(
|
|
provider?: string | null,
|
|
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
|
|
): Record<string, string> | undefined {
|
|
const policy = resolveProviderAttributionPolicy(provider, env);
|
|
if (!policy?.enabledByDefault) {
|
|
return undefined;
|
|
}
|
|
return policy.headers;
|
|
}
|