Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,49 @@ rotation, build and atomically swap in new `OpenAI::NetHTTPClient` and
in-flight work finishes. See the complete [custom HTTP client mTLS
example](examples/mtls_custom_http_client.rb).

## Microsoft Azure OpenAI

Use the standard client with the Azure provider to call model deployments through
the Azure OpenAI v1 API. The provider accepts an Azure resource endpoint and
adds `/openai/v1` when needed:

```ruby
require "openai"

client = OpenAI::Client.new(
provider: OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
)
)

response = client.responses.create(
model: ENV.fetch("AZURE_OPENAI_DEPLOYMENT"),
input: "Say hello!"
)

puts(response.output_text)
```

Omit `endpoint` and `api_key` to use `AZURE_OPENAI_ENDPOINT` and
`AZURE_OPENAI_API_KEY`. For Microsoft Entra authentication, pass a callable
that returns a current bearer token. The provider invokes it before every
request attempt, including retries:

```ruby
client = OpenAI::Client.new(
provider: OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
token_provider: -> { fetch_azure_openai_token }
)
)
```

This integration targets the Azure OpenAI v1 API. It does not add dated
`api-version` query parameters or rewrite requests to legacy
`/deployments/{deployment}` paths. See [azure.md](azure.md) for configuration,
authentication precedence, and endpoint security details.

## Amazon Bedrock

Use the standard client with the Bedrock provider to call OpenAI models through Amazon Bedrock's OpenAI-compatible API. Add `aws-sdk-core` to your application for AWS credential discovery and SigV4 signing:
Expand Down
110 changes: 110 additions & 0 deletions azure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Microsoft Azure OpenAI

Configure the standard `OpenAI::Client` with the Azure provider to use the
[Azure OpenAI v1 API](https://learn.microsoft.com/azure/foundry/openai/api-version-lifecycle):

```ruby
require "openai"

client = OpenAI::Client.new(
provider: OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
)
)

response = client.responses.create(
model: ENV.fetch("AZURE_OPENAI_DEPLOYMENT"),
input: "Say hello!"
)

puts(response.output_text)
```

The `model` parameter is the Azure model deployment name. The provider exposes
the normal Ruby SDK resources, request and response models, retries, pagination,
streaming helpers, and custom HTTP transport. Azure controls which resources and
features are available for a deployment; unsupported calls surface as normal API
errors.

## Endpoint configuration

Pass the Azure resource endpoint or set `AZURE_OPENAI_ENDPOINT`:

```ruby
provider = OpenAI::Providers.azure(
endpoint: "https://my-resource.openai.azure.com",
api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
)
```

The provider appends `/openai/v1` when it is absent. These values therefore
configure the same base URL:

```text
https://my-resource.openai.azure.com
https://my-resource.openai.azure.com/openai
https://my-resource.openai.azure.com/openai/v1/
```

The endpoint must be an absolute HTTP or HTTPS URL without user information, a
query string, or a fragment. Use HTTPS outside local testing. A path prefix is
preserved for gateways and private routing, for example
`https://gateway.example.com/azure` becomes
`https://gateway.example.com/azure/openai/v1`.

## Authentication

Configure exactly one authentication mode explicitly. If neither is explicit,
the provider uses `AZURE_OPENAI_API_KEY`.

### Azure API key

Pass `api_key` or set `AZURE_OPENAI_API_KEY`. The provider sends it in Azure's
`api-key` header:

```ruby
provider = OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
)
```

Passing `api_key: nil` explicitly skips the environment fallback.

### Microsoft Entra bearer token

Pass a callable that returns a current access token for Azure OpenAI. Credential
acquisition stays with the application, so the SDK does not require an Azure
identity package:

```ruby
provider = OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
token_provider: -> {
credential.get_token("https://cognitiveservices.azure.com/.default").token
}
)
```

An explicit `token_provider` takes precedence over an ambient
`AZURE_OPENAI_API_KEY`. It is invoked immediately before every request attempt,
including API retries, so applications can refresh short-lived tokens without
rebuilding the client.

## Security

The provider validates the request origin before attaching an API key or bearer
token. It refuses to authenticate redirects or custom requests whose origin
differs from the configured Azure endpoint. Custom `Authorization` and `api-key`
headers cannot be combined with provider-owned authentication.

Keep credentials out of source control and logs. Prefer short-lived Microsoft
Entra tokens to long-lived API keys for production workloads.

## Dated Azure APIs

This provider targets the GA Azure OpenAI v1 API. It does not support dated API
versions such as `2025-04-01-preview`, inject `api-version` query parameters, or
rewrite generated resource paths to `/deployments/{deployment}`. Use the v1 API
for new integrations.
39 changes: 10 additions & 29 deletions examples/azure_openai.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,16 @@

require_relative "../lib/openai"

# Set environment variables
# - `OPENAI_API_KEY` to your Azure OpenAI API key
# - `OPENAI_BASE_URL` to `https://{resource}.openai.azure.com/openai/v1/`
client = OpenAI::Client.new

# Chat Completion
chat_completion = client.chat.completions.create(
messages: [
{
role: "user",
content: "Tell me a joke."
}
],
model: :"gpt-4o",
request_options: {
extra_query: {"api-version": "preview"}
}
client = OpenAI::Client.new(
provider: OpenAI::Providers.azure(
endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
)
)
pp(chat_completion)

# Image Generation
image_response = client.images.generate(
model: "dall-e-3",
size: "1024x1024",
# quality: "medium",
n: 1,
prompt: "An astronaut lounging in a tropical resort in space, pixel art",
request_options: {
extra_query: {"api-version": "preview"}
}
response = client.responses.create(
model: ENV.fetch("AZURE_OPENAI_DEPLOYMENT"),
input: "Say hello!"
)
pp(image_response)

pp(response)
1 change: 1 addition & 0 deletions lib/openai.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
require_relative "openai/net_http_client"
require_relative "openai/provider"
require_relative "openai/internal/provider"
require_relative "openai/providers/azure"
require_relative "openai/providers/bedrock"
require_relative "openai/internal/transport/base_client"
require_relative "openai/client"
Expand Down
Loading