Skip to content
Open
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
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,29 @@
- For UI work, include dark-theme evidence in addition to the default/light-theme evidence unless the task is explicitly light-only.
- For refresh-persistence fixes, include a post-refresh screenshot that still shows the expected UI state.

## Docker Provider/Auth Regression Workflow

- Use this workflow when a change touches Docker startup, Codex auth detection, OpenCode Zen/OpenRouter/custom providers, provider model loading, app-server config, chat send/reply handling, or failed-turn error rendering.
- Build and test a packaged Docker image, not only the Vite dev server:
1. Run `pnpm run build`.
2. Run `pnpm pack --pack-destination /tmp`.
3. Build a local image that installs the packed `codexapp` tarball plus `@openai/codex`, with `CODEX_HOME=/codex-home` and command `codexapp --port ${PORT:-4190} --no-password --no-open --no-tunnel --no-login`.
4. Use OrbStack/Docker CLI. Do not rely on Docker Desktop.
- Start fresh isolated containers on unique localhost ports for at least these cases:
- no auth file: no `/codex-home/auth.json`; expect runtime OpenCode Zen fallback, `model_provider="opencode-zen"`, `model="big-pickle"`, send `hi`, wait for an assistant reply.
- invalid/expired auth file: mount an `auth.json` with token fields containing invalid/expired strings; expect Codex provider path, send `hi`, wait for final 401/auth error rendered in chat, verify `Send feedback`, reload the thread, verify the error persists, and verify no duplicate live `Thinking` overlay remains after persistence.
- malformed auth file: mount invalid JSON as `/codex-home/auth.json`; expect it to be treated as unusable auth and fall back to Zen, then send `hi` and wait for a reply.
- provider switch: start from OpenCode Zen, send `hi` and wait for a reply, switch the Provider settings selector to OpenRouter (do not change the model dropdown directly), send `hi` again and wait for a reply.
- Browser assertions must inspect conversation rows, not sidebar previews. A test is not passing just because the sidebar contains the sent text.
- Save screenshots under `output/playwright/` for all Docker browser cases and show them inline in the completion report.
- Before reporting success, include:
- tested URLs/ports,
- provider/config summary for each container,
- exact build/test commands,
- screenshot absolute paths,
- whether invalid auth persisted after reload and whether duplicate live overlay count was zero.
- If any Docker edge case fails, fix it before requesting PR review or merge.

## Mandatory CJS + TestChat Validation For Markdown/File-Link Features

- For any markdown parsing, link parsing, file-link rendering, or browse-link encoding change, verification in `TestChat` is mandatory before reporting completion.
Expand Down
88 changes: 88 additions & 0 deletions llm-wiki/raw/fixes/copied-auth-provider-promotion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Copied Auth Provider Promotion Fix

Date: 2026-05-13

## Problem

In Docker no-auth mode, Codex Web Local starts with an OpenCode Zen runtime fallback. If the user switched the provider to OpenRouter while unauthenticated and then copied a valid `auth.json` into the mounted `CODEX_HOME`, the UI detected Codex auth but kept stale community-provider state.

Observed issues:
- Provider stayed on OpenRouter after valid Codex auth appeared.
- The Accounts badge stayed at `0` until a manual account refresh.
- The new-thread composer could show a generic `Model` label after provider promotion.
- The Settings feedback row could show stale `Send feedback / Issue detected` after recovery even when there was no visible current error.
- Sending on Codex worked after manually switching provider, proving the copied auth file was valid.

## Root Cause

The server read `webui-custom-providers.json` as authoritative whenever it existed. That file can contain community fallback provider state created during the unauthenticated phase. After `auth.json` appeared, the fallback provider state still supplied app-server provider flags and `/codex-api/free-mode/status` data.

The frontend also relied on the accounts snapshot for the Accounts count. A copied `auth.json` did not automatically import the active auth file into the accounts store.

Finally, provider-scoped new-thread model persistence applied to non-Codex providers but not to Codex. After provider promotion, the home composer could temporarily fall back to the generic `Model` placeholder instead of a concrete Codex model.

## Fix

Commit:
- `7ee94f83 Promote copied auth to Codex provider`

Implementation details:
- Added `shouldSuppressCommunityFreeModeForCodexAuth()` in `src/server/freeMode.ts`.
- `ensureDefaultFreeModeStateForMissingAuthSync()` now returns `null` when usable Codex auth exists and the existing provider state is only community fallback (`openrouter` or `opencode-zen` without a custom key).
- User-configured providers are preserved:
- OpenRouter with `customKey: true`
- OpenCode Zen with an explicit API key
- Custom endpoint provider
- `/codex-api/free-mode/status` now reports `hasCodexAuth`.
- `App.vue` uses `hasCodexAuth` to import a copied active `auth.json` into Accounts via `refreshAccountsFromAuth()` once.
- New-thread model persistence now uses provider-scoped slots for Codex as well as non-Codex providers.
- The Settings feedback row is shown only when a current visible error exists, not merely because historical diagnostics exist.

## Docker Validation

Fresh packaged image:

```text
codexui-local:e5e9-auth-promote-final2
```

Flow:
1. Start a fresh container with empty mounted `CODEX_HOME`.
2. Confirm initial provider is `opencode-zen`.
3. Switch provider to `openrouter`.
4. Copy `/Users/igor/.codex/auth.json` into the mounted `CODEX_HOME`.
5. Reload the UI.
6. Confirm provider changes to `codex`.
7. Confirm Accounts count becomes `1`.
8. Confirm the composer shows a concrete Codex model, not generic `Model`.
9. Confirm no stale `Send feedback / Issue detected` row appears.
10. Send `hi`; wait for a Codex reply.

Final validation result:

```json
{
"initialProvider": "opencode-zen",
"afterSwitchProvider": "openrouter",
"afterCopyProvider": "codex",
"afterCopyAccounts": 1,
"afterCopyHasIssue": false,
"finalProvider": "codex",
"finalHasIssue": false,
"stillBusy": false
}
```

Screenshot artifacts:
- `output/playwright/auth-promote-final2-01-noauth.png`
- `output/playwright/auth-promote-final2-02-openrouter.png`
- `output/playwright/auth-promote-final2-03-after-copy.png`
- `output/playwright/auth-promote-final2-04-reply.png`

## Verification Commands

```bash
pnpm test:unit src/server/freeMode.test.ts src/server/codexAppServerBridge.archive.test.ts src/composables/useDesktopState.test.ts src/api/codexGateway.test.ts
pnpm run build
pnpm pack --pack-destination /tmp
```
78 changes: 78 additions & 0 deletions llm-wiki/raw/fixes/opencode-zen-docker-auth-provider-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# OpenCode Zen Docker Auth and Provider Models Fix

Date: 2026-05-13

## Problem

Codex Web Local had two Docker startup edge cases around OpenCode Zen fallback and Codex auth:

1. In an authenticated Docker container, immediately polling `/codex-api/thread-live-state` after `turn/start` could return:

```text
thread <id> is not materialized yet; includeTurns is unavailable before first user message
```

The turn completed normally, but the bridge exposed this transient Codex state as `liveStateError.kind = "readFailed"`, making the chat look broken during first-turn startup.

2. In an unauthenticated Docker container, the model selector could appear empty or stale because frontend model loading called Codex `model/list` before `/codex-api/provider-models`. In OpenCode Zen fallback mode, provider models are authoritative; `model/list` can be slow, return Codex models, or fail independently.

## Root Cause

The live-state endpoint treated every `thread/read includeTurns=true` failure as a real read failure. Codex can briefly create a thread before the first user message is materialized, so that exact error is a pending state, not a terminal failure.

The model-loading helper fetched `model/list` first and only then attempted provider model discovery. This made no-auth Zen startup depend on a Codex model-list call that is not the source of truth for Zen models.

## Fix

Commits:
- `545c0dec Handle pending first-turn live state`
- `2eaf4bd3 Load provider models before Codex model list`

Implementation details:
- Added `isThreadMaterializationPendingError()` in `src/server/codexAppServerBridge.ts`.
- `/codex-api/thread-live-state` now maps that specific pending-materialization error to:
- `conversationState: { turns: [] }`
- `liveStateError: null`
- `isInProgress: true`
- Real `thread/read` failures still surface through `liveStateError`.
- `getAvailableModelIds()` now fetches `/codex-api/provider-models` first when provider models are included.
- If provider models are `exclusive` or `requireProviderModels` is true, it returns provider models without waiting on Codex `model/list`.
- Optional provider-model loading still falls back to `model/list` if provider models are unavailable.

## Docker Validation

Fresh image:

```text
codexui-local:e5e9-current
```

No-auth container:
- URL: `http://127.0.0.1:4191/#/`
- `config/read`: `model = "big-pickle"`, `model_provider = "opencode-zen"`
- App-server command includes Zen proxy flags.
- Sending `hi` returns an assistant reply.
- Model selector includes `big-pickle`, `deepseek-v4-flash-free`, and other Zen provider models.

Auth-mounted container:
- URL: `http://127.0.0.1:4192/#/`
- Mounted `/Users/igor/.codex/auth.json` to `/codex-home/auth.json`.
- `config/read`: `model = null`, `model_provider = null`
- App-server command has no Zen proxy flags.
- Sending `hi` returns an assistant reply.
- First-turn live-state polling does not expose the transient materialization error as `liveStateError`.

## Operational Notes

- For Docker validation, install the packed `codexapp` artifact during image build instead of using `pnpm dlx` at container runtime. Runtime `pnpm dlx` can re-download and extract dependencies on every start and can be killed under memory pressure.
- When validating no-auth Zen mode, trust `/codex-api/provider-models` and `/codex-api/free-mode/status` for provider models; `model/list` may still return Codex catalog rows from the Codex CLI.
- Browser verification should include a screenshot of the opened model selector after loading `http://127.0.0.1:4191/#/`.

## Verification Commands

```bash
pnpm test:unit src/server/codexAppServerBridge.archive.test.ts
pnpm test:unit src/api/codexGateway.test.ts src/composables/useDesktopState.test.ts
pnpm run build
```

29 changes: 29 additions & 0 deletions llm-wiki/wiki/concepts/opencode-zen-big-pickle.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ model_provider = "opencode-zen"
- Codex CLI deprecation warning for `wire_api = "chat"` is safe to ignore on v0.93.0
- In Codex Web Local's Zen proxy, DeepSeek thinking-mode responses must round-trip `reasoning_content` into later Chat Completions messages. Missing this field can produce `The reasoning_content in the thinking mode must be passed back to the API`.
- Chat-shaped Zen proxy payloads must be posted to `/v1/chat/completions`, even when the incoming local request uses the Responses-shaped `/responses` route.
- In no-auth Docker mode, OpenCode Zen provider models are authoritative. Fetch `/codex-api/provider-models` before relying on Codex `model/list`, because `model/list` may return Codex catalog rows or fail independently.
- During authenticated Docker first-turn startup, `thread ... is not materialized yet; includeTurns is unavailable before first user message` is a transient in-progress state, not a chat error.

## Codex Web Local Proxy Behavior

Expand All @@ -58,7 +60,34 @@ For thinking-mode models behind `big-pickle`, the proxy must preserve assistant

This behavior was fixed in commit `47d52c8c` after a Docker repro using an empty `CODEX_HOME`, no login, and no Zen API key.

## Docker Auth and Model Loading

Codex Web Local's unauthenticated Docker path should use OpenCode Zen only as a runtime fallback. It should not permanently write fallback provider configuration, and it should not depend on Codex `model/list` for the Zen selector.

Validated Docker states:
- Empty `CODEX_HOME`: `config/read` reports `model = "big-pickle"` and `model_provider = "opencode-zen"`, the app-server command includes local Zen proxy flags, and the model selector loads provider models from `/codex-api/provider-models`.
- `auth.json` mounted into `CODEX_HOME`: `config/read` reports `model = null` and `model_provider = null`, the app-server command has no Zen flags, and sending `hi` uses the default Codex provider path.

The first authenticated turn may briefly make `thread/read includeTurns=true` fail with `not materialized yet; includeTurns is unavailable before first user message`. The bridge maps that exact response to an in-progress empty live state with no `liveStateError`; real `thread/read` failures still surface as errors.

## Copied Auth Promotion

If a container starts without auth and later receives a valid `auth.json`, Codex auth should take precedence over community fallback provider state. This matters when a user starts in no-auth Zen mode, switches to OpenRouter, then copies auth into `CODEX_HOME`.

Expected behavior after copying auth and reloading:
- Community fallback provider state (`openrouter` or `opencode-zen` without a custom key) is suppressed.
- Provider promotes to Codex.
- Accounts imports the copied active auth file and the badge updates from `0` to at least `1`.
- The new-thread composer shows a concrete Codex model, not a generic `Model` placeholder.
- Stale historical diagnostics do not show a `Send feedback / Issue detected` row unless a current visible error remains.

User-configured provider state is preserved: OpenRouter with `customKey: true`, OpenCode Zen with an explicit API key, and custom endpoint providers should not be suppressed merely because Codex auth exists.

This behavior was fixed in commit `7ee94f83` and validated in a packaged Docker image by running: no-auth Zen startup, switch to OpenRouter, copy host `auth.json`, reload, verify Codex provider + Accounts `1`, send `hi`, and wait for a Codex reply.

## Related
- Source: [opencode-zen-big-pickle-codex-cli.md](../../raw/fixes/opencode-zen-big-pickle-codex-cli.md)
- Source: [opencode-zen-reasoning-content-proxy.md](../../raw/fixes/opencode-zen-reasoning-content-proxy.md)
- Source: [opencode-zen-docker-auth-provider-models.md](../../raw/fixes/opencode-zen-docker-auth-provider-models.md)
- Source: [copied-auth-provider-promotion.md](../../raw/fixes/copied-auth-provider-promotion.md)
- [merge-to-main-workflow.md](./merge-to-main-workflow.md)
3 changes: 3 additions & 0 deletions llm-wiki/wiki/entities/codex-web-local.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
- User-visible UI work is expected to include dark-theme verification, not only light-theme checks
- Worktree dev startup may reuse a shared `node_modules` tree; forcing reinstall is not always the right default
- Directory Hub is the `#/skills` surface for Plugins, Apps, Composio, MCPs, Skills search, and installed local skills
- Unauthenticated Docker startup can use OpenCode Zen as a runtime fallback, while an auth-mounted `CODEX_HOME` should switch back to the default Codex provider path without Zen flags

## Source links
- [Source snapshot](../../raw/projects/codex-web-local.md)
- [Integrated terminal source](../../raw/features/integrated-terminal.md)
- [Directory Hub Composio and Skills search source](../../raw/features/directory-hub-composio-skills-search.md)
- [Realtime chat rendering source](../../raw/features/realtime-chat-rendering-inline-media.md)
- [Skills route UI + first-launch card source](../../raw/features/skills-route-ui-and-first-launch-card.md)
- [OpenCode Zen Docker auth/provider models source](../../raw/fixes/opencode-zen-docker-auth-provider-models.md)
- [Integrated terminal concept](../concepts/integrated-terminal.md)
- [Directory Hub, Composio, and Skills Search concept](../concepts/directory-hub-composio-skills.md)
- [Realtime chat rendering concept](../concepts/realtime-chat-rendering.md)
- [Merge-to-main workflow concept](../concepts/merge-to-main-workflow.md)
- [Skills route UI concept](../concepts/skills-route-ui.md)
- [OpenCode Zen + Big Pickle concept](../concepts/opencode-zen-big-pickle.md)
4 changes: 3 additions & 1 deletion llm-wiki/wiki/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- [concepts/integrated-terminal.md](./concepts/integrated-terminal.md): Codex.app-style integrated xterm/PTY terminal architecture, edge cases, and verification.
- [concepts/directory-hub-composio-skills.md](./concepts/directory-hub-composio-skills.md): Directory Hub tab routing, Composio connector behavior, Skills search/install semantics, and edge-case testing.
- [concepts/merge-to-main-workflow.md](./concepts/merge-to-main-workflow.md): branch integration and conflict-resolution workflow.
- [concepts/opencode-zen-big-pickle.md](./concepts/opencode-zen-big-pickle.md): OpenCode Zen Big Pickle model configuration for Codex CLI and OpenCode CLI.
- [concepts/opencode-zen-big-pickle.md](./concepts/opencode-zen-big-pickle.md): OpenCode Zen Big Pickle model configuration, local proxy behavior, Docker auth switching, and provider model loading.
- [concepts/realtime-chat-rendering.md](./concepts/realtime-chat-rendering.md): realtime chat rendering, sync-churn reduction, and inline media sanitization.
- [concepts/skills-route-ui.md](./concepts/skills-route-ui.md): Skills route naming, first-launch Plugins card persistence, dark-theme fixes, and verification lessons.
- [concepts/thread-heartbeat-automations.md](./concepts/thread-heartbeat-automations.md): thread-scoped heartbeat automation storage, multi-automation management, and manual run behavior.
Expand All @@ -26,3 +26,5 @@
- [../raw/projects/codex-web-local.md](../raw/projects/codex-web-local.md): immutable source snapshot for project facts.
- [../raw/fixes/opencode-zen-big-pickle-codex-cli.md](../raw/fixes/opencode-zen-big-pickle-codex-cli.md): Big Pickle + Codex CLI fix details.
- [../raw/fixes/opencode-zen-reasoning-content-proxy.md](../raw/fixes/opencode-zen-reasoning-content-proxy.md): Codex Web Local Zen proxy reasoning_content round-trip fix and Docker verification.
- [../raw/fixes/opencode-zen-docker-auth-provider-models.md](../raw/fixes/opencode-zen-docker-auth-provider-models.md): Docker auth/no-auth provider switching, first-turn live-state materialization, and provider-model loading fixes.
- [../raw/fixes/copied-auth-provider-promotion.md](../raw/fixes/copied-auth-provider-promotion.md): copied `auth.json` promotion from community fallback provider state to Codex, account import, model-label, and stale feedback-row fixes.
12 changes: 12 additions & 0 deletions llm-wiki/wiki/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,15 @@
- Updated project cron automation notes for the combined Automations panel.
- Updated Automations panel notes for active/newest sorting and direct edit buttons.
- Updated project cron automation notes for absolute cwd validation and multi-cwd preservation.

## [2026-05-13] ingest | copied auth provider promotion
- Added source: [raw/fixes/copied-auth-provider-promotion.md](../raw/fixes/copied-auth-provider-promotion.md).
- Updated wiki page: [concepts/opencode-zen-big-pickle.md](./concepts/opencode-zen-big-pickle.md).
- Documents: suppressing community fallback provider state after valid Codex auth appears, preserving user-configured providers, importing copied auth into Accounts, provider-scoped Codex model persistence, stale feedback-row cleanup, and packaged Docker validation.
- Updated [index.md](./index.md).

## [2026-05-13] ingest | OpenCode Zen Docker auth and provider models
- Added source: [raw/fixes/opencode-zen-docker-auth-provider-models.md](../raw/fixes/opencode-zen-docker-auth-provider-models.md).
- Updated wiki page: [concepts/opencode-zen-big-pickle.md](./concepts/opencode-zen-big-pickle.md).
- Documents: no-auth Zen runtime fallback, auth-mounted Docker switching back to Codex defaults, first-turn materialization as a transient live-state condition, provider-model-first loading, and the build-time Docker install workaround for runtime `pnpm dlx` OOM risk.
- Updated [overview.md](./overview.md), [entities/codex-web-local.md](./entities/codex-web-local.md), and [index.md](./index.md).
Loading