Repository: vercel-labs/ai
File: packages/anthropic/src/anthropic-provider.ts (TypeScript)

Code before:

  // Load auth credentials at initialization time for early validation
  const rawAuthToken = loadOptionalSetting({
    settingValue: options.authToken,
    environmentVariableName: 'ANTHROPIC_AUTH_TOKEN',
  });
  const authToken =
    rawAuthToken && rawAuthToken.trim().length > 0
      ? rawAuthToken.trim()
      : undefined;

  const rawApiKey = loadOptionalSetting({
    settingValue: options.apiKey,
    environmentVariableName: 'ANTHROPIC_API_KEY',
  });
  const apiKey =
    rawApiKey && rawApiKey.trim().length > 0 ? rawApiKey.trim() : undefined;

  // Validate that both are not provided simultaneously
  if (authToken && apiKey) {
    throw new InvalidArgumentError({
      argument: 'apiKey/authToken',
      message:
        'Both apiKey and authToken were provided. Please use only one authentication method.',
    });
  }

  const getHeaders = () => {
    const authHeaders: Record<string, string> = authToken
      ? { Authorization: `Bearer ${authToken}` }
      : {
          'x-api-key':
            apiKey ??
            loadApiKey({
              apiKey: undefined,
              environmentVariableName: 'ANTHROPIC_API_KEY',
              description: 'Anthropic',
            }),
        };

    return withUserAgentSuffix(
      {
        'anthropic-version': '2023-06-01',
        ...authHeaders,
        ...options.headers,
      },
      `ai-sdk/anthropic/${VERSION}`,
    );
  };

  const createChatModel = (modelId: AnthropicMessagesModelId) =>

Review comment (security):
this check leads to an error if the apiKey and authToken are defined in the .env file (and not the actual client file)

one can have both apiKey and authToken in the .env file and still only use one

this error should only pop up if the user passed both while initialising the provider

Code after:

  // Only error if both are explicitly provided in options
  if (options.apiKey && options.authToken) {
    throw new InvalidArgumentError({
      argument: 'apiKey/authToken',
      message:
        'Both apiKey and authToken were provided. Please use only one authentication method.',
    });
  }

  const getHeaders = () => {
    const authHeaders: Record<string, string> = options.authToken
      ? { Authorization: `Bearer ${options.authToken}` }
      : {
          'x-api-key': loadApiKey({
            apiKey: options.apiKey,
            environmentVariableName: 'ANTHROPIC_API_KEY',
            description: 'Anthropic',
          }),
        };

    return withUserAgentSuffix(
      {
        'anthropic-version': '2023-06-01',
        ...authHeaders,
        ...options.headers,
      },
      `ai-sdk/anthropic/${VERSION}`,
    );
  };

  const createChatModel = (modelId: AnthropicMessagesModelId) =>
    new AnthropicMessagesLanguageModel(modelId, {
      provider: providerName,
      baseURL,
      headers: getHeaders,
      fetch: options.fetch,
      generateId: options.generateId ?? generateId,
      supportedUrls: () => ({
        'image/*': [/^https?:\/\/.*$/],
        'application/pdf': [/^https?:\/\/.*$/],
      }),
    });

  const provider = function (modelId: AnthropicMessagesModelId) {
    if (new.target) {
      throw new Error(
        'The Anthropic model function cannot be called with the new keyword.',
      );
    }