Skip to content

feat: support OpenAI Codex auth and reasoning effort in agent settings#1921

Merged
yottahmd merged 6 commits intomainfrom
openai-codex
Apr 1, 2026
Merged

feat: support OpenAI Codex auth and reasoning effort in agent settings#1921
yottahmd merged 6 commits intomainfrom
openai-codex

Conversation

@yottahmd
Copy link
Copy Markdown
Collaborator

@yottahmd yottahmd commented Apr 1, 2026

Summary

  • add OpenAI Codex subscription auth and provider support to agent settings and setup
  • add model-level reasoning effort support in the agent settings Web UI and thread it into agent runtime requests
  • refresh the built-in OpenAI and OpenAI Codex presets to the current GPT-5.4 family

Testing

  • make api
  • pnpm gen:api
  • pnpm build
  • go test ./internal/agent ./internal/llm/...
  • go test ./internal/agent -run 'TestAPI_(CreateSession_AppliesModelThinkingEffort|SendMessage_UpdatesThinkingEffort|CreateSession_OmitsThinkingWhenNoEffortConfigured)$' -count=1
  • go test ./internal/service/frontend/api/v1 -run 'Test(CreateAgentModel|UpdateAgentModel|ListModelPresets|ApplyModelUpdates|SetDefaultAgentModel|ListAgentModels)$' -count=1
  • go test ./internal/service/frontend/api/v1 -run '^$' -count=1

Summary by CodeRabbit

  • New Features

    • Added OAuth-based subscription authentication for OpenAI Codex provider with admin credential management endpoints
    • Added configurable reasoning effort levels for models that support this capability
    • New admin endpoints to manage provider authentication (list, login, logout, complete login flow)
  • Updates

    • Updated OpenAI model presets with latest model versions
    • Added OpenAI Codex as a selectable provider option in model configuration

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 1, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 058a37f6-ad39-4d82-8fbd-ef1949b47288

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added OAuth authentication support for agent providers (specifically OpenAI Codex subscription) with a new OAuth manager package handling login flows, credential storage, and validation. Extended LLM request configuration with optional "thinking effort" (reasoning) propagation through agent sessions and loops. Implemented file-based encrypted credential persistence and new frontend API endpoints for provider connection management.

Changes

Cohort / File(s) Summary
OpenAPI Specification
api/v1/api.yaml
Added three new admin-only agent OAuth management endpoints (/settings/agent/auth/providers) and their request/response schemas. Extended model configuration schemas with optional thinkingEffort and introduced openai-codex as a new provider type.
OAuth Core Infrastructure
internal/agentoauth/types.go, internal/agentoauth/manager.go, internal/agentoauth/manager_test.go
Established OAuth credential types, interfaces, and error sentinels. Implemented Manager with login/logout/status/refresh flows, concurrent refresh locking, and in-memory flow tracking with TTL expiration.
OpenAI Codex Provider
internal/agentoauth/openai_codex.go, internal/agentoauth/openai_codex_test.go
Implemented OAuth provider for OpenAI Codex with PKCE-based auth flow, token exchange, JWT-based account ID extraction, and refresh token support.
OAuth Credential Persistence
internal/persis/fileagentoauth/store.go, internal/persis/fileagentoauth/store_test.go
File-backed encrypted credential store with CRUD operations, atomic writes, permission enforcement, and error-tolerant directory scanning.
Agent API & Session Thinking Effort
internal/agent/api.go, internal/agent/api_test.go, internal/agent/model_config.go, internal/agent/loop.go, internal/agent/session.go
Propagated thinking effort from model configuration through session manager and loop, conditionally including Thinking field in LLM requests. Added OAuth dependency injection to agent API.
Agent Provider & Context
internal/agent/provider_cache.go, internal/agent/provider_cache_test.go, internal/agent/contextkeys.go
Extended provider cache with dependency injection for OAuth credentials. Added context helpers for OAuth manager retrieval.
Model Presets & Configuration
internal/agent/presets.go, internal/agent/presets_test.go
Updated OpenAI model presets (GPT-5.4 versions) and added OpenAI Codex subscription presets. Validated new openai-codex provider type.
LLM Type System
internal/llm/types.go, internal/llm/provider.go, internal/llm/allproviders/allproviders.go
Extended Config with account ID and OAuth credential provider interface. Added ProviderOpenAICodex type and parsing. Registered Codex provider package.
OpenAI Codex LLM Provider
internal/llm/providers/openaicodex/codex.go, internal/llm/providers/openaicodex/codex_test.go
Implemented LLM provider for OpenAI Codex with SSE response streaming, tool call handling, thinking/reasoning request configuration, and credential resolution.
Backend Service Integration
internal/runtime/agent/agent.go, internal/runtime/builtin/agentstep/executor.go, internal/cmd/context.go, internal/cmd/start.go, internal/cmd/restart.go, internal/cmd/retry.go, internal/cmd/dry.go
Wired OAuth manager through agent runtime initialization, session manager config, and command-line execution paths (start/restart/retry/dry-run).
Frontend Service Setup
internal/service/frontend/server.go, internal/service/frontend/api/v1/api.go, internal/service/frontend/api/v1/agent_auth.go, internal/service/frontend/api/v1/agent_models.go, internal/service/frontend/api/v1/agent_models_test.go
Initialized encrypted OAuth store and manager at frontend server startup. Implemented OAuth management endpoints with admin authorization. Extended model creation/update with thinking effort validation and provider-specific configuration (e.g., denying direct API key for Codex).
Worker Service Integration
internal/service/worker/remote_handler.go
Aggregated agent stores (config/model/memory/OAuth) into bundle for DAG execution; initialized OAuth manager with encryption when available.
Frontend Schema & Types
ui/src/api/v1/schema.ts
Generated TypeScript types for new OAuth endpoints and thinking effort enums from OpenAPI specification.
Frontend UI Components
ui/src/features/agent/components/ProviderAuthCard.tsx, ui/src/features/agent/hooks/useAgentAuthProviders.ts, ui/src/pages/agent-settings/ModelFormModal.tsx, ui/src/pages/agent-settings/index.tsx, ui/src/pages/setup.tsx
Implemented provider authentication UI card with login/disconnect flows, OAuth provider hook for data fetching, and integration in model form and setup wizards with Codex subscription connection enforcement.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/Browser
    participant Frontend as Frontend API
    participant OAuthMgr as OAuth Manager
    participant OAuthStore as Credential Store
    participant Provider as OpenAI Codex Provider
    participant ExternalOAuth as OpenAI Auth Service

    User->>Frontend: POST /settings/agent/auth/providers/{id}/login
    Frontend->>OAuthMgr: StartLogin(ctx, provider)
    OAuthMgr->>Provider: StartAuthFlow()
    Provider->>Provider: Generate PKCE verifier, state
    Provider-->>OAuthMgr: authFlow (state, verifier)
    OAuthMgr-->>Frontend: FlowID, AuthURL, Instructions
    Frontend-->>User: Redirect to AuthURL (OpenAI login page)

    User->>ExternalOAuth: Authorize & Redirect
    ExternalOAuth->>Frontend: Redirect to callback with code, state
    User->>Frontend: POST /settings/agent/auth/providers/{id}/login/complete
    Frontend->>OAuthMgr: CompleteLogin(ctx, provider, code, state)
    OAuthMgr->>OAuthMgr: Validate state, lookup flowID
    OAuthMgr->>Provider: ExchangeCode(code, verifier)
    Provider->>ExternalOAuth: POST token endpoint (authorization_code)
    ExternalOAuth-->>Provider: access_token, refresh_token, expires_in
    Provider->>Provider: Extract account ID from JWT
    Provider-->>OAuthMgr: Credential (tokens, account ID, expiry)
    OAuthMgr->>OAuthStore: Set(credential)
    OAuthStore-->>OAuthMgr: Stored
    OAuthMgr-->>Frontend: Credential (account ID, connected status)
    Frontend-->>User: Success response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • feat: chat assistant #1615: Modifies internal/agent/api.go and related agent runtime infrastructure; overlaps with OAuth manager dependency injection and API wiring in this PR.
  • refactor: make scheduler proc-authoritative #1824: Changes internal/runtime/agent/agent.go struct fields (Agent/Options); directly conflicts/adjacent to the AgentOAuthManager field additions in this PR.
  • feat: agent step type #1681: Updates internal/agent/loop.go to add per-loop state tracking; shares the same file and pattern as the ThinkingEffort/SetThinkingEffort additions in this PR.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.72% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the two main features: OpenAI Codex authentication support and reasoning effort implementation in agent settings, matching the scope of changes across backend and frontend code.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch openai-codex

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/agent/api.go (1)

872-909: ⚠️ Potential issue | 🟠 Major

Reactivated sessions now inherit the current default model's reasoning settings.

This block still rebuilds model-specific runtime state from defaultModelID, and reactivateSession never restores the session's original mgr.model. After cleanup/restart, a session created on a non-default model can resume on a different model with different pricing and thinkingEffort. Please persist and restore the session model before applying model-specific runtime config here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agent/api.go` around lines 872 - 909, The reactivation code
currently resolves provider using a.getDefaultModelID and applies model-specific
runtime state, which can change a session's original model; instead, read and
restore the session's persisted model ID (e.g., sess.Model or sess.ModelID)
first and use that model ID when calling a.resolveProvider to populate
InputCostPer1M, OutputCostPer1M and ThinkingEffort; only fall back to
a.getDefaultModelID if the session has no stored model; also ensure the restored
model ID is passed into SessionManagerConfig / NewSessionManager (e.g., include
ModelID or Model field) so the manager keeps the original session model rather
than inheriting the current default.
🧹 Nitpick comments (9)
internal/agent/model_config.go (1)

132-132: Consider adding a doc comment for valid ThinkingEffort values.

The field is correctly added with omitempty for optional serialization. For maintainability, consider adding a brief comment documenting the expected values (e.g., "low", "medium", "high" or similar) so future developers understand the valid range without needing to trace through the validation logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agent/model_config.go` at line 132, Add a concise doc comment above
the ThinkingEffort struct field in model_config.go explaining the
expected/allowed string values (e.g., "low", "medium", "high" or whatever the
validation accepts) so future readers know the valid range without tracing
validation logic; reference the ThinkingEffort string field in the struct and
include note about omitempty and whether values are case-sensitive or mapped to
enums.
internal/agent/provider_cache_test.go (1)

25-25: Add one test for non-empty ProviderDeps path.

These updates correctly align callsites, but the suite still validates only ProviderDeps{}. Please add one case with populated deps (OAuth manager path) so the new dependency-based behavior is covered.

Also applies to: 29-29, 46-46, 62-62, 73-73, 99-99, 195-195, 252-252

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agent/provider_cache_test.go` at line 25, Add a test case that calls
cache.GetOrCreate with a non-empty ProviderDeps (e.g.,
ProviderDeps{OAuthManagerPath: "some/path"}) instead of only ProviderDeps{} so
the dependency-based path is exercised; update the test(s) that currently invoke
cache.GetOrCreate(cfg, ProviderDeps{}) to also call cache.GetOrCreate(cfg,
ProviderDeps{OAuthManagerPath: "<valid-or-temp-path>"}), then assert the same
expectations you have for p1/model1 (or the relevant returned values) to ensure
the OAuth-manager path branch is covered. Ensure you adjust all similar test
sites that currently use ProviderDeps{} (including other occurrences calling
cache.GetOrCreate, cfg, p1, model1) to include one non-empty deps case.
internal/agent/api_test.go (1)

1094-1109: Capture model-b requests too.

Line 1108 only receives a second request if SendMessage keeps reusing model-a's provider. Registering model-b with a capturing provider would keep this test focused on thinking-effort propagation instead of current provider-reuse semantics.

Suggested change
 reqCh := make(chan *llm.ChatRequest, 2)
 api, _ := testAPIWithModels(t, modelA, modelB)
 api.providers.Set(modelA.ToLLMConfig(), newCapturingProvider(reqCh, simpleStopResponse("a")))
-api.providers.Set(modelB.ToLLMConfig(), newStopProvider("b"))
+api.providers.Set(modelB.ToLLMConfig(), newCapturingProvider(reqCh, simpleStopResponse("b")))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agent/api_test.go` around lines 1094 - 1109, The test registers
modelB with newStopProvider so the second request isn't captured; update the
provider registration to use a capturing provider for modelB (e.g., call
api.providers.Set(modelB.ToLLMConfig(), newCapturingProvider(reqCh,
simpleStopResponse("b")))) so that the second request emitted by api.SendMessage
is received on reqCh; look for the reqCh, testAPIWithModels, api.providers.Set,
newCapturingProvider/newStopProvider, CreateSession and SendMessage calls to
make the change.
internal/cmd/context.go (1)

576-591: Extract the encrypted OAuth-store bootstrap into one helper.

This key → encryptor → store sequence is now duplicated here, in buildRemoteNodeResolver, and again in internal/service/worker/remote_handler.go. Centralizing it would keep the directory layout and warning behavior from drifting.

Possible extraction
+func newAgentOAuthManager(dataDir string) (*agentoauth.Manager, error) {
+	encKey, err := crypto.ResolveKey(dataDir)
+	if err != nil {
+		return nil, err
+	}
+	enc, err := crypto.NewEncryptor(encKey)
+	if err != nil {
+		return nil, err
+	}
+	store, err := fileagentoauth.New(filepath.Join(dataDir, "agent", "oauth"), enc)
+	if err != nil {
+		return nil, err
+	}
+	return agentoauth.NewManager(store), nil
+}
+
 	encKey, err := crypto.ResolveKey(c.Config.Paths.DataDir)
 	if err != nil {
 		logger.Warn(c, "Failed to resolve encryption key for agent OAuth store", tag.Error(err))
 	} else {
-		enc, err := crypto.NewEncryptor(encKey)
-		if err != nil {
-			logger.Warn(c, "Failed to create encryptor for agent OAuth store", tag.Error(err))
-		} else {
-			store, err := fileagentoauth.New(filepath.Join(c.Config.Paths.DataDir, "agent", "oauth"), enc)
-			if err != nil {
-				logger.Warn(c, "Failed to create agent OAuth store", tag.Error(err))
-			} else {
-				result.OAuthManager = agentoauth.NewManager(store)
-			}
-		}
+		manager, err := newAgentOAuthManager(c.Config.Paths.DataDir)
+		if err != nil {
+			logger.Warn(c, "Failed to create agent OAuth manager", tag.Error(err))
+		} else {
+			result.OAuthManager = manager
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cmd/context.go` around lines 576 - 591, Extract the repeated
key→encryptor→store bootstrapping into a single helper (e.g.,
bootstrapAgentOAuthStore or NewAgentOAuthManager) that encapsulates
crypto.ResolveKey, crypto.NewEncryptor, fileagentoauth.New and returns the
created agentoauth.Manager (or the store plus manager) and any error; replace
the inline sequences in context.go (where result.OAuthManager is set) and in
buildRemoteNodeResolver and internal/service/worker/remote_handler.go to call
this helper, preserving the same filepath.Join(c.Config.Paths.DataDir, "agent",
"oauth") layout and the existing logger.Warn messages (use the same messages and
tag.Error(err) when bubbling warnings) so behavior and logs remain identical.
internal/agentoauth/openai_codex.go (1)

154-170: Consider adding timeout to HTTP client for token exchange.

Using http.DefaultClient without a timeout could cause indefinite hangs if the OpenAI auth server is unresponsive. Consider using a client with a configured timeout (e.g., 30 seconds).

♻️ Proposed fix to add timeout
+var tokenClient = &http.Client{
+	Timeout: 30 * time.Second,
+}
+
 func exchangeToken(ctx context.Context, form url.Values) (*Credential, error) {
 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, openAICodexTokenURL, strings.NewReader(form.Encode()))
 	if err != nil {
 		return nil, fmt.Errorf("create token request: %w", err)
 	}
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

-	resp, err := http.DefaultClient.Do(req)
+	resp, err := tokenClient.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("exchange OAuth token: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agentoauth/openai_codex.go` around lines 154 - 170, The
exchangeToken function uses http.DefaultClient which has no timeout and can
hang; replace the HTTP call to use a dedicated http.Client with a timeout (e.g.,
30s) instead of http.DefaultClient.Do; update the call in exchangeToken where
resp, err := http.DefaultClient.Do(req) to use a locally constructed client (or
a shared client variable) with Timeout set so the token exchange is bounded,
keeping all other behavior (headers, body read/close, and status handling) the
same and still using the existing openAICodexTokenURL and ctx.
internal/persis/fileagentoauth/store.go (1)

219-228: Consider logging time parse failures.

Failed time parsing is silently ignored, leaving zero-value timestamps. While this is safe, logging a warning could help diagnose corrupted credential files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/persis/fileagentoauth/store.go` around lines 219 - 228, When
parseTime fails for stored.ExpiresAt or stored.UpdatedAt the error is currently
ignored; update the blocks that call parseTime (around stored.ExpiresAt and
stored.UpdatedAt) to log a warning including the field name, the raw string
(stored.ExpiresAt / stored.UpdatedAt) and the parse error before leaving the
timestamp as the zero value; keep the existing behavior of only assigning
cred.ExpiresAt / cred.UpdatedAt on successful parse. Use the project's logging
mechanism (or fmt/log if none exists) to emit the warning so parse failures are
visible for debugging.
internal/agentoauth/manager.go (1)

174-176: Minor: Consider iterating over m.providers keys instead of hardcoded list.

Line 175 uses a hardcoded []string{ProviderOpenAICodex} while m.providers already contains the registered providers. If providers are added/removed, this list must be updated manually.

Suggested improvement
 func (m *Manager) Status(ctx context.Context) ([]ProviderStatus, error) {
 	statuses := make([]ProviderStatus, 0, len(m.providers))
-	for _, provider := range []string{ProviderOpenAICodex} {
+	for provider := range m.providers {
 		prov, err := m.lookupProvider(provider)

Note: If ordering matters, you may want to sort the keys or maintain a separate ordered list.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/agentoauth/manager.go` around lines 174 - 176, The loop currently
iterates a hardcoded slice []string{ProviderOpenAICodex}; change it to iterate
the keys of m.providers so new providers are handled automatically: build a
slice of provider names from the map m.providers (optionally sort it if
deterministic order is required) and then call m.lookupProvider for each name to
populate statuses (types: ProviderStatus, variables: statuses, provider, prov,
err, method: lookupProvider). Ensure the code replaces the literal
ProviderOpenAICodex usage with the dynamic key iteration.
internal/llm/providers/openaicodex/codex.go (1)

238-241: Consider logging JSON parse errors for debugging.

Silent continue on unmarshal errors (line 240) could hide malformed events from Codex. While skipping unknown data is reasonable, logging at debug level would help diagnose issues in production.

Suggested improvement
 		var event responseEvent
 		if err := json.Unmarshal([]byte(data), &event); err != nil {
+			// Log at debug level to aid troubleshooting without noise
+			// logger.Debug(ctx, "skipping unparseable SSE event", "error", err, "data", data)
 			continue
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/llm/providers/openaicodex/codex.go` around lines 238 - 241, The JSON
unmarshal error is being swallowed when parsing Codex events; update the block
around json.Unmarshal([]byte(data), &event) (responseEvent/event) to log the
error at debug level including the error and the raw data before continuing
(e.g., call the package's debug logger with a message like "failed to unmarshal
Codex response" plus err and data) so malformed events are visible for
troubleshooting, then continue as before.
internal/service/frontend/api/v1/agent_auth.go (1)

85-97: Consider using returned credential to avoid extra store lookup.

The credential returned by CompleteLogin (line 85) is discarded, then providerStatus (line 94) re-fetches it from the store. While functionally correct, this creates redundant I/O.

Possible optimization

If ProviderStatus can be constructed from the credential, consider building the response directly:

cred, err := a.agentOAuthManager.CompleteLogin(...)
if err != nil {
    return nil, toAgentAuthError(ctx, "complete login", err)
}
// Build status from cred instead of re-fetching

However, if providerStatus includes additional data beyond the credential, the current approach is fine.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/service/frontend/api/v1/agent_auth.go` around lines 85 - 97,
CompleteLogin currently returns a credential that is ignored and then
providerStatus re-reads the store, causing redundant I/O; change the flow in the
handler to capture the returned credential from
a.agentOAuthManager.CompleteLogin (e.g., store it in a local variable like cred)
and use that credential to construct the ProviderStatus response directly (or
add a helper that builds providerStatus from the credential) instead of calling
providerStatus(ctx, request.ProviderId) again; if providerStatus truly requires
extra store-derived fields, update or add a function (e.g.,
providerStatusFromCredential or augmentProviderStatus) that merges cred with the
additional data to avoid a full duplicate lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/v1/api.yaml`:
- Around line 9437-9449: The CompleteAgentAuthProviderLoginRequest schema
currently allows only flowId and thus accepts payloads the handler must reject;
update the CompleteAgentAuthProviderLoginRequest definition to keep flowId
required, add a oneOf (or anyOf) constraint requiring at least one of
redirectUrl or code, and make redirectUrl and code non-empty strings by adding
minLength: 1 to each property; reference the schema and properties by name
(CompleteAgentAuthProviderLoginRequest, flowId, redirectUrl, code) when making
the change.

In `@internal/llm/providers/openaicodex/codex.go`:
- Around line 37-45: The constructor New currently allows creating a Provider
when only cfg.APIKey is set but resolveCredential expects both APIKey and
AccountID; update New (the New function that returns *Provider) to validate that
if cfg.OAuthCredentialProvider is nil and cfg.APIKey is non-empty then
cfg.AccountID must also be non-empty and return an error (e.g. a descriptive
fmt.Errorf("account ID required when using API key")) if it's missing, so
creation fails early instead of deferring to resolveCredential; keep the
existing httpClient/Provider return when validation passes.

In `@internal/service/frontend/api/v1/agent_models_test.go`:
- Around line 469-487: The subtest "openai-codex clears api key and base url"
currently expects CreateAgentModel to return an error but should assert success
and that credentials are normalized away; update the test (inside the t.Run
block using newAgentTestSetupWithOAuth and the call to
setup.api.CreateAgentModel with apigen.CreateAgentModelRequestObject /
CreateModelConfigRequest) to require no error, require a non-nil resp, and
assert that the returned model/response has empty ApiKey and BaseUrl fields (or
their equivalent in the response object) instead of expecting failure.

In `@ui/src/api/v1/schema.ts`:
- Around line 1895-1898: The CompleteAgentAuthProviderLoginRequest schema
currently allows only { flowId } and must be changed in the OpenAPI source so
the request requires one completion input; update the
CompleteAgentAuthProviderLoginRequest definition (used by the post operation for
completeAgentAuthProviderLogin) to enforce that either redirectUrl or code is
provided (use a oneOf/anyOf with object variants that each require flowId plus
either redirectUrl or code, or use required + oneOf on the properties), then
regenerate frontend types with pnpm gen:api so the generated
ui/src/api/v1/schema.ts reflects the new validation.

In `@ui/src/pages/agent-settings/index.tsx`:
- Around line 899-907: The cell currently treats a null codexProvider as "Not
connected" which conflates loading/error with an actual disconnected state;
update the rendering for the openai-codex branch to first check the auth query
state (e.g., the codex auth query's isLoading/isError flags or an explicit
codexProviderLoading/codexProviderError) and render a distinct "Loading..." or
"Error" label when loading/error, only falling back to "Not connected" when
codexProvider is non-null and connected is false; keep references to m.provider
=== 'openai-codex', codexProvider, and m.apiKeyConfigured to locate the code to
change.

---

Outside diff comments:
In `@internal/agent/api.go`:
- Around line 872-909: The reactivation code currently resolves provider using
a.getDefaultModelID and applies model-specific runtime state, which can change a
session's original model; instead, read and restore the session's persisted
model ID (e.g., sess.Model or sess.ModelID) first and use that model ID when
calling a.resolveProvider to populate InputCostPer1M, OutputCostPer1M and
ThinkingEffort; only fall back to a.getDefaultModelID if the session has no
stored model; also ensure the restored model ID is passed into
SessionManagerConfig / NewSessionManager (e.g., include ModelID or Model field)
so the manager keeps the original session model rather than inheriting the
current default.

---

Nitpick comments:
In `@internal/agent/api_test.go`:
- Around line 1094-1109: The test registers modelB with newStopProvider so the
second request isn't captured; update the provider registration to use a
capturing provider for modelB (e.g., call
api.providers.Set(modelB.ToLLMConfig(), newCapturingProvider(reqCh,
simpleStopResponse("b")))) so that the second request emitted by api.SendMessage
is received on reqCh; look for the reqCh, testAPIWithModels, api.providers.Set,
newCapturingProvider/newStopProvider, CreateSession and SendMessage calls to
make the change.

In `@internal/agent/model_config.go`:
- Line 132: Add a concise doc comment above the ThinkingEffort struct field in
model_config.go explaining the expected/allowed string values (e.g., "low",
"medium", "high" or whatever the validation accepts) so future readers know the
valid range without tracing validation logic; reference the ThinkingEffort
string field in the struct and include note about omitempty and whether values
are case-sensitive or mapped to enums.

In `@internal/agent/provider_cache_test.go`:
- Line 25: Add a test case that calls cache.GetOrCreate with a non-empty
ProviderDeps (e.g., ProviderDeps{OAuthManagerPath: "some/path"}) instead of only
ProviderDeps{} so the dependency-based path is exercised; update the test(s)
that currently invoke cache.GetOrCreate(cfg, ProviderDeps{}) to also call
cache.GetOrCreate(cfg, ProviderDeps{OAuthManagerPath: "<valid-or-temp-path>"}),
then assert the same expectations you have for p1/model1 (or the relevant
returned values) to ensure the OAuth-manager path branch is covered. Ensure you
adjust all similar test sites that currently use ProviderDeps{} (including other
occurrences calling cache.GetOrCreate, cfg, p1, model1) to include one non-empty
deps case.

In `@internal/agentoauth/manager.go`:
- Around line 174-176: The loop currently iterates a hardcoded slice
[]string{ProviderOpenAICodex}; change it to iterate the keys of m.providers so
new providers are handled automatically: build a slice of provider names from
the map m.providers (optionally sort it if deterministic order is required) and
then call m.lookupProvider for each name to populate statuses (types:
ProviderStatus, variables: statuses, provider, prov, err, method:
lookupProvider). Ensure the code replaces the literal ProviderOpenAICodex usage
with the dynamic key iteration.

In `@internal/agentoauth/openai_codex.go`:
- Around line 154-170: The exchangeToken function uses http.DefaultClient which
has no timeout and can hang; replace the HTTP call to use a dedicated
http.Client with a timeout (e.g., 30s) instead of http.DefaultClient.Do; update
the call in exchangeToken where resp, err := http.DefaultClient.Do(req) to use a
locally constructed client (or a shared client variable) with Timeout set so the
token exchange is bounded, keeping all other behavior (headers, body read/close,
and status handling) the same and still using the existing openAICodexTokenURL
and ctx.

In `@internal/cmd/context.go`:
- Around line 576-591: Extract the repeated key→encryptor→store bootstrapping
into a single helper (e.g., bootstrapAgentOAuthStore or NewAgentOAuthManager)
that encapsulates crypto.ResolveKey, crypto.NewEncryptor, fileagentoauth.New and
returns the created agentoauth.Manager (or the store plus manager) and any
error; replace the inline sequences in context.go (where result.OAuthManager is
set) and in buildRemoteNodeResolver and
internal/service/worker/remote_handler.go to call this helper, preserving the
same filepath.Join(c.Config.Paths.DataDir, "agent", "oauth") layout and the
existing logger.Warn messages (use the same messages and tag.Error(err) when
bubbling warnings) so behavior and logs remain identical.

In `@internal/llm/providers/openaicodex/codex.go`:
- Around line 238-241: The JSON unmarshal error is being swallowed when parsing
Codex events; update the block around json.Unmarshal([]byte(data), &event)
(responseEvent/event) to log the error at debug level including the error and
the raw data before continuing (e.g., call the package's debug logger with a
message like "failed to unmarshal Codex response" plus err and data) so
malformed events are visible for troubleshooting, then continue as before.

In `@internal/persis/fileagentoauth/store.go`:
- Around line 219-228: When parseTime fails for stored.ExpiresAt or
stored.UpdatedAt the error is currently ignored; update the blocks that call
parseTime (around stored.ExpiresAt and stored.UpdatedAt) to log a warning
including the field name, the raw string (stored.ExpiresAt / stored.UpdatedAt)
and the parse error before leaving the timestamp as the zero value; keep the
existing behavior of only assigning cred.ExpiresAt / cred.UpdatedAt on
successful parse. Use the project's logging mechanism (or fmt/log if none
exists) to emit the warning so parse failures are visible for debugging.

In `@internal/service/frontend/api/v1/agent_auth.go`:
- Around line 85-97: CompleteLogin currently returns a credential that is
ignored and then providerStatus re-reads the store, causing redundant I/O;
change the flow in the handler to capture the returned credential from
a.agentOAuthManager.CompleteLogin (e.g., store it in a local variable like cred)
and use that credential to construct the ProviderStatus response directly (or
add a helper that builds providerStatus from the credential) instead of calling
providerStatus(ctx, request.ProviderId) again; if providerStatus truly requires
extra store-derived fields, update or add a function (e.g.,
providerStatusFromCredential or augmentProviderStatus) that merges cred with the
additional data to avoid a full duplicate lookup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8fce0caf-8b1d-4162-89d5-10c11ced29b1

📥 Commits

Reviewing files that changed from the base of the PR and between bed0c6f and a383c17.

📒 Files selected for processing (43)
  • api/v1/api.gen.go
  • api/v1/api.yaml
  • internal/agent/api.go
  • internal/agent/api_test.go
  • internal/agent/contextkeys.go
  • internal/agent/loop.go
  • internal/agent/model_config.go
  • internal/agent/presets.go
  • internal/agent/presets_test.go
  • internal/agent/provider_cache.go
  • internal/agent/provider_cache_test.go
  • internal/agent/session.go
  • internal/agentoauth/manager.go
  • internal/agentoauth/manager_test.go
  • internal/agentoauth/openai_codex.go
  • internal/agentoauth/openai_codex_test.go
  • internal/agentoauth/types.go
  • internal/cmd/context.go
  • internal/cmd/dry.go
  • internal/cmd/restart.go
  • internal/cmd/retry.go
  • internal/cmd/start.go
  • internal/llm/allproviders/allproviders.go
  • internal/llm/provider.go
  • internal/llm/providers/openaicodex/codex.go
  • internal/llm/providers/openaicodex/codex_test.go
  • internal/llm/types.go
  • internal/persis/fileagentoauth/store.go
  • internal/persis/fileagentoauth/store_test.go
  • internal/runtime/agent/agent.go
  • internal/runtime/builtin/agentstep/executor.go
  • internal/service/frontend/api/v1/agent_auth.go
  • internal/service/frontend/api/v1/agent_models.go
  • internal/service/frontend/api/v1/agent_models_test.go
  • internal/service/frontend/api/v1/api.go
  • internal/service/frontend/server.go
  • internal/service/worker/remote_handler.go
  • ui/src/api/v1/schema.ts
  • ui/src/features/agent/components/ProviderAuthCard.tsx
  • ui/src/features/agent/hooks/useAgentAuthProviders.ts
  • ui/src/pages/agent-settings/ModelFormModal.tsx
  • ui/src/pages/agent-settings/index.tsx
  • ui/src/pages/setup.tsx

Comment thread api/v1/api.yaml
Comment on lines +9437 to +9449
CompleteAgentAuthProviderLoginRequest:
type: object
required:
- flowId
description: "Complete a manual OAuth login flow"
properties:
flowId:
type: string
redirectUrl:
type: string
code:
type: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Require at least one OAuth callback input.

flowId alone satisfies this schema today, so the contract accepts a payload the handler can only reject at runtime. Model redirectUrl or code as required alternatives, and make these strings non-empty.

Suggested schema tightening
    CompleteAgentAuthProviderLoginRequest:
      type: object
      required:
        - flowId
+     anyOf:
+       - required: [redirectUrl]
+       - required: [code]
      description: "Complete a manual OAuth login flow"
      properties:
        flowId:
          type: string
+         minLength: 1
        redirectUrl:
          type: string
+         format: uri
+         minLength: 1
        code:
          type: string
+         minLength: 1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CompleteAgentAuthProviderLoginRequest:
type: object
required:
- flowId
description: "Complete a manual OAuth login flow"
properties:
flowId:
type: string
redirectUrl:
type: string
code:
type: string
CompleteAgentAuthProviderLoginRequest:
type: object
required:
- flowId
anyOf:
- required: [redirectUrl]
- required: [code]
description: "Complete a manual OAuth login flow"
properties:
flowId:
type: string
minLength: 1
redirectUrl:
type: string
format: uri
minLength: 1
code:
type: string
minLength: 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1/api.yaml` around lines 9437 - 9449, The
CompleteAgentAuthProviderLoginRequest schema currently allows only flowId and
thus accepts payloads the handler must reject; update the
CompleteAgentAuthProviderLoginRequest definition to keep flowId required, add a
oneOf (or anyOf) constraint requiring at least one of redirectUrl or code, and
make redirectUrl and code non-empty strings by adding minLength: 1 to each
property; reference the schema and properties by name
(CompleteAgentAuthProviderLoginRequest, flowId, redirectUrl, code) when making
the change.

Comment on lines +37 to +45
func New(cfg llm.Config) (llm.Provider, error) {
if cfg.OAuthCredentialProvider == nil && strings.TrimSpace(cfg.APIKey) == "" {
return nil, llm.ErrNoAPIKey
}
return &Provider{
config: cfg,
httpClient: &http.Client{Timeout: cfg.Timeout},
}, nil
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Incomplete validation: AccountID not checked when APIKey is provided.

The constructor allows creation with only an APIKey, but resolveCredential (line 112-114) requires both APIKey AND AccountID to be non-empty. This causes a deferred failure: the provider is created successfully but fails on the first request.

Proposed fix
 func New(cfg llm.Config) (llm.Provider, error) {
-	if cfg.OAuthCredentialProvider == nil && strings.TrimSpace(cfg.APIKey) == "" {
+	if cfg.OAuthCredentialProvider == nil && (strings.TrimSpace(cfg.APIKey) == "" || strings.TrimSpace(cfg.AccountID) == "") {
 		return nil, llm.ErrNoAPIKey
 	}
 	return &Provider{
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func New(cfg llm.Config) (llm.Provider, error) {
if cfg.OAuthCredentialProvider == nil && strings.TrimSpace(cfg.APIKey) == "" {
return nil, llm.ErrNoAPIKey
}
return &Provider{
config: cfg,
httpClient: &http.Client{Timeout: cfg.Timeout},
}, nil
}
func New(cfg llm.Config) (llm.Provider, error) {
if cfg.OAuthCredentialProvider == nil && (strings.TrimSpace(cfg.APIKey) == "" || strings.TrimSpace(cfg.AccountID) == "") {
return nil, llm.ErrNoAPIKey
}
return &Provider{
config: cfg,
httpClient: &http.Client{Timeout: cfg.Timeout},
}, nil
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/llm/providers/openaicodex/codex.go` around lines 37 - 45, The
constructor New currently allows creating a Provider when only cfg.APIKey is set
but resolveCredential expects both APIKey and AccountID; update New (the New
function that returns *Provider) to validate that if cfg.OAuthCredentialProvider
is nil and cfg.APIKey is non-empty then cfg.AccountID must also be non-empty and
return an error (e.g. a descriptive fmt.Errorf("account ID required when using
API key")) if it's missing, so creation fails early instead of deferring to
resolveCredential; keep the existing httpClient/Provider return when validation
passes.

Comment on lines +469 to +487
t.Run("openai-codex clears api key and base url", func(t *testing.T) {
t.Parallel()

setup := newAgentTestSetupWithOAuth(t, true)
customURL := "https://example.com"
customKey := "sk-should-not-stick"

resp, err := setup.api.CreateAgentModel(adminCtx(), apigen.CreateAgentModelRequestObject{
Body: &apigen.CreateModelConfigRequest{
Name: "Codex",
Provider: "openai-codex",
Model: "gpt-5.4",
ApiKey: &customKey,
BaseUrl: &customURL,
},
})
require.Error(t, err)
assert.Nil(t, resp)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

This subtest asserts the opposite of its stated behavior.

The case is named "openai-codex clears api key and base url", but it currently expects CreateAgentModel to fail. Once the backend normalizes those fields away, this test will fail despite the intended behavior. Assert success and verify the stored model/response has empty credentials instead.

🧪 Suggested assertion change
-		require.Error(t, err)
-		assert.Nil(t, resp)
+		require.NoError(t, err)
+		createResp, ok := resp.(apigen.CreateAgentModel201JSONResponse)
+		require.True(t, ok)
+		assert.Empty(t, setup.modelStore.models[createResp.Id].APIKey)
+		assert.Empty(t, setup.modelStore.models[createResp.Id].BaseURL)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
t.Run("openai-codex clears api key and base url", func(t *testing.T) {
t.Parallel()
setup := newAgentTestSetupWithOAuth(t, true)
customURL := "https://example.com"
customKey := "sk-should-not-stick"
resp, err := setup.api.CreateAgentModel(adminCtx(), apigen.CreateAgentModelRequestObject{
Body: &apigen.CreateModelConfigRequest{
Name: "Codex",
Provider: "openai-codex",
Model: "gpt-5.4",
ApiKey: &customKey,
BaseUrl: &customURL,
},
})
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("openai-codex clears api key and base url", func(t *testing.T) {
t.Parallel()
setup := newAgentTestSetupWithOAuth(t, true)
customURL := "https://example.com"
customKey := "sk-should-not-stick"
resp, err := setup.api.CreateAgentModel(adminCtx(), apigen.CreateAgentModelRequestObject{
Body: &apigen.CreateModelConfigRequest{
Name: "Codex",
Provider: "openai-codex",
Model: "gpt-5.4",
ApiKey: &customKey,
BaseUrl: &customURL,
},
})
require.NoError(t, err)
createResp, ok := resp.(apigen.CreateAgentModel201JSONResponse)
require.True(t, ok)
assert.Empty(t, setup.modelStore.models[createResp.Id].APIKey)
assert.Empty(t, setup.modelStore.models[createResp.Id].BaseURL)
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/service/frontend/api/v1/agent_models_test.go` around lines 469 -
487, The subtest "openai-codex clears api key and base url" currently expects
CreateAgentModel to return an error but should assert success and that
credentials are normalized away; update the test (inside the t.Run block using
newAgentTestSetupWithOAuth and the call to setup.api.CreateAgentModel with
apigen.CreateAgentModelRequestObject / CreateModelConfigRequest) to require no
error, require a non-nil resp, and assert that the returned model/response has
empty ApiKey and BaseUrl fields (or their equivalent in the response object)
instead of expecting failure.

Comment thread ui/src/api/v1/schema.ts
Comment on lines +1895 to +1898
* Complete agent auth provider login
* @description Completes a manual OAuth login flow using the pasted redirect URL or authorization code. Requires admin role.
*/
post: operations["completeAgentAuthProviderLogin"];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Require one completion input in the schema.

CompleteAgentAuthProviderLoginRequest currently accepts { flowId } with neither redirectUrl nor code, even though the endpoint is documented as completing the flow with one of those inputs. That weakens the generated client contract for a new auth flow and shifts an avoidable validation failure to runtime. Since this file is generated, the fix should be made in the source OpenAPI schema.

🛠️ Suggested OpenAPI shape
 CompleteAgentAuthProviderLoginRequest:
   type: object
   required:
     - flowId
   properties:
     flowId:
       type: string
     redirectUrl:
       type: string
     code:
       type: string
+  oneOf:
+    - required: [redirectUrl]
+    - required: [code]

As per coding guidelines, "Frontend API types must be generated from OpenAPI spec via pnpm gen:api to maintain type safety with the backend".

Also applies to: 4009-4014

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/api/v1/schema.ts` around lines 1895 - 1898, The
CompleteAgentAuthProviderLoginRequest schema currently allows only { flowId }
and must be changed in the OpenAPI source so the request requires one completion
input; update the CompleteAgentAuthProviderLoginRequest definition (used by the
post operation for completeAgentAuthProviderLogin) to enforce that either
redirectUrl or code is provided (use a oneOf/anyOf with object variants that
each require flowId plus either redirectUrl or code, or use required + oneOf on
the properties), then regenerate frontend types with pnpm gen:api so the
generated ui/src/api/v1/schema.ts reflects the new validation.

Comment on lines +899 to +907
{m.provider === 'openai-codex' ? (
<span className={`text-xs ${codexProvider?.connected ? 'text-green-600' : 'text-muted-foreground'}`}>
{codexProvider?.connected ? 'Subscription' : 'Not connected'}
</span>
) : (
<span className={`text-xs ${m.apiKeyConfigured ? 'text-green-600' : 'text-muted-foreground'}`}>
{m.apiKeyConfigured ? 'Configured' : 'Not set'}
</span>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don't collapse "unknown" into "Not connected" here.

codexProvider is null both while the auth query is still loading and when it failed, so this cell briefly reports a disconnected subscription even though the status is actually unknown. That is especially misleading right after page load or a remote-node switch. Render a loading/error state before falling back to "Not connected".

💡 Possible fix
-                      {m.provider === 'openai-codex' ? (
-                        <span className={`text-xs ${codexProvider?.connected ? 'text-green-600' : 'text-muted-foreground'}`}>
-                          {codexProvider?.connected ? 'Subscription' : 'Not connected'}
-                        </span>
-                      ) : (
+                      {m.provider === 'openai-codex' ? (
+                        <span
+                          className={`text-xs ${
+                            authLoading
+                              ? 'text-muted-foreground'
+                              : authError
+                                ? 'text-amber-600'
+                                : codexProvider?.connected
+                                  ? 'text-green-600'
+                                  : 'text-muted-foreground'
+                          }`}
+                        >
+                          {authLoading
+                            ? 'Checking...'
+                            : authError
+                              ? 'Unavailable'
+                              : codexProvider?.connected
+                                ? 'Subscription'
+                                : 'Not connected'}
+                        </span>
+                      ) : (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{m.provider === 'openai-codex' ? (
<span className={`text-xs ${codexProvider?.connected ? 'text-green-600' : 'text-muted-foreground'}`}>
{codexProvider?.connected ? 'Subscription' : 'Not connected'}
</span>
) : (
<span className={`text-xs ${m.apiKeyConfigured ? 'text-green-600' : 'text-muted-foreground'}`}>
{m.apiKeyConfigured ? 'Configured' : 'Not set'}
</span>
)}
{m.provider === 'openai-codex' ? (
<span
className={`text-xs ${
authLoading
? 'text-muted-foreground'
: authError
? 'text-amber-600'
: codexProvider?.connected
? 'text-green-600'
: 'text-muted-foreground'
}`}
>
{authLoading
? 'Checking...'
: authError
? 'Unavailable'
: codexProvider?.connected
? 'Subscription'
: 'Not connected'}
</span>
) : (
<span className={`text-xs ${m.apiKeyConfigured ? 'text-green-600' : 'text-muted-foreground'}`}>
{m.apiKeyConfigured ? 'Configured' : 'Not set'}
</span>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/pages/agent-settings/index.tsx` around lines 899 - 907, The cell
currently treats a null codexProvider as "Not connected" which conflates
loading/error with an actual disconnected state; update the rendering for the
openai-codex branch to first check the auth query state (e.g., the codex auth
query's isLoading/isError flags or an explicit
codexProviderLoading/codexProviderError) and render a distinct "Loading..." or
"Error" label when loading/error, only falling back to "Not connected" when
codexProvider is non-null and connected is false; keep references to m.provider
=== 'openai-codex', codexProvider, and m.apiKeyConfigured to locate the code to
change.

@yottahmd yottahmd merged commit 14249a6 into main Apr 1, 2026
6 checks passed
@yottahmd yottahmd deleted the openai-codex branch April 1, 2026 06:50
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 53.42679% with 299 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.64%. Comparing base (b53e219) to head (079f7e6).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
internal/agentoauth/openai_codex.go 16.53% 102 Missing and 4 partials ⚠️
internal/agentoauth/manager.go 43.40% 75 Missing and 28 partials ⚠️
internal/persis/fileagentoauth/store.go 64.06% 26 Missing and 20 partials ⚠️
internal/service/worker/remote_handler.go 70.27% 10 Missing and 1 partial ⚠️
internal/agent/api.go 81.39% 6 Missing and 2 partials ⚠️
internal/agentoauth/types.go 0.00% 8 Missing ⚠️
internal/persis/fileagentoauth/manager.go 45.45% 3 Missing and 3 partials ⚠️
internal/agent/contextkeys.go 40.00% 3 Missing ⚠️
internal/cmd/context.go 40.00% 1 Missing and 2 partials ⚠️
internal/runtime/builtin/agentstep/executor.go 0.00% 3 Missing ⚠️
... and 1 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1921      +/-   ##
==========================================
- Coverage   68.77%   68.64%   -0.13%     
==========================================
  Files         457      462       +5     
  Lines       57637    58222     +585     
==========================================
+ Hits        39638    39966     +328     
- Misses      14388    14576     +188     
- Partials     3611     3680      +69     
Files with missing lines Coverage Δ
internal/agent/loop.go 87.90% <100.00%> (+0.81%) ⬆️
internal/agent/model_config.go 100.00% <ø> (ø)
internal/agent/presets.go 100.00% <ø> (ø)
internal/agent/provider_cache.go 90.76% <100.00%> (+5.05%) ⬆️
internal/agent/session.go 89.39% <100.00%> (+0.34%) ⬆️
internal/agent/types.go 100.00% <ø> (ø)
internal/cmd/dry.go 81.17% <100.00%> (+0.22%) ⬆️
internal/cmd/restart.go 68.11% <100.00%> (+0.23%) ⬆️
internal/cmd/retry.go 61.01% <100.00%> (+0.22%) ⬆️
internal/cmd/start.go 35.96% <100.00%> (+0.15%) ⬆️
... and 15 more

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b53e219...079f7e6. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant