Skip to content

[AIGTWY-4881] Keep Codex's managed default model when ug saves state - #1010

Merged
david-siqi-liu merged 1 commit into
mainfrom
david/aigtwy-4881-codex-default-model
Oct 6, 2026
Merged

david-siqi-liu merged 1 commit into
mainfrom
david/aigtwy-4881-codex-default-model

Conversation

@david-siqi-liu

Copy link
Copy Markdown
Collaborator

Standalone extract of the default_model part of #921, so CUJ 6 (#987) isn't blocked on the provenance stack.

codex.default_model() called clear_model_preferences when there was no managed default in the state it was given. ug configure writes Codex's managed model, then save_state -> hydrate_state (without the managed overlay) -> default_model_for_tool -> codex.default_model() deleted it again. Codex then started on whatever model the gateway listed first instead of the admin's default. The live CUJ 6 run reproduced this: with a UC-location config, Codex served codex_extra instead of the managed default codex_primary.

Changes:

  • src/ucode/agents/codex.py: default_model() no longer calls clear_model_preferences, so looking up the default never rewrites config. The launch path still calls it, so a stale model ug pinned is still retired at launch.
  • tests/test_agent_codex.py: the test that asserted the lookup cleared model and model_reasoning_effort now asserts it leaves the config byte-for-byte unchanged (the same flip [AIGTWY-4901] Only remove a Codex model ug wrote #921 makes).

#921 still carries the broader provenance-based fix. When it lands, it supersedes this line with no conflict in intent.

Validation: ruff check and ruff format --check pass. Full pytest: 3201 passed; the only 2 failures are test_e2e_user_agent, which needs a live gateway and also fails locally on main. The updated test fails without the fix.

This pull request and its description were written by Isaac.

`codex.default_model()` called `clear_model_preferences`, so any state hydrate
without the managed overlay (for example `save_state` right after
`write_tool_config`) deleted the `model` ug had just written. Codex then
started on whatever the gateway listed first instead of the admin's default.
Looking up the default no longer rewrites config; launch still clears a stale
pinned model.

Co-authored-by: Isaac <no-reply@databricks.com>
david-siqi-liu added a commit that referenced this pull request Oct 6, 2026
@david-siqi-liu
david-siqi-liu marked this pull request as ready for review October 6, 2026 16:32
@david-siqi-liu david-siqi-liu added the ug-review Run the automated UG review label Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

UG review

Reviewed the removal of configuration writes from Codex default-model lookup and the updated regression test, focusing on preserving managed model preferences during state saves. No actionable issues are evident in the supplied diff.

No actionable findings.

Automated advisory review of 036008149997 using Lilly's UG review rubric. It does not approve or block this PR.

@david-siqi-liu
david-siqi-liu added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit 4c1b866 Oct 6, 2026
31 checks passed
@david-siqi-liu
david-siqi-liu deleted the david/aigtwy-4881-codex-default-model branch October 6, 2026 17:35
xsh310 pushed a commit to xsh310/ucode that referenced this pull request Oct 7, 2026
CUJ 6 (AIGTWY-4881, epic AIGTWY-4875) checks that a developer who
receives successive admin configs ends up with exactly the latest one:
no stale ug-managed values, and their own settings untouched. It runs
live on main's dedicated-workspace CUJ framework (databricks#1000) with the TUI
request recorder (databricks#994), against the CUJ 6 plan in the [UG Configure E2E
doc](https://docs.google.com/document/d/1WKd1fdWD0Y4tAV1H9Si-SGx2UZFL7iZ2S3HtBjidmS0/edit).

Workspace configs are read only, because parallel CI jobs share them.
Each phase is the single published config of its own pre-provisioned
workspace, and one shared home moves through them:
- A: `dbc-8c38ce9b-634b`, CUJ 1's config plus the named MCP
`ug_e2e.tools.fixture_reader`
- B: `dbc-175bc4a3-a511`, Claude on the Bedrock MPS
`ug_e2e.providers.bedrock`, Codex on UC discovery `ug_e2e.models`, Codex
as the default agent
- C: `dbc-998133ab-de86`, Codex only, on the static list
`system.ai.gpt-5-6-luna`

All three share one metastore, the `ug_e2e` fixtures, and one trace
table. The test never writes workspace config; it checks each published
config against the plan at the start and asserts it is unchanged at
teardown. A to B to C also exercises ug's cross-workspace switch.

Builds on databricks#1010 (merged), and on databricks#1004 (merged), whose
`workspace_origin` keeps the TUI request recorder's
`http://127.0.0.1:<port>` origin for the workspace API calls CUJ 6
routes through it.

Changes:
- `tests/e2e_cuj/test_cuj_repeated_config.py`: one class, phases as
ordered class-scoped fixtures (`phase_a` -> `phase_b` -> `phase_c`)
returning frozen evidence, 28 small tests on top.
- Setup: seeds user-owned Claude and Codex prefs, a user stdio MCP, and
a hand-written skill, with no ug state.
- Readback: each phase workspace publishes exactly the plan's config
(agents, model sources, defaults, headers, tracing, MCP selector).
- Phase A: configures twice; identical settings and registrations, no
duplicates; both agents complete a task with their phase headers and
default models at gateway ingress (recorder) and in the native turn.
- Phase B: Claude carries `databricks-model-provider-service` and no
Phase A headers; Codex carries `databricks-model-service-parent-schema`
and only the Phase B header; request and turn models match the sources.
Bare `ug` in a real terminal launches Codex and completes a task on
`ug_e2e.models.codex_primary`, and writes the Phase B header into
`/etc/codex/managed_config.toml`. Static picker, family defaults,
tracing keys, static Codex catalog, and the managed MCP are gone and
stay gone after launches. Codex emits a span; Claude emits none.
- Phase C: configures in a terminal (Phase B's terminal launch made ug
own the machine-wide files) and clears Phase B's headers from `/etc`.
Codex requests carry no Phase B headers, the picker is exactly Luna,
Codex and bare `ug` both run Luna, `ug claude` is rejected with no
inference request, and no Codex span is emitted while the Phase B span
proves the trace query works.
- Every phase: user prefs, MCP registrations, and skill files are
unchanged, and each agent's registered user MCP still starts and lists
its tool.
- `tests/e2e_cuj/helpers/constants.py`: the CUJ 6 metastore fixtures.
The Claude tracing keys come from
`ucode.agents.claude.CLAUDE_OTEL_TRACE_ENV_KEYS`.
- `tests/e2e_cuj/helpers/tui_request_recorder.py`: `retarget_session` is
public so a terminal configure can be retargeted to the recorder.

Known gaps (tracked in AIGTWY-4972):
- Managed skills are not covered: UC skill bundles can't be uploaded on
these workspaces' Default Storage catalog (Files API HTTP 501).

Validation: ruff check and format pass; related unit tests pass. Live:
`E2E CUJs` on this head passed 48 tests (CUJ 6's 28, plus CUJ 1, 2, 4,
and 5) in 11m36s:
https://github.com/databricks/unity-gateway/actions/runs/37567899055/job/112619786676

This pull request and its description were written by Isaac.

Co-authored-by: Isaac <no-reply@databricks.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ug-review Run the automated UG review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants