unsloth/studio/frontend
Daniel Han 8ee60019a4 Studio: round 6 Codex hardening (5 follow-ups)
Reviewer round 6 surfaced five real follow-ups on top of rounds 5
through 5g. Each one is a fix for an asymmetric guard or a wrong-
shape lookup in the new Codex provider code:

1. Re-gate `installed=True` on having BOTH the SDK AND a `codex`
   binary on PATH. Round 5 widened the gate to SDK-only, but the
   login route still shells out to the binary, so an SDK-only host
   would surface a Codex row whose Sign-in button immediately
   failed with "codex CLI not found on PATH". The canonical
   `openai-codex` package depends on `openai-codex-cli-bin` which
   places the shim on PATH for free, so the common install still
   lights up; the gate just refuses to advertise a provider Studio
   cannot actually drive end-to-end.

2. `_safe_thread_safety_kwargs` now also probes `.api` and
   `.generated.v2_all` for `SandboxMode`. Upstream `openai_codex`
   exports `ApprovalMode` at the top level but `SandboxMode` lives
   under `openai_codex.generated.v2_all`. The previous lookup
   returned `{}` on the canonical SDK install, so every thread_start
   ran with the unsafe `auto_review` default. Submodule probe
   resolves the canonical layout and keeps backwards-compat with
   builds that DID re-export at the top level.

3. `_coerce_text` now applies the answer-event-type filter on the
   object path too. The upstream SDK emits typed payload classes
   like `CommandExecutionOutputDelta`, `FileChangeDelta`,
   `ToolCallDelta`, `PatchApplyDelta`, etc., all of which carry a
   `.delta` string of local stdout / file paths / tool args. The
   dict path already filtered these out; the object path used to
   return `.delta` unconditionally, so a real SDK install could
   leak tool output into the visible chat reply.

4. `_ScrubbedEnvAsyncCodex` is now process-wide concurrency-safe
   AND fails-closed if the SDK constructor raises:
   - Refcount each scrubbed key under an `asyncio.Lock` so a fan-out
     wrapper that exits early cannot restore a secret while another
     wrapper is still inside SDK startup (round 6 reproduced this:
     wrapper A exited, wrapper B's SDK saw the restored HF_TOKEN).
   - Move `_async_codex_cls()` and its `__aenter__` INSIDE a
     try/except in `__aenter__`; on failure, run the release path
     so the scrubbed env vars are restored even though `__aexit__`
     never fires for the failed construction.

5. `_run_cli` now detaches into its own process group via
   `start_new_session=True` (Unix) / `CREATE_NEW_PROCESS_GROUP`
   (Windows) and kills the whole group on timeout, matching the
   protected path in `stream_codex_device_login`. A shimmed
   `codex login status` that forks a helper and blocks no longer
   leaves the child running after we killed the parent.

Frontend follow-up: chat-adapter now routes every rendered yield
through a `renderFullContent()` helper so the Codex per-tab text
accumulated in earlier `_toolEvent` frames is preserved when the
synthesis content delta arrives. Previously the next regular
content yield rebuilt `parts` from `cumulativeText` alone and the
tab section vanished from the final assistant message.

Tests: 49 cases total (was 47). New regressions:
- `installed_requires_both_cli_and_sdk` (round 6 revert).
- `safety_kwargs_finds_sandbox_mode_in_submodule` (canonical SDK
  layout where `SandboxMode` is in `.generated.v2_all`).
- `scrubbed_env_construction_failure_restores_env` (no permanent
  env leak when the SDK constructor raises).
- Expanded `coerce_text_drops_non_answer_event_types` to also
  exercise the object-shape code path with `CommandExecutionOutputDelta`,
  `FileChangeDelta`, `ToolCallDelta`, `PatchApplyDelta`,
  `PlanUpdateDelta`, `AgentReasoningDelta`, plus the
  positive `AgentMessageDelta` allow-through.
2026-05-24 17:30:01 +00:00
..
public Polish/cloud to providers (#5450) 2026-05-15 19:29:21 +04:00
src Studio: round 6 Codex hardening (5 follow-ups) 2026-05-24 17:30:01 +00:00
.gitignore perf(studio): upgrade to Vite 8 + auto-install bun for faster frontend builds (#4522) 2026-03-25 04:27:41 -07:00
.gitkeep add studio root folder 2026-02-02 09:14:35 +00:00
.npmrc security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
biome.json feat: add seed dataset support with configuration, preview, and builder utilities 2026-02-14 18:44:38 +01:00
components.json add studio root folder 2026-02-02 09:14:35 +00:00
data-designer.openapi (1).yaml save and import, and fixes 2026-02-04 14:32:49 +01:00
eslint.config.js Final cleanup 2026-03-12 18:28:04 +00:00
index.html Final cleanup 2026-03-12 18:28:04 +00:00
package-lock.json Add OpenDocument chat attachments (#5510) 2026-05-18 03:41:24 -07:00
package.json Add OpenDocument chat attachments (#5510) 2026-05-18 03:41:24 -07:00
tsconfig.app.json Relax frontend unused local check (#4388) 2026-03-17 16:04:11 -07:00
tsconfig.json cleanup 2026-02-04 13:28:39 +01:00
tsconfig.node.json cleanup 2026-02-04 13:28:39 +01:00
vite.config.ts Fix Install commands for Windows + 1 line installs (#4447) 2026-03-19 02:09:09 -07:00