Module: OpenAI::Providers::Bedrock Private

Defined in:
lib/openai/providers/bedrock.rb

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Defined Under Namespace

Classes: BearerAuth, CustomCredentialsProvider, DefaultCredentialsProvider, Definition, ProfileCredentialsProvider, SigV4Auth

Constant Summary collapse

SERVICES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

{mantle: "bedrock-mantle", runtime: "bedrock"}.freeze
AWS_REGION_PATTERN =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

/\A[a-z]{2,8}(?:-[a-z0-9]+)+-\d+\z/
AUTH_HEADERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%w[authorization].freeze
SIGNING_HEADERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%w[authorization x-amz-content-sha256 x-amz-date x-amz-security-token].freeze
BEARER_AUTH_MARKER =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

:openai_bedrock_bearer
SIGV4_AUTH_MARKER =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

:openai_bedrock_sigv4
MISSING_REGION_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Bedrock requires an AWS region. Pass `region` to `bedrock(...)`, or set `AWS_REGION` " \
"or `AWS_DEFAULT_REGION`."
MISSING_CREDENTIALS_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Could not find credentials for Bedrock. Pass a bearer credential or AWS credentials " \
"to `bedrock(...)`, set `AWS_BEARER_TOKEN_BEDROCK`, or configure the default AWS credential chain."
CREDENTIAL_RESOLUTION_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Failed to resolve AWS credentials for Bedrock. Verify your AWS profile, environment " \
"variables, or runtime identity configuration and try again."
NON_REPLAYABLE_BODY_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Bedrock SigV4 authentication requires a replayable request body. Buffer the body " \
"before sending or use bearer authentication."
MISSING_DEPENDENCY_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Bedrock AWS authentication requires optional AWS dependencies. Add `gem \"aws-sdk-core\"` " \
"to your Gemfile, run `bundle install`, and try again."
PARTIAL_STATIC_CREDENTIALS_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Static AWS credentials require both `access_key_id` and `secret_access_key`. " \
"A `session_token` may only be used with both."
AMBIGUOUS_AWS_AUTH_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Bedrock authentication is ambiguous. Configure exactly one explicit AWS mode: " \
"static credentials, profile, or credential provider."
AMBIGUOUS_AUTH_MESSAGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"Bedrock authentication is ambiguous. Configure exactly one explicit mode: bearer " \
"credential, static AWS credentials, profile, or credential provider."

Class Method Summary collapse

Class Method Details

.load_aws!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



266
267
268
269
270
271
# File 'lib/openai/providers/bedrock.rb', line 266

def load_aws!
  require("aws-sdk-core")
  require("aws-sigv4")
rescue LoadError => e
  raise OpenAI::Errors::Error.new(MISSING_DEPENDENCY_MESSAGE), cause: e
end

.normalize_base_url(base_url) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/openai/providers/bedrock.rb', line 355

def normalize_base_url(base_url)
  uri = URI(base_url)
  unless uri.is_a?(URI::HTTP) && uri.host
    raise ArgumentError, "The Bedrock `base_url` must be an absolute HTTP or HTTPS URL."
  end
  uri.path = uri.path.sub(%r{/responses(?:/.*)?\z}, "")
  uri.path = "" if uri.path == "/"
  uri.to_s.sub(%r{/\z}, "")
rescue URI::InvalidURIError => e
  message = "The Bedrock `base_url` must be an absolute HTTP or HTTPS URL."
  raise ArgumentError.new(message), cause: e
end

.normalize_endpoint(endpoint) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


347
348
349
350
351
352
353
# File 'lib/openai/providers/bedrock.rb', line 347

def normalize_endpoint(endpoint)
  return nil if endpoint.nil?
  return endpoint.to_sym if endpoint == "mantle" || endpoint == "runtime"
  return endpoint if endpoint == :mantle || endpoint == :runtime

  raise ArgumentError, "The Bedrock `endpoint` must be either `mantle` or `runtime`."
end

.normalize_optional_string(value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



427
428
429
430
431
432
# File 'lib/openai/providers/bedrock.rb', line 427

def normalize_optional_string(value)
  return nil if value.nil?
  return nil unless value.is_a?(String)
  normalized = value.strip
  normalized unless normalized.empty?
end

.parse_endpoint_hostname(hostname) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/openai/providers/bedrock.rb', line 304

def parse_endpoint_hostname(hostname)
  service, region, *suffix_parts = hostname.delete_suffix(".").downcase.split(".")
  suffix = suffix_parts.join(".")

  if service == "bedrock-mantle" && region&.match?(/\A[a-z0-9-]+\z/) && suffix == "api.aws"
    return {endpoint: :mantle, region: region}
  end

  if %w[bedrock-runtime bedrock-runtime-fips].include?(service) && region &&
     runtime_dns_suffixes(region).include?(suffix)
    return {endpoint: :runtime, region: region}
  end

  nil
end

.profile_region(profile) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



368
369
370
371
372
373
374
# File 'lib/openai/providers/bedrock.rb', line 368

def profile_region(profile)
  configured_profile = profile || ENV["AWS_PROFILE"] || ENV["AWS_DEFAULT_PROFILE"] || "default"
  region = Aws.shared_config.region(profile: configured_profile)
  normalize_optional_string(region)
rescue StandardError => e
  raise OpenAI::Errors::Error.new(CREDENTIAL_RESOLUTION_MESSAGE), cause: e
end

.provider_headers(request, marker:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



376
377
378
379
380
381
382
383
384
385
# File 'lib/openai/providers/bedrock.rb', line 376

def provider_headers(request, marker:)
  headers = request.fetch(:headers).dup
  if request[:provider_auth] == marker
    headers.delete("authorization")
  elsif headers.key?("authorization")
    raise OpenAI::Errors::Error,
          "Bedrock provider authentication cannot be combined with a custom `Authorization` header."
  end
  headers
end

.resolve_base_url(base_url, region, endpoint:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


273
274
275
276
277
278
279
280
281
282
283
# File 'lib/openai/providers/bedrock.rb', line 273

def resolve_base_url(base_url, region, endpoint:)
  return base_url if base_url
  raise ArgumentError, MISSING_REGION_MESSAGE if region.nil?

  if endpoint == :runtime
    suffix, = runtime_dns_suffixes(region)
    "https://bedrock-runtime.#{region}.#{suffix}/openai/v1"
  else
    "https://bedrock-mantle.#{region}.api.aws/v1"
  end
end

.runtime_dns_suffixes(region) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/openai/providers/bedrock.rb', line 285

def runtime_dns_suffixes(region)
  case region
  when /\Acn-/
    ["amazonaws.com.cn", "api.amazonwebservices.com.cn"]
  when /\Aeusc-/
    ["amazonaws.eu", "api.amazonwebservices.eu"]
  when /\Aus-iso-/
    ["c2s.ic.gov", "api.aws.ic.gov"]
  when /\Aus-isob-/
    ["sc2s.sgov.gov", "api.aws.scloud"]
  when /\Aeu-isoe-/
    ["cloud.adc-e.uk", "api.cloud-aws.adc-e.uk"]
  when /\Aus-isof-/
    ["csp.hci.ic.gov", "api.aws.hci.ic.gov"]
  else
    ["amazonaws.com", "api.aws"]
  end
end

.validate_canonical_endpoint!(base_url, endpoint, region) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/openai/providers/bedrock.rb', line 320

def validate_canonical_endpoint!(base_url, endpoint, region)
  uri = URI(base_url)
  canonical = parse_endpoint_hostname(uri.host)
  return unless canonical

  unless uri.is_a?(URI::HTTPS)
    raise ArgumentError, "Canonical Amazon Bedrock endpoints require HTTPS."
  end
  if canonical.fetch(:endpoint) != endpoint
    raise ArgumentError,
          "The Bedrock #{canonical.fetch(:endpoint)} hostname does not match the " \
          "selected `#{endpoint}` endpoint."
  end
  return if region.nil? || canonical.fetch(:region) == region

  raise ArgumentError,
        "The Bedrock endpoint region `#{canonical.fetch(:region)}` does not match the " \
        "configured AWS region `#{region}`."
end

.validate_credentials!(credentials) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



415
416
417
418
419
420
421
422
423
424
425
# File 'lib/openai/providers/bedrock.rb', line 415

def validate_credentials!(credentials)
  access_key_id = credentials&.access_key_id
  secret_access_key = credentials&.secret_access_key
  session_token = credentials&.session_token if credentials.respond_to?(:session_token)
  valid =
    access_key_id.is_a?(String) && !access_key_id.strip.empty? &&
    secret_access_key.is_a?(String) && !secret_access_key.strip.empty? &&
    (session_token.nil? || (session_token.is_a?(String) && !session_token.strip.empty?))
  return credentials if valid
  raise OpenAI::Errors::Error, CREDENTIAL_RESOLUTION_MESSAGE
end

.validate_endpoint_region!(url, region, endpoint:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/openai/providers/bedrock.rb', line 396

def validate_endpoint_region!(url, region, endpoint:)
  canonical = parse_endpoint_hostname(url.host)
  return unless canonical

  if canonical.fetch(:endpoint) != endpoint
    raise OpenAI::Errors::Error,
          "The Bedrock #{canonical.fetch(:endpoint)} hostname does not match the " \
          "selected `#{endpoint}` endpoint."
  end

  endpoint_region = canonical.fetch(:region)
  return if endpoint_region == region
  message =
    "The Bedrock endpoint region `#{endpoint_region}` does not match the SigV4 " \
    "region `#{region}`."
  raise OpenAI::Errors::Error,
        message
end

.validate_origin!(url, base_url, action:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



387
388
389
390
391
392
393
394
# File 'lib/openai/providers/bedrock.rb', line 387

def validate_origin!(url, base_url, action:)
  return if OpenAI::Internal::Util.uri_origin(url) == OpenAI::Internal::Util.uri_origin(base_url)
  message =
    "Refusing to #{action} a Bedrock request for an origin other than the configured " \
    "provider URL."
  raise OpenAI::Errors::Error,
        message
end

.validate_region!(region) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


340
341
342
343
344
345
# File 'lib/openai/providers/bedrock.rb', line 340

def validate_region!(region)
  return if AWS_REGION_PATTERN.match?(region)

  raise ArgumentError,
        "The Bedrock AWS `region` is invalid. Use a standard AWS region such as `us-east-1`."
end