| Title: | 'ChatGPT' Plan Provider for 'ellmer' |
| Version: | 0.2.0 |
| URL: | https://github.com/simxnherrera/ellmercodex |
| BugReports: | https://github.com/simxnherrera/ellmercodex/issues |
| Description: | Connects 'ellmer' chats to a 'ChatGPT' subscription through 'OpenAI”s documented "Sign in with ChatGPT" flow for open-source, locally hosted apps https://developers.openai.com/siwc/token-sharing-open-source. Provides a stable, explicitly bounded core of the public 'ellmer' (>= 0.5.0) Chat object, including browser sign-in with dynamic client registration, package-scoped credential storage, redacted diagnostics, multi-turn text, streaming, structured-output, function-tool, asynchronous, cancellation, cloning, metadata, multimodal chat, account-specific model discovery, and reasoning-effort selection through the public 'Responses' API. Parallel and batch helper functions are explicitly unsupported because 'ChatGPT' plan usage is stream-only. This independent third-party integration is not endorsed by 'OpenAI'. |
| License: | MIT + file LICENSE |
| Depends: | R (≥ 4.1.0) |
| Encoding: | UTF-8 |
| Language: | en-US |
| Imports: | coro, ellmer (≥ 0.5.0), httr2 (≥ 1.3.0), httpuv, jose, jsonlite, openssl, promises, rlang, S7 |
| Suggests: | callr, knitr, later, pkgload, rmarkdown, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Config/roxygen2/version: | 8.1.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-06 18:23:14 UTC; simonherrera |
| Author: | Simon Herrera [aut, cre, cph] |
| Maintainer: | Simon Herrera <simxnherrera@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-16 12:40:16 UTC |
ellmercodex: ChatGPT plan provider for ellmer
Description
ellmercodex provides a stable, explicitly bounded core integration between
ellmer and a ChatGPT subscription. It uses
OpenAI's documented "Sign in with ChatGPT" flow for open-source, locally
hosted apps (https://developers.openai.com/siwc/token-sharing-open-source)
and the public Responses API. The stable compatibility target is the public
ellmer Chat (0.5.0 or later) object for interactive, single-conversation
operations. This package is independent and is not affiliated with or
endorsed by OpenAI.
Details
Authentication is never started as a package-loading side effect. Call
codex_login() explicitly before chat_codex() when no stored credential
is available. Examples and offline tests do not authenticate, open a
browser, read credentials, or make network requests.
The usual workflow is to check codex_available(), authenticate with
codex_login(), inspect the account with codex_account(), and then create
a chat with chat_codex(). codex_models() can be used after sign-in to
inspect the account-specific model catalog and its advertised reasoning
efforts. codex_logout() removes only the credential owned by this package.
The public API is deliberately small: codex_login(), codex_logout(),
codex_account(), codex_models(), codex_available(), and
chat_codex(). The chat compatibility layer is checked against the
required ellmer contracts at runtime and supports interactive Chat methods:
text and content streaming, model parameters, per-model reasoning effort,
structured output, multi-turn history, rich image/PDF content, asynchronous
chat, tool loops, callbacks, cancellation, cloning, echo, and response
metadata. Provider token counting and file management are unavailable.
The separately exported ellmer parallel/batch helpers are outside
the stable core contract and are explicitly blocked for the Codex stream-only
endpoint rather than silently degraded. ChatGPT plan usage also rejects some
Responses arguments, such as temperature and max_output_tokens; these
fail before a request is sent.
External service and compatibility
ChatGPT plan usage through "Sign in with ChatGPT" is a preview feature for open-source and locally hosted apps; paid or remotely hosted apps need OpenAI's approval. It requires an eligible ChatGPT plan and workspace, and its limits and supported features may change. The package does not claim affiliation with or endorsement by OpenAI.
Author(s)
Maintainer: Simon Herrera simxnherrera@gmail.com [copyright holder]
Authors:
Simon Herrera simxnherrera@gmail.com [copyright holder]
See Also
Useful links:
Report bugs at https://github.com/simxnherrera/ellmercodex/issues
Create a Codex chat backed by ellmer
Description
chat_codex() returns a normal ellmer Chat object configured for the
public Responses API with ChatGPT plan usage. It does not start browser
authentication. Call codex_login() explicitly first when no stored
credential is available; an existing credential is loaded and refreshed as
needed.
Usage
chat_codex(
system_prompt = NULL,
model = NULL,
echo = c("none", "output", "all"),
effort = NULL,
params = NULL,
api_args = list()
)
Arguments
system_prompt |
Optional system prompt passed to ellmer. |
model |
Optional Codex model name. If omitted, |
echo |
One of |
effort |
Optional Codex reasoning effort. It is forwarded through
ellmer's |
params |
Optional ellmer model parameters, usually created with
|
api_args |
Optional named list of additional Responses arguments passed
through ellmer on every request. This is an advanced escape hatch for
Responses arguments accepted with ChatGPT plan usage. Arguments the
documentation prohibits (such as |
Details
The returned chat is the public ellmer Chat object (0.5.0 or later) for
interactive, single-conversation operations, including ordinary and
structured chat, synchronous and asynchronous streaming, tool declarations
and multi-round execution, callbacks, cancellation, cloning, history, echo,
model/provider configuration, rich content, and response metadata.
Provider token counting and file management are unavailable with ChatGPT
plan usage and fail before making a request. The
compatibility layer uses one contract-checked provider/turn-submission seam
while leaving public Chat methods and ellmer lifecycle semantics intact.
The separate ellmer parallel/batch helpers are outside this stable core
contract. Parallel helpers use the package blocker, while batch helpers stop
in ellmer's generic unsupported-provider check because the Codex endpoint is
stream-only.
$chat_structured() intentionally follows ellmer's semantics and disables
registered tools for that request. Call $chat() first when tool-assisted
context is needed, then use $chat_structured() to extract structured data.
Value
An object inheriting from ellmer's Chat class.
The returned object retains ellmer's public Chat methods, history,
callbacks, registered tools, asynchronous methods, and R6 cloning behavior.
Conditions
Invalid arguments signal codex_chat_argument_error. Missing or
incompatible ellmer installations signal codex_ellmer_missing or
codex_ellmer_compatibility_error. Authentication failures found before
the Chat is constructed retain their package condition classes. Transport
and protocol errors retain their specific Codex/ellmer condition classes;
compatibility-shape failures use codex_ellmer_compatibility_error.
Side effects
Constructing a chat reads the current process credential or this package's
credential store and may refresh an expired stored credential. When model
is omitted, or when an effort is supplied, it also queries the authenticated
account catalog. It does not open a browser or generate a response.
See Also
codex_login(), codex_account(), codex_models(), codex_logout(),
and ellmer::chat_openai()
Examples
chat <- chat_codex(
system_prompt = "Be concise."
)
chat$chat("Hello")
weather_tool <- ellmer::tool(
function(city) paste("Sunny in", city),
name = "get_weather",
description = "Get the current weather for a city.",
arguments = list(city = ellmer::type_string())
)
chat$register_tool(weather_tool)
chat$chat("What is the weather in Montevideo?")
Show a redacted Codex authentication summary.
Description
The account identifier and all token material are deliberately replaced or omitted. Calling this function does not open a browser; an expired stored credential may be refreshed.
Usage
codex_account(auth = NULL)
Arguments
auth |
Optional in-memory credential. If omitted, the current process-local session and then the package's own credential store are checked. |
Value
A one-row data frame with columns:
authenticated |
Logical; whether a valid package credential was found. |
account |
Always |
expires_at |
The access-token expiry as a UTC |
Conditions
A malformed in-memory credential signals codex_auth_argument_error and a
malformed stored value signals codex_credential_store_error.
Examples
codex_account()
Check whether the local ellmercodex integration is available.
Description
This is an offline check. By default it verifies package dependencies and
static configuration only; it does not open a browser, make a request, or
inspect a credential store. Set check_credentials = TRUE when an explicit
credential-presence check is desired.
Usage
codex_available(check_credentials = FALSE)
Arguments
check_credentials |
Whether to inspect this package's own credential
backend. Defaults to |
Value
A single logical value. TRUE means that the required dependencies,
static configuration, and the supported ellmer compatibility seam are
available. With check_credentials = TRUE, it also requires a usable
package-owned credential to be present. FALSE does not identify a single
cause; use the package startup diagnostics or contact the package
maintainer with a sanitized reproducible report.
Note
The default check does not prove that the remote Codex service is reachable, that a model is available to the account, or that a request will succeed.
Examples
codex_available()
if (interactive()) codex_available(check_credentials = TRUE)
Check the exported ellmer compatibility seam
Description
The package requires ellmer 0.5.0 or later and checks the private contracts needed by the Codex streaming transport before constructing a chat.
Usage
codex_ellmer_compatibility()
Value
The installed ellmer version, invisibly.
Sign in with ChatGPT in the browser.
Description
codex_login() is the explicit authentication entry point. It follows
OpenAI's documented "Sign in with ChatGPT" flow for open-source, locally
hosted apps: it opens the system browser for registration and consent,
listens once on the loopback callback, exchanges the PKCE-protected code
for tokens with the issued client ID, verifies the ID token, and checks that
ChatGPT plan usage (chatgpt.tokens.use.direct) was granted.
Usage
codex_login(persist = TRUE, timeout = 300)
Arguments
persist |
Whether to save the credential for later sessions. The
default is |
timeout |
Maximum callback wait in seconds. This must be one positive
number. The loopback listener is closed when authentication succeeds,
fails, or times out. When |
Details
The first sign-in creates a registration bound to the selected ChatGPT
account and workspace. Later sign-ins reauthorize that registration. Use
codex_logout() first to sign in with a different account or workspace.
The package never reads credentials created by Codex CLI or another
application.
Credentials are stored in tools::R_user_dir("ellmercodex", "config"), or in the directory named by the ELLMERCODEX_HOME
environment variable. The same directory holds a stable, opaque host
identifier (ext_agent_host_id) that is created before the first
sign-in, even when persist = FALSE, because the flow requires it to be
stable for each host.
Value
An internal codex_auth object. Use codex_account() for a safe
account summary; token fields are intentionally not printed.
Conditions
Invalid arguments signal codex_auth_argument_error; callback and token
failures use codex_oauth_callback_error, codex_oauth_timeout, or
codex_token_exchange_error as appropriate. If ChatGPT plan usage was not
granted, codex_plan_scope_error is signaled.
Note
This function is interactive: it opens the default browser and
listens on http://127.0.0.1:1455/callback (set
ELLMERCODEX_CALLBACK_PORT to use another port).
Examples
auth <- codex_login()
codex_account(auth)
Sign out and remove ellmercodex's stored credential.
Description
This function revokes the refresh token with OpenAI (by default), clears the process-local session, and deletes this package's own credential file. It never removes Codex CLI credentials or another application's entries. The host identifier is kept because the documented flow requires it to stay stable for this host.
Usage
codex_logout(revoke = TRUE)
Arguments
revoke |
Whether to revoke the refresh token at OpenAI's documented
revocation endpoint before deleting it locally. Revocation is best effort:
local credentials are removed even when the network request fails, in
which case a |
Value
TRUE, invisibly. The process-local credential is cleared even if
no persistent credential exists.
Conditions
Logout signals no backend details. Storage failures are reported as
codex_credential_store_error by the explicit login and refresh paths that
write credentials.
Note
To use a different ChatGPT account or workspace, call
codex_logout() and then codex_login(); the next sign-in creates a new
registration instead of reauthorizing the previous one.
Examples
codex_logout()
List models available to the authenticated Codex account.
Description
This makes one authenticated request to OpenAI's documented model catalog
(GET https://api.openai.com/v1/models) with the ChatGPT plan access token,
and keeps the models marked for listing (visibility: "list"). The returned rows include each model's advertised reasoning effort
levels, so callers can select an effort without copying a stale catalog into
this package. Availability is account- and workspace-specific. The catalog
may lag behind models accepted by the chat service; explicitly supplied IDs
absent from the catalog are passed to the service for validation.
Usage
codex_models(auth = NULL, client_version = NULL)
Arguments
auth |
Optional package credential. If omitted, the current session or package-owned credential is loaded and refreshed as needed. |
client_version |
Deprecated and ignored. The documented catalog does not take a client version. Kept so existing calls keep working. |
Value
A codex_models data frame with one row per catalog model. Its
columns are:
id |
The model identifier accepted by chat_codex. |
owned_by |
The service or owner label advertised by the catalog. |
display_name |
A human-readable model name. |
description |
The catalog description, when supplied. |
default_reasoning_effort |
The advertised default effort. |
supported_reasoning_efforts |
A list-column of effort names. |
supported_in_api |
Whether the catalog marks the model as API-supported. |
priority |
The catalog priority, when supplied. |
default_service_tier |
The advertised default service tier. |
service_tiers |
A list-column of advertised service tiers. |
The supported and source attributes describe the catalog result.
Conditions
Missing credentials signal codex_auth_missing; HTTP and protocol failures
use the same sanitized transport conditions as generation requests.
Note
The catalog is account- and workspace-specific and is queried at call time. Cache or select a model explicitly if a reproducible workflow must not change when the account's catalog changes.
Examples
models <- codex_models()
models[c("id", "default_reasoning_effort", "supported_reasoning_efforts")]
ellmercodex condition classes
Description
ellmercodex signals structured conditions so callers can handle failures without parsing messages. Messages are sanitized and never intentionally include tokens, authorization codes, OAuth state, account identifiers, or credential-store contents.
Details
Authentication and credential conditions inherit from codex_auth_error.
The principal subclasses are codex_auth_missing,
codex_auth_argument_error, codex_oauth_argument_error,
codex_oauth_callback_error,
codex_oauth_timeout, codex_token_exchange_error,
codex_refresh_error, codex_account_error,
codex_credential_store_error, and codex_plan_scope_error (ChatGPT plan
usage, the chatgpt.tokens.use.direct scope, was not granted). Refresh
and token-exchange errors carry the OAuth error code in an oauth_error
field when the server returned one. codex_logout() signals the warning
codex_revocation_warning when remote revocation fails.
Transport and stream conditions are codex_request_error,
codex_authentication_error, codex_rate_limit_error,
codex_model_unavailable_error, codex_malformed_request_error,
codex_server_error, codex_network_error, codex_protocol_error,
codex_protocol_changed_error, codex_generation_error, and
codex_incomplete_error.
Documented ChatGPT plan usage error codes map to more specific subclasses
that keep the parents above, and carry the server's code and param
fields: codex_usage_limit_error (subscription_sharing_usage_limit_exceeded;
also a codex_rate_limit_error), codex_usage_unavailable_error
(subscription_sharing_usage_unavailable and
subscription_sharing_user_unavailable; also a codex_server_error),
codex_plan_ineligible_error (subscription_sharing_user_not_eligible;
also a codex_authentication_error), and
codex_unsupported_capability_error
(subscription_sharing_unsupported_capability; also a
codex_malformed_request_error).
ellmer integration conditions are codex_chat_argument_error,
codex_chat_error, codex_model_selection_error, codex_ellmer_missing, and
codex_ellmer_compatibility_error.
Handle these classes with condition handlers rather than matching their
messages. More specific subclasses can be handled before the common
codex_auth_error or codex_request_error parents.
Examples
error <- tryCatch(
codex_available(NA),
codex_auth_argument_error = identity
)
inherits(error, "codex_auth_error")