openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
610 lines (609 loc) • 28.2 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { r as createLazyRuntimeModule, t as createLazyRuntimeMethod } from "./lazy-runtime-CgCh8H_K.js";
import { _ as supportsClaudeNativeXhighEffort, c as resolveClaudeModelIdentity, d as resolveClaudeOpus5ModelIdentity, f as resolveClaudeSonnet5ModelIdentity, g as supportsClaudeNativeMaxEffort, l as resolveClaudeMythos5ModelIdentity, m as supportsClaudeAdaptiveThinking, p as supportsClaude1MContext, s as resolveClaudeFable5ModelIdentity } from "./anthropic-DfKaEfcc.js";
import { n as buildManifestModelProviderConfig } from "./provider-catalog-8ARoyQkL.js";
import { n as resolveClaudeThinkingProfile } from "./provider-claude-thinking-ZZ6yytGk.js";
import { m as isAnthropicOAuthApiKey } from "./provider-stream-shared-DakgNCd0.js";
import { t as createProviderApiKeyAuthMethod } from "./provider-api-key-auth-mNtReYE0.js";
import "./string-coerce-runtime-GQa0ehRA.js";
import { a as buildProviderReplayFamilyHooks, c as modelCostsEqual, p as cloneFirstTemplateModel } from "./provider-model-shared-fX-Ywqb3.js";
import "./provider-catalog-shared-B4jeC2Nd.js";
import "./provider-entry-CPCFGnL8.js";
import { c as CLAUDE_CLI_OFF_THINKING_PROFILE, f as CLAUDE_MODEL_ID_ALIASES, i as CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS, l as CLAUDE_CLI_PROFILE_ID, n as CLAUDE_CLI_CANONICAL_DEFAULT_MODEL_REF, p as modelCatalog, t as CLAUDE_CLI_BACKEND_ID } from "./cli-constants-Dsp5krT8.js";
import { o as supportsClaudeDynamicSystemPromptSections } from "./cli-shared-CG1e0C2R.js";
import { t as buildAnthropicCliBackend } from "./cli-backend-DnKWkDNh.js";
import { n as normalizeAnthropicProviderConfigForProvider, t as applyAnthropicConfigDefaults } from "./config-defaults-BNZXO8PG.js";
import { t as acceptsAnthropicLiveModelContract } from "./live-model-contract-gate-COwzxGD_.js";
import { t as anthropicMediaUnderstandingProvider } from "./media-understanding-provider-Da7rtyfS.js";
import { n as prepareClaudeCliSyntheticAuth } from "./provider-discovery-Dn1_OaYj.js";
import { n as registerClaudeSessionDiscovery, t as createClaudeSessionNodeInvokePolicies } from "./session-catalog-registration-D2_kqRf8.js";
import { s as wrapAnthropicProviderStream } from "./stream-wrappers-DxN-2fFz.js";
import { n as resolveAnthropicUsageAuth, t as fetchAnthropicUsage } from "./usage-BkxZFS8w.js";
//#region extensions/anthropic/register.runtime.ts
/**
* Anthropic provider runtime registration. It owns API-key/setup-token/Claude
* CLI auth, dynamic model normalization, usage auth, media, and stream wrappers.
*/
const loadAuthRuntime = createLazyRuntimeModule(() => import("./extensions/anthropic/auth.runtime.js"));
const buildOpenAICompatibleProviderCatalog = createLazyRuntimeMethod(createLazyRuntimeModule(() => import("./plugin-sdk/provider-catalog-live-runtime.js")), (runtime) => runtime.buildOpenAICompatibleProviderCatalog);
const PROVIDER_ID = "anthropic";
function classifyAnthropicFailoverDescriptor(value) {
switch (value?.trim().toUpperCase()) {
case "RATE_LIMIT_ERROR": return "rate_limit";
case "API_ERROR": return "server_error";
default: return;
}
}
const DEFAULT_ANTHROPIC_MODEL = "anthropic/claude-opus-5";
const ANTHROPIC_OPUS_48_MODEL_ID = "claude-opus-4-8";
const ANTHROPIC_OPUS_48_DOT_MODEL_ID = "claude-opus-4.8";
const ANTHROPIC_OPUS_47_MODEL_ID = "claude-opus-4-7";
const ANTHROPIC_OPUS_47_DOT_MODEL_ID = "claude-opus-4.7";
const ANTHROPIC_1M_CONTEXT_TOKENS = 1e6;
const ANTHROPIC_MODERN_MAX_OUTPUT_TOKENS = 128e3;
const ANTHROPIC_SONNET_5_STANDARD_PRICING_START_MS = Date.UTC(2026, 8, 1);
const ANTHROPIC_SONNET_5_PROMOTIONAL_COST = {
input: 2,
output: 10,
cacheRead: .2,
cacheWrite: 2.5
};
const ANTHROPIC_SONNET_5_STANDARD_COST = {
input: 3,
output: 15,
cacheRead: .3,
cacheWrite: 3.75
};
const ANTHROPIC_OPUS_46_MODEL_ID = "claude-opus-4-6";
const ANTHROPIC_OPUS_46_DOT_MODEL_ID = "claude-opus-4.6";
const ANTHROPIC_OPUS_47_TEMPLATE_MODEL_IDS = [ANTHROPIC_OPUS_46_MODEL_ID, ANTHROPIC_OPUS_46_DOT_MODEL_ID];
const ANTHROPIC_SONNET_46_MODEL_ID = "claude-sonnet-4-6";
const ANTHROPIC_SONNET_46_DOT_MODEL_ID = "claude-sonnet-4.6";
function buildAnthropicCatalogProvider() {
return buildManifestModelProviderConfig({
providerId: PROVIDER_ID,
catalog: modelCatalog.providers.anthropic
});
}
/**
* Discovery credentials arrive as either an API key or a Claude subscription
* OAuth access token. Anthropic rejects an OAuth token sent as `x-api-key`, and
* rejects the request outright when both auth headers are present, so the two
* shapes must select mutually exclusive headers.
*/
function buildAnthropicDiscoveryAuthHeaders(key) {
if (!key) return {};
return isAnthropicOAuthApiKey(key) ? { authorization: `Bearer ${key}` } : { "x-api-key": key };
}
/**
* Live discovery replaces the seed catalog with whatever `/v1/models` returns.
* Anthropic does not publish every model it serves, so replacement alone would
* hide shipped entries that have no live row. Re-add the manifest models the
* live response omitted; discovered rows still win on shared ids.
*/
function restoreUnpublishedAnthropicModels(result) {
if (!result || !("provider" in result)) return result;
const discovered = result.provider.models ?? [];
if (discovered.length === 0) return result;
const discoveredIds = new Set(discovered.map((model) => model.id));
const unpublished = (buildAnthropicCatalogProvider().models ?? []).filter((model) => !discoveredIds.has(model.id));
if (unpublished.length === 0) return result;
return { provider: {
...result.provider,
models: [...discovered, ...unpublished.toSorted((a, b) => a.id.localeCompare(b.id))]
} };
}
function resolveAnthropicSonnet5Cost(nowMs = Date.now()) {
return nowMs >= ANTHROPIC_SONNET_5_STANDARD_PRICING_START_MS ? ANTHROPIC_SONNET_5_STANDARD_COST : ANTHROPIC_SONNET_5_PROMOTIONAL_COST;
}
function resolveAnthropicModelCost(modelId) {
const normalized = resolveClaudeModelIdentity({ id: modelId }).replace(/-\d{8}$/, "");
const id = CLAUDE_MODEL_ID_ALIASES.get(normalized) ?? normalized;
return isAnthropicSonnet5Model(id) ? resolveAnthropicSonnet5Cost() : modelCatalog.providers.anthropic.models.find((model) => model.id === id)?.cost;
}
const CLAUDE_CLI_CANONICAL_ALLOWLIST_REFS = CLAUDE_CLI_DEFAULT_ALLOWLIST_REFS.map((ref) => ref.startsWith(`claude-cli/`) ? `anthropic/${ref.slice(CLAUDE_CLI_BACKEND_ID.length + 1)}` : ref);
function resolveAnthropic46ForwardCompatModel(params) {
const trimmedModelId = params.ctx.modelId.trim();
const lower = normalizeLowercaseStringOrEmpty(trimmedModelId);
if (trimmedModelId !== lower) return;
if (!(lower === params.dashModelId || lower === params.dotModelId || lower.startsWith(`${params.dashModelId}-`) || lower.startsWith(`${params.dotModelId}-`))) return;
const templateIds = [];
if (lower.startsWith(params.dashModelId)) templateIds.push(lower.replace(params.dashModelId, params.dashTemplateId));
if (lower.startsWith(params.dotModelId)) templateIds.push(lower.replace(params.dotModelId, params.dotTemplateId));
templateIds.push(...params.fallbackTemplateIds);
return cloneFirstTemplateModel({
providerId: PROVIDER_ID,
modelId: trimmedModelId,
templateIds,
ctx: params.ctx,
patch: normalizeLowercaseStringOrEmpty(params.ctx.provider) === "claude-cli" ? { provider: CLAUDE_CLI_BACKEND_ID } : void 0
});
}
function resolveAnthropicSnapshotModel(ctx) {
const modelId = ctx.modelId.trim();
const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
const match = /^(claude-[a-z0-9]+(?:-[a-z0-9]+)*)-\d{8}$/.exec(normalizedModelId);
if (modelId !== normalizedModelId || normalizeLowercaseStringOrEmpty(ctx.provider) !== PROVIDER_ID || !match) return;
const templateId = match[1];
const captured = cloneFirstTemplateModel({
providerId: PROVIDER_ID,
modelId,
templateIds: [templateId],
ctx
});
if (captured) return captured;
const template = resolveAnthropicManifestModel(templateId);
return template ? {
...template,
id: modelId,
name: modelId
} : void 0;
}
/** Newest Claude generation whose request contract this plugin encodes. */
const ANTHROPIC_NEWEST_KNOWN_GENERATION = {
major: 5,
minor: 0
};
/**
* Read the generation from either Claude id order: `claude-<family>-<major>[-<minor>]`
* (4.6 onward) and `claude-<major>[-<minor>]-<family>` (through 3.7). The minor
* capture is bounded to two digits so a trailing snapshot date such as
* `claude-opus-4-20250514` does not parse as a minor version.
*/
function resolveAnthropicModelGeneration(modelId) {
const match = /claude-[a-z]+-(\d{1,2})(?:-(\d{1,2}))?(?![0-9])/.exec(modelId) ?? /claude-(\d{1,2})(?:-(\d{1,2}))?(?![0-9])/.exec(modelId);
if (!match) return;
return {
major: Number(match[1]),
minor: match[2] === void 0 ? 0 : Number(match[2])
};
}
/**
* Claude ids from a generation newer than anything this plugin encodes. Request
* shaping is selected by version predicates in `@openclaw/llm-core`, so such an
* id would otherwise fall through to pre-4.6 shaping — manual `budget_tokens`
* plus caller sampling params — which current models reject outright.
*/
function isAnthropicUnreleasedGenerationModel(modelId) {
if (matchesAnthropicModernModel(modelId)) return false;
const generation = resolveAnthropicModelGeneration(modelId);
if (!generation) return false;
return generation.major > ANTHROPIC_NEWEST_KNOWN_GENERATION.major || generation.major === ANTHROPIC_NEWEST_KNOWN_GENERATION.major && generation.minor > ANTHROPIC_NEWEST_KNOWN_GENERATION.minor;
}
/**
* Route an unreleased id onto the newest contract we encode, matching family
* when we recognize it. Stamping `canonicalModelId` is the same seam Bedrock and
* Mantle use to map a provider-native id onto a canonical Claude contract, so
* shaping follows without teaching the shared contracts about unknown ids.
*/
function resolveAnthropicUnreleasedCanonicalModelId(modelId) {
return /(?:^|-)claude-sonnet-/.test(modelId) ? "claude-sonnet-5" : "claude-opus-5";
}
let anthropicManifestModelIndex;
function resolveAnthropicManifestModel(modelId) {
if (!anthropicManifestModelIndex) {
anthropicManifestModelIndex = /* @__PURE__ */ new Map();
const catalog = buildAnthropicCatalogProvider();
for (const model of catalog.models ?? []) {
const api = model.api ?? catalog.api;
const baseUrl = model.baseUrl ?? catalog.baseUrl;
if (api && baseUrl) anthropicManifestModelIndex.set(model.id, {
...model,
input: model.input.filter((item) => item === "text" || item === "image"),
provider: PROVIDER_ID,
api,
baseUrl
});
}
}
return anthropicManifestModelIndex.get(modelId);
}
function resolveAnthropicManifestCompat(provider, modelId) {
return normalizeLowercaseStringOrEmpty(provider) === PROVIDER_ID ? resolveAnthropicManifestModel(modelId)?.compat : void 0;
}
function buildAnthropicForwardCompatModel(ctx) {
const trimmedModelId = ctx.modelId.trim();
const lower = normalizeLowercaseStringOrEmpty(trimmedModelId);
const normalizedProvider = normalizeLowercaseStringOrEmpty(ctx.provider);
const unreleasedGeneration = isAnthropicUnreleasedGenerationModel(lower);
if (trimmedModelId !== lower || !(matchesAnthropicModernModel(lower) || unreleasedGeneration)) return;
if (isAnthropicMandatoryClaude5Model(lower) && normalizedProvider !== PROVIDER_ID) return;
const provider = normalizedProvider === "claude-cli" ? CLAUDE_CLI_BACKEND_ID : PROVIDER_ID;
const compat = ctx.modelRegistry.find(provider, trimmedModelId)?.compat ?? resolveAnthropicManifestCompat(provider, trimmedModelId);
return {
id: trimmedModelId,
name: trimmedModelId,
provider,
...compat ? { compat } : {},
api: "anthropic-messages",
baseUrl: "https://api.anthropic.com",
reasoning: true,
input: ["text", "image"],
cost: (provider === PROVIDER_ID ? resolveAnthropicModelCost(trimmedModelId) : void 0) ?? {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0
},
contextWindow: resolveAnthropicFixedContextWindow(provider, trimmedModelId) ?? 2e5,
maxTokens: isAnthropic128kOutputModel(trimmedModelId) ? ANTHROPIC_MODERN_MAX_OUTPUT_TOKENS : 64e3,
...unreleasedGeneration ? { params: { canonicalModelId: resolveAnthropicUnreleasedCanonicalModelId(lower) } } : {},
...supportsClaudeNativeXhighEffort({ id: trimmedModelId }) ? { thinkingLevelMap: {
...isAnthropicMandatoryClaude5Model(trimmedModelId) ? { minimal: "low" } : {},
xhigh: "xhigh",
max: "max"
} } : supportsAnthropicNativeMaxEffort(trimmedModelId) ? { thinkingLevelMap: { max: "max" } } : {}
};
}
function resolveAnthropicForwardCompatModel(ctx) {
return resolveAnthropicSnapshotModel(ctx) ?? resolveAnthropic46ForwardCompatModel({
ctx,
dashModelId: ANTHROPIC_OPUS_48_MODEL_ID,
dotModelId: ANTHROPIC_OPUS_48_DOT_MODEL_ID,
dashTemplateId: ANTHROPIC_OPUS_47_MODEL_ID,
dotTemplateId: ANTHROPIC_OPUS_47_DOT_MODEL_ID,
fallbackTemplateIds: ANTHROPIC_OPUS_47_TEMPLATE_MODEL_IDS
}) ?? resolveAnthropic46ForwardCompatModel({
ctx,
dashModelId: ANTHROPIC_OPUS_47_MODEL_ID,
dotModelId: ANTHROPIC_OPUS_47_DOT_MODEL_ID,
dashTemplateId: ANTHROPIC_OPUS_46_MODEL_ID,
dotTemplateId: ANTHROPIC_OPUS_46_DOT_MODEL_ID,
fallbackTemplateIds: ANTHROPIC_OPUS_47_TEMPLATE_MODEL_IDS
}) ?? resolveAnthropic46ForwardCompatModel({
ctx,
dashModelId: ANTHROPIC_OPUS_46_MODEL_ID,
dotModelId: ANTHROPIC_OPUS_46_DOT_MODEL_ID,
dashTemplateId: ANTHROPIC_OPUS_47_MODEL_ID,
dotTemplateId: ANTHROPIC_OPUS_46_MODEL_ID,
fallbackTemplateIds: ANTHROPIC_OPUS_47_TEMPLATE_MODEL_IDS
}) ?? resolveAnthropic46ForwardCompatModel({
ctx,
dashModelId: ANTHROPIC_SONNET_46_MODEL_ID,
dotModelId: ANTHROPIC_SONNET_46_DOT_MODEL_ID,
dashTemplateId: ANTHROPIC_SONNET_46_MODEL_ID,
dotTemplateId: ANTHROPIC_SONNET_46_MODEL_ID,
fallbackTemplateIds: [ANTHROPIC_SONNET_46_MODEL_ID, ANTHROPIC_SONNET_46_DOT_MODEL_ID]
}) ?? buildAnthropicForwardCompatModel(ctx);
}
function isAnthropicGa1MModel(modelId) {
return supportsClaude1MContext({ id: modelId });
}
function isAnthropicFable5Model(modelId) {
return resolveClaudeFable5ModelIdentity({ id: modelId }) !== void 0;
}
function isAnthropicMythos5Model(modelId) {
return resolveClaudeMythos5ModelIdentity({ id: modelId }) !== void 0;
}
function isAnthropicMandatoryClaude5Model(modelId) {
return isAnthropicFable5Model(modelId) || isAnthropicMythos5Model(modelId);
}
function isAnthropicSonnet5Model(modelId) {
return resolveClaudeSonnet5ModelIdentity({ id: modelId }) !== void 0;
}
function isAnthropicOpus5Model(modelId) {
return resolveClaudeOpus5ModelIdentity({ id: modelId }) !== void 0;
}
function isAnthropicExact1MClaude5Model(modelId) {
return isAnthropicMandatoryClaude5Model(modelId) || isAnthropicSonnet5Model(modelId) || isAnthropicOpus5Model(modelId);
}
function resolveAnthropicFixedContextWindow(provider, modelId) {
return isAnthropicExact1MClaude5Model(modelId) || isAnthropicGa1MModel(modelId) && (normalizeLowercaseStringOrEmpty(provider) !== "claude-cli" || normalizeLowercaseStringOrEmpty(modelId).endsWith("[1m]")) ? ANTHROPIC_1M_CONTEXT_TOKENS : void 0;
}
function isAnthropic128kOutputModel(modelId) {
return isAnthropicExact1MClaude5Model(modelId) || isAnthropicGa1MModel(modelId);
}
function isAnthropicLargeImageModel(modelId) {
return supportsClaudeNativeXhighEffort({ id: modelId });
}
function isAnthropicMythosPreviewModel(modelId) {
return /(?:^|-)claude-mythos-preview(?=$|[^a-z0-9])/.test(resolveClaudeModelIdentity({ id: modelId }));
}
function supportsAnthropicNativeMaxEffort(modelId) {
return supportsClaudeNativeMaxEffort({ id: modelId }) || isAnthropicMythosPreviewModel(modelId);
}
function hasConfiguredModelOverride(config, provider, modelId, override) {
const providers = config?.models?.providers;
if (!providers || typeof providers !== "object") return false;
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
for (const [providerId, providerConfig] of Object.entries(providers)) {
if (normalizeLowercaseStringOrEmpty(providerId) !== normalizedProvider) continue;
if (!Array.isArray(providerConfig?.models)) continue;
for (const model of providerConfig.models) {
if (normalizeLowercaseStringOrEmpty(typeof model?.id === "string" ? model.id : "") !== normalizedModelId) continue;
if (override === "cost" ? model?.cost !== void 0 : typeof model?.contextTokens === "number" && model.contextTokens > 0 || typeof model?.contextWindow === "number" && model.contextWindow > 0) return true;
}
}
return false;
}
function applyAnthropicFixedContextWindow(params) {
const fixedContextWindow = resolveAnthropicFixedContextWindow(params.provider, params.contractModelId);
if (fixedContextWindow === void 0) return;
if (hasConfiguredModelOverride(params.config, params.provider, params.modelId, "context")) return;
const exactContextWindow = isAnthropicExact1MClaude5Model(params.contractModelId);
const nextContextWindow = exactContextWindow ? fixedContextWindow : Math.max(params.model.contextWindow ?? 0, fixedContextWindow);
const nextContextTokens = exactContextWindow ? fixedContextWindow : typeof params.model.contextTokens === "number" ? Math.max(params.model.contextTokens, fixedContextWindow) : fixedContextWindow;
if (nextContextWindow === params.model.contextWindow && nextContextTokens === params.model.contextTokens) return;
return {
...params.model,
contextWindow: nextContextWindow,
contextTokens: nextContextTokens
};
}
function applyAnthropicModernMaxTokens(params) {
if (!isAnthropic128kOutputModel(params.modelId)) return;
if ((params.model.maxTokens ?? 0) >= ANTHROPIC_MODERN_MAX_OUTPUT_TOKENS) return;
return {
...params.model,
maxTokens: ANTHROPIC_MODERN_MAX_OUTPUT_TOKENS
};
}
function applyAnthropicThinkingLevelMap(params) {
const mandatoryClaude5 = isAnthropicMandatoryClaude5Model(params.modelId);
const nativeXhigh = mandatoryClaude5 || supportsClaudeNativeXhighEffort({ id: params.modelId });
if (!supportsAnthropicNativeMaxEffort(params.modelId)) return;
const current = params.model.thinkingLevelMap;
const nativeDefaults = isAnthropicMythosPreviewModel(params.modelId) ? { max: "max" } : {
...mandatoryClaude5 ? { minimal: "low" } : {},
xhigh: nativeXhigh ? "xhigh" : null,
max: "max"
};
const currentEfforts = current;
if (Object.keys(nativeDefaults).every((level) => currentEfforts?.[level] !== void 0)) return;
return {
...params.model,
thinkingLevelMap: {
...nativeDefaults,
...current
}
};
}
function matchesAnthropicModernModel(modelId) {
return supportsClaudeAdaptiveThinking({ id: modelId }) || isAnthropicMythosPreviewModel(modelId);
}
function hasImageInput(input) {
return Array.isArray(input) && input.includes("image");
}
function supportsAnthropicImageInput(modelId, modelName) {
return [modelId, modelName].filter((value) => typeof value === "string").some((candidate) => matchesAnthropicModernModel(candidate));
}
function resolveAnthropicImageMediaInput(modelId, modelName) {
if (!supportsAnthropicImageInput(modelId, modelName)) return;
const largeImageModel = [modelId, modelName].filter((value) => typeof value === "string").some((ref) => isAnthropicLargeImageModel(ref));
return { image: {
maxSidePx: largeImageModel ? 2576 : 1568,
preferredSidePx: largeImageModel ? 2576 : 1568,
tokenMode: "provider"
} };
}
function applyAnthropicImageInputCapability(params) {
if (hasImageInput(params.model.input)) return;
if (!supportsAnthropicImageInput(params.modelId, params.model.name)) return;
return {
...params.model,
input: ["text", "image"]
};
}
function normalizeAnthropicResolvedModel(ctx) {
const contractModelId = resolveClaudeModelIdentity({
id: ctx.modelId,
params: ctx.model.params
});
if (isAnthropicMandatoryClaude5Model(contractModelId) && normalizeLowercaseStringOrEmpty(ctx.provider) !== PROVIDER_ID) return;
const contractModel = isAnthropicExact1MClaude5Model(contractModelId) && !ctx.model.reasoning ? {
...ctx.model,
reasoning: true
} : ctx.model;
const imageCapableModel = applyAnthropicImageInputCapability({
modelId: contractModelId,
model: contractModel
}) ?? contractModel;
const mediaInput = resolveAnthropicImageMediaInput(contractModelId, imageCapableModel.name);
const mediaInputModel = mediaInput ? {
...imageCapableModel,
mediaInput: {
...mediaInput,
...imageCapableModel.mediaInput,
image: {
...mediaInput.image,
...imageCapableModel.mediaInput?.image
}
}
} : imageCapableModel;
const outputModel = applyAnthropicModernMaxTokens({
modelId: contractModelId,
model: mediaInputModel
}) ?? mediaInputModel;
const thinkingLevelModel = applyAnthropicThinkingLevelMap({
modelId: contractModelId,
model: outputModel
}) ?? outputModel;
const contextWindowModel = applyAnthropicFixedContextWindow({
config: ctx.config,
provider: ctx.provider,
modelId: ctx.modelId,
contractModelId,
model: thinkingLevelModel
}) ?? thinkingLevelModel;
const cost = resolveAnthropicModelCost(contractModelId);
const pricingModel = normalizeLowercaseStringOrEmpty(ctx.provider) === PROVIDER_ID && !hasConfiguredModelOverride(ctx.config, ctx.provider, ctx.modelId, "cost") && cost && !modelCostsEqual(contextWindowModel.cost, cost) ? {
...contextWindowModel,
cost
} : contextWindowModel;
return pricingModel === ctx.model ? void 0 : pricingModel;
}
/** Build the full Anthropic provider descriptor used by runtime registration. */
function buildAnthropicProvider() {
const providerId = "anthropic";
const defaultAnthropicModel = DEFAULT_ANTHROPIC_MODEL;
return {
id: providerId,
label: "Anthropic",
deprecatedProfileIds: [CLAUDE_CLI_PROFILE_ID],
docsPath: "/providers/models",
hookAliases: [CLAUDE_CLI_BACKEND_ID],
envVars: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
oauthProfileIdRepairs: [{
legacyProfileId: "anthropic:default",
promptLabel: "Anthropic"
}],
auth: [
{
id: "cli",
label: "Claude CLI",
hint: "Keep using a local Claude CLI login and run Anthropic models through the Claude CLI runtime",
kind: "custom",
wizard: {
choiceId: "anthropic-cli",
choiceLabel: "Anthropic Claude CLI",
choiceHint: "Keep using an existing Claude Code CLI login on this host",
assistantPriority: -20,
groupId: "anthropic",
groupLabel: "Anthropic",
groupHint: "Claude CLI + API key",
modelAllowlist: {
allowedKeys: [...CLAUDE_CLI_CANONICAL_ALLOWLIST_REFS],
initialSelections: [CLAUDE_CLI_CANONICAL_DEFAULT_MODEL_REF],
message: "Claude CLI models"
}
},
run: async (ctx) => await (await loadAuthRuntime()).runAnthropicCliMigration(ctx),
runNonInteractive: async (ctx) => await (await loadAuthRuntime()).runAnthropicCliMigrationNonInteractive({
config: ctx.config,
runtime: ctx.runtime,
agentDir: ctx.agentDir
})
},
{
id: "setup-token",
label: "Anthropic setup-token",
hint: "Paste a long-lived token created with 'claude setup-token'",
kind: "token",
wizard: {
choiceId: "setup-token",
choiceLabel: "Anthropic setup-token",
choiceHint: "Token created by running 'claude setup-token' in your terminal",
assistantPriority: 40,
groupId: "anthropic",
groupLabel: "Anthropic",
groupHint: "Claude CLI + API key + token"
},
run: async (ctx) => await (await loadAuthRuntime()).runAnthropicSetupTokenAuth(ctx, defaultAnthropicModel),
validateNonInteractive: async (ctx) => Boolean((await loadAuthRuntime()).validateAnthropicSetupTokenNonInteractive(ctx)),
runNonInteractive: async (ctx) => await (await loadAuthRuntime()).runAnthropicSetupTokenNonInteractive(ctx, defaultAnthropicModel)
},
createProviderApiKeyAuthMethod({
providerId,
methodId: "api-key",
label: "Anthropic API key",
hint: "Direct Anthropic API key",
optionKey: "anthropicApiKey",
flagName: "--anthropic-api-key",
envVar: "ANTHROPIC_API_KEY",
promptMessage: "Enter Anthropic API key",
defaultModel: defaultAnthropicModel,
expectedProviders: ["anthropic"],
wizard: {
choiceId: "apiKey",
choiceLabel: "Anthropic API key",
groupId: "anthropic",
groupLabel: "Anthropic",
groupHint: "Claude CLI + API key"
}
})
],
catalog: {
order: "simple",
run: async (ctx) => restoreUnpublishedAnthropicModels(await buildOpenAICompatibleProviderCatalog({
ctx,
providerId,
buildProvider: buildAnthropicCatalogProvider,
modelDiscovery: {
endpointPath: "v1/models",
buildRequestHeaders: ({ apiKey, discoveryApiKey }) => ({
"anthropic-version": "2023-06-01",
...buildAnthropicDiscoveryAuthHeaders(discoveryApiKey ?? apiKey)
}),
acceptUnknownModel: acceptsAnthropicLiveModelContract
}
}))
},
staticCatalog: {
order: "simple",
run: async () => ({ provider: buildAnthropicCatalogProvider() })
},
normalizeConfig: ({ provider, providerConfig }) => normalizeAnthropicProviderConfigForProvider({
provider,
providerConfig
}),
applyConfigDefaults: ({ config, env }) => applyAnthropicConfigDefaults({
config,
env
}),
resolveDynamicModel: (ctx) => {
const model = resolveAnthropicForwardCompatModel(ctx);
if (!model) return;
return normalizeAnthropicResolvedModel({
config: ctx.config,
provider: ctx.provider,
modelId: ctx.modelId,
model
}) ?? model;
},
normalizeResolvedModel: (ctx) => normalizeAnthropicResolvedModel(ctx),
prepareSyntheticAuth: ({ config, provider, env, signal }) => prepareClaudeCliSyntheticAuth(normalizeLowercaseStringOrEmpty(provider) === "claude-cli" ? config : void 0, {
env,
signal
}),
...buildProviderReplayFamilyHooks({ family: "native-anthropic-by-model" }),
isModernModelRef: ({ provider, modelId }) => matchesAnthropicModernModel(modelId) && (!isAnthropicMandatoryClaude5Model(modelId) || normalizeLowercaseStringOrEmpty(provider) === PROVIDER_ID),
resolveReasoningOutputMode: () => "native",
classifyFailoverReason: ({ code, errorType }) => classifyAnthropicFailoverDescriptor(errorType) ?? classifyAnthropicFailoverDescriptor(code),
resolveThinkingProfile: ({ provider, modelId, params }) => {
const contractModelId = resolveClaudeModelIdentity({
id: modelId,
params
});
return isAnthropicMythos5Model(contractModelId) && normalizeLowercaseStringOrEmpty(provider) !== PROVIDER_ID ? CLAUDE_CLI_OFF_THINKING_PROFILE : resolveClaudeThinkingProfile(contractModelId, void 0, { includeNativeMax: [PROVIDER_ID, CLAUDE_CLI_BACKEND_ID].includes(normalizeLowercaseStringOrEmpty(provider)) });
},
wrapStreamFn: wrapAnthropicProviderStream,
resolveUsageAuth: resolveAnthropicUsageAuth,
fetchUsageSnapshot: fetchAnthropicUsage,
isCacheTtlEligible: () => true,
buildAuthDoctorHint: async (ctx) => (await loadAuthRuntime()).buildAnthropicAuthDoctorHint({
config: ctx.config,
store: ctx.store,
profileId: ctx.profileId
})
};
}
/** Register Anthropic provider, Claude CLI backend, and media understanding provider. */
function registerAnthropicPlugin(api) {
let supportsDynamicSystemPromptSections = false;
const ensureDynamicSystemPromptSectionsSupport = createLazyRuntimeModule(async () => {
try {
const result = await api.runtime.system.runCommandWithTimeout(["claude", "--version"], {
timeoutMs: 1500,
killProcessTree: true,
maxOutputBytes: {
stdout: 1024,
stderr: 1024
}
});
supportsDynamicSystemPromptSections = result?.code === 0 && supportsClaudeDynamicSystemPromptSections(result.stdout);
} catch {
supportsDynamicSystemPromptSections = false;
}
});
api.registerCliBackend(buildAnthropicCliBackend({
ensureDynamicSystemPromptSectionsSupport,
supportsDynamicSystemPromptSections: () => supportsDynamicSystemPromptSections
}));
api.registerProvider(buildAnthropicProvider());
api.registerMediaUnderstandingProvider(anthropicMediaUnderstandingProvider);
registerClaudeSessionDiscovery(api);
for (const policy of createClaudeSessionNodeInvokePolicies()) api.registerNodeInvokePolicy(policy);
}
//#endregion
export { registerAnthropicPlugin as n, buildAnthropicProvider as t };