feat: support using the action with Azure-hosted OpenAI models (#47)
This PR introduces a new, optional input to the GitHub Action,
`responses-api-endpoint`, which makes it possible to use this Action
with Azure. As explained in the updated `README.md`, if
`responses-api-endpoint` is specified, it will be the URL that Codex
hits to make Responses API requests. In practice, we expect this to be
used mostly by Azure users.
With the Azure account I just created, I got this working with the
following configuration:
```yaml
jobs:
codex:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Start Codex proxy
uses: openai/codex-action@71690bb0c5
with:
openai-api-key: ${{ secrets.AZURE_OPENAI_API_KEY }}
responses-api-endpoint: "https://bolinfest-7804-resource.cognitiveservices.azure.com/openai/v1/responses"
```
Under the hood, if `responses-api-endpoint` is non-empty, it simply
becomes the `--upstream-url` argument to `codex-responses-api-proxy`.
TO DISCUSS: Better/shorter name than `responses-api-endpoint`?
This PR builds on the work of https://github.com/openai/codex/pull/6129.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
Run [Codex](https://github.com/openai/codex#codex-exec) from a GitHub Actions workflow while keeping tight control over the privileges available to Codex. This action handles installing the Codex CLI and configuring it with a secure proxy to the [Responses API](https://platform.openai.com/docs/api-reference/responses).
|
||||
|
||||
Users must provide their [`OPENAI_API_KEY`](https://platform.openai.com/api-keys) as a [GitHub Actions secret](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets) to use this action.
|
||||
Users must provide an API key for their chosen provider (for example, [`OPENAI_API_KEY`](https://platform.openai.com/api-keys) or `AZURE_OPENAI_API_KEY` [if using Azure for OpenAI models](#azure)) as a [GitHub Actions secret](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets) to use this action.
|
||||
|
||||
## Example: Create Your Own Pull Request Bot
|
||||
|
||||
@@ -90,25 +90,26 @@ jobs:
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Default |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| `openai-api-key` | Secret used to start the Responses API proxy. Required when starting the proxy (key-only or key+prompt). Store it in `secrets`. | `""` |
|
||||
| `prompt` | Inline prompt text. Provide this or `prompt-file`. | `""` |
|
||||
| `prompt-file` | Path (relative to the repository root) of a file that contains the prompt. Provide this or `prompt`. | `""` |
|
||||
| `output-file` | File where the final Codex message is written. Leave empty to skip writing a file. | `""` |
|
||||
| `working-directory` | Directory passed to `codex exec --cd`. Defaults to the repository root. | `""` |
|
||||
| `sandbox` | Sandbox mode for Codex. One of `workspace-write` (default), `read-only` or `danger-full-access`. | `""` |
|
||||
| `codex-version` | Version of `@openai/codex` to install. | `""` |
|
||||
| `codex-args` | Extra arguments forwarded to `codex exec`. Accepts JSON arrays (`["--flag", "value"]`) or shell-style strings. | `""` |
|
||||
| `output-schema` | Inline schema contents written to a temp file and passed to `codex exec --output-schema`. Mutually exclusive with `output-schema-file`. | `""` |
|
||||
| `output-schema-file` | Schema file forwarded to `codex exec --output-schema`. Leave empty to skip passing the option. | `""` |
|
||||
| `model` | Model the agent should use. Leave empty to let Codex pick its default. | `""` |
|
||||
| `effort` | Reasoning effort the agent should use. Leave empty to let Codex pick its default. | `""` |
|
||||
| `codex-home` | Directory to use as the Codex CLI home (config/cache). Uses the CLI default when empty. | `""` |
|
||||
| `safety-strategy` | Controls how the action restricts Codex privileges. See [Safety strategy](#safety-strategy). | `drop-sudo` |
|
||||
| `codex-user` | Username to run Codex as when `safety-strategy` is `unprivileged-user`. | `""` |
|
||||
| `allow-users` | List of GitHub usernames who can trigger the action in addition to those who have write access to the repo. | "" |
|
||||
| `allow-bots` | Allow runs triggered by GitHub Apps/bot accounts to bypass the write-access check. | "false" |
|
||||
| Name | Description | Default |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| `openai-api-key` | Secret used to start the Responses API proxy when you are using OpenAI (default). Store it in `secrets`. | `""` |
|
||||
| `responses-api-endpoint` | Optional Responses API endpoint override, e.g. `https://example.openai.azure.com/openai/v1/responses`. Leave empty to use the proxy's default. | `""` |
|
||||
| `prompt` | Inline prompt text. Provide this or `prompt-file`. | `""` |
|
||||
| `prompt-file` | Path (relative to the repository root) of a file that contains the prompt. Provide this or `prompt`. | `""` |
|
||||
| `output-file` | File where the final Codex message is written. Leave empty to skip writing a file. | `""` |
|
||||
| `working-directory` | Directory passed to `codex exec --cd`. Defaults to the repository root. | `""` |
|
||||
| `sandbox` | Sandbox mode for Codex. One of `workspace-write` (default), `read-only` or `danger-full-access`. | `""` |
|
||||
| `codex-version` | Version of `@openai/codex` to install. | `""` |
|
||||
| `codex-args` | Extra arguments forwarded to `codex exec`. Accepts JSON arrays (`["--flag", "value"]`) or shell-style strings. | `""` |
|
||||
| `output-schema` | Inline schema contents written to a temp file and passed to `codex exec --output-schema`. Mutually exclusive with `output-schema-file`. | `""` |
|
||||
| `output-schema-file` | Schema file forwarded to `codex exec --output-schema`. Leave empty to skip passing the option. | `""` |
|
||||
| `model` | Model the agent should use. Leave empty to let Codex pick its default. | `""` |
|
||||
| `effort` | Reasoning effort the agent should use. Leave empty to let Codex pick its default. | `""` |
|
||||
| `codex-home` | Directory to use as the Codex CLI home (config/cache). Uses the CLI default when empty. | `""` |
|
||||
| `safety-strategy` | Controls how the action restricts Codex privileges. See [Safety strategy](#safety-strategy). | `drop-sudo` |
|
||||
| `codex-user` | Username to run Codex as when `safety-strategy` is `unprivileged-user`. | `""` |
|
||||
| `allow-users` | List of GitHub usernames who can trigger the action in addition to those who have write access to the repo. | `""` |
|
||||
| `allow-bots` | Allow runs triggered by GitHub Apps/bot accounts to bypass the write-access check. | `false` |
|
||||
|
||||
## Safety Strategy
|
||||
|
||||
@@ -145,10 +146,29 @@ jobs:
|
||||
## Additional tips
|
||||
|
||||
- Run this action after `actions/checkout@v5` so Codex has access to your repository contents.
|
||||
- To use a non-default Responses endpoint (for example Azure OpenAI), set `responses-api-endpoint` to the provider's URL while keeping `openai-api-key` populated; the proxy will still send `Authorization: Bearer <key>` upstream.
|
||||
- If you want Codex to have access to a narrow set of privileged functionality, consider running a local MCP server that can perform these actions and configure Codex to use it.
|
||||
- If you need more control over the CLI invocation, pass flags through `codex-args` or create a `config.toml` in `codex-home`.
|
||||
- Once `openai/codex-action` is run once with `openai-api-key`, you can also call `codex` from subsequent scripts in your job. (You can omit `prompt` and `prompt-file` from the action in this case.)
|
||||
|
||||
## Azure
|
||||
|
||||
To configure the Action to use OpenAI models hosted on Azure, pay close attention to the following:
|
||||
|
||||
- The `responses-api-endpoint` must be set to the full URL (including any required query parameters) that Codex will `POST` to for a Responses API request. For Azure, this might look like `https://YOUR_PROJECT_NAME.openai.azure.com/openai/v1/responses`. Note that [unlike when customizing a model provider in Codex](https://github.com/openai/codex/blob/main/docs/config.md#azure-model-provider-example), you must include the `v1/responses` suffix to the URL yourself, if appropriate.
|
||||
- The `openai-api-key` input must be a valid key that can be used with the `Authorization: Bearer <KEY>` header when making a `POST` request to your Responses API endpoint. (This is also true for the value of the [`env_key`](https://github.com/openai/codex/blob/main/docs/config.md#azure-model-provider-example) when setting a custom provider using the Codex CLI.)
|
||||
|
||||
Ultimately, your configured Action might look something like the following:
|
||||
|
||||
```yaml
|
||||
- name: Start Codex proxy
|
||||
uses: openai/codex-action@v1
|
||||
with:
|
||||
openai-api-key: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||
responses-api-endpoint: "https://bolinfest-7804-resource.cognitiveservices.azure.com/openai/v1/responses"
|
||||
prompt: "Debug all the things."
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [Apache License 2.0](./LICENSE).
|
||||
|
||||
+21
-5
@@ -18,6 +18,10 @@ inputs:
|
||||
description: "OpenAI API key used by Codex."
|
||||
required: false
|
||||
default: ""
|
||||
responses-api-endpoint:
|
||||
description: "Optional Responses API endpoint override, e.g. https://example.openai.azure.com/openai/v1/responses. Defaults to the proxy's built-in endpoint when empty."
|
||||
required: false
|
||||
default: ""
|
||||
working-directory:
|
||||
description: "Working directory that Codex should use. Defaults to the repository root."
|
||||
required: false
|
||||
@@ -165,17 +169,29 @@ runs:
|
||||
fi
|
||||
|
||||
# This is its own step to minimize the runtime logic that has access to the
|
||||
# API key. Note we use `env -u OPENAI_API_KEY` to ensure extra copies of the
|
||||
# key do not end up in the memory of the `codex-responses-api-proxy` process
|
||||
# where environment variables are stored.
|
||||
# API key. Note we use `env -u PROXY_API_KEY` to ensure extra copies of the
|
||||
# key do not end up in the memory of the `codex-responses-api-proxy`
|
||||
# process where environment variables are stored.
|
||||
- name: Start Responses API proxy
|
||||
if: ${{ inputs['openai-api-key'] != '' && steps.start_proxy.outputs.server_info_file_exists == 'false' }}
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ inputs['openai-api-key'] }}
|
||||
PROXY_API_KEY: ${{ inputs['openai-api-key'] }}
|
||||
shell: bash
|
||||
run: |
|
||||
upstream_url="${{ inputs['responses-api-endpoint'] }}"
|
||||
|
||||
args=(
|
||||
codex-responses-api-proxy
|
||||
--http-shutdown
|
||||
--server-info "${{ steps.derive_server_info.outputs.server_info_file }}"
|
||||
)
|
||||
|
||||
if [ -n "$upstream_url" ]; then
|
||||
args+=(--upstream-url "$upstream_url")
|
||||
fi
|
||||
|
||||
(
|
||||
printenv OPENAI_API_KEY | env -u OPENAI_API_KEY codex-responses-api-proxy --http-shutdown --server-info "${{ steps.derive_server_info.outputs.server_info_file }}"
|
||||
printenv PROXY_API_KEY | env -u PROXY_API_KEY "${args[@]}"
|
||||
) &
|
||||
|
||||
- name: Wait for Responses API proxy
|
||||
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ import * as os from "node:os";
|
||||
import { SafetyStrategy } from "./runCodexExec";
|
||||
import { checkOutput } from "./checkOutput";
|
||||
|
||||
const MODEL_PROVIDER = "openai-proxy";
|
||||
const MODEL_PROVIDER = "codex-action-responses-proxy";
|
||||
|
||||
export async function writeProxyConfig(
|
||||
codexHome: string,
|
||||
@@ -29,7 +29,7 @@ model_provider = "${MODEL_PROVIDER}"
|
||||
|
||||
# Added by codex-action.
|
||||
[model_providers.${MODEL_PROVIDER}]
|
||||
name = "OpenAI Proxy"
|
||||
name = "Codex Action Responses Proxy"
|
||||
base_url = "http://127.0.0.1:${port}/v1"
|
||||
wire_api = "responses"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user