Skip to content

feat: three-state base_url semantics for runtime config switching - #565

Merged
delete-cloud merged 4 commits into
mainfrom
feat/runtime-config-three-state
Jun 11, 2026
Merged

delete-cloud merged 4 commits into
mainfrom
feat/runtime-config-three-state

Conversation

@delete-cloud

@delete-cloud delete-cloud commented Jun 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

Follow-up to #563/#564. base_url handling across the runtime-config switching stack was two-state (None = keep), which meant a session's base_url could never be cleared back to the provider default once set. This PR introduces three-state semantics end to end:

  • omitted / UNSET — keep the session's current value
  • explicit null / None — reset to the provider default
  • value — set it

Core (coding_agent/runs)

  • New UNSET sentinel in replacement.py, threaded through RuntimeReplacementService, LocalDaemonRuntimePreparationService, SessionManager.replace_session_runtime_config, and the local CLI session-manager protocol.
  • Checkpoint restore is unaffected (it uses its own base_url_override path).

HTTP (PATCH /sessions/{id}/runtime-config)

  • model_fields_set distinguishes omitted fields from explicit null.
  • base_url: null resets to provider default; null for model/provider/thinking is rejected with 422 (no meaningful reset target); empty body still 400.

ACP (session/set_mode)

  • Modes are now declarative for endpoints: a mode that names a provider fully describes its config, so an omitted base_url resets to the provider default instead of leaking the previous mode's endpoint onto the new provider. Model-only modes keep the current endpoint.

Test repairs in touched areas

Tests

  • tests/coding_agent/test_runtime_replacement_service.py — 5 passed (new: clear, rollback-after-clear)
  • tests/coding_agent/test_runtime_config_schema.py — new, 6 passed
  • tests/acp — 63 passed (was 3 pre-existing failures)
  • tests/cli/test_repl.py — 53 passed (was 2 pre-existing failures)
  • Full touched-area sweep (tests/coding_agent tests/cli tests/acp tests/ui/test_session_manager_runtime.py): failure-set diff vs main shows exactly 5 failures fixed, 0 introduced (37 → 32; remaining 32 are pre-existing on main).

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

Refactor

  • Enhanced runtime configuration update semantics to distinguish between omitted fields (no change), explicit null values (reset where applicable), and provided values (update configuration).
  • Added validation to reject invalid null values for non-resettable configuration fields.
  • Improved API documentation to clarify three-state configuration behavior.

delete-cloud and others added 4 commits June 12, 2026 01:02
Distinguish "not provided" (UNSET, keep current) from explicit None
(reset to provider default) across the runtime replacement chain:
RuntimeReplacementService, LocalDaemonRuntimePreparationService,
SessionManager.replace_session_runtime_config, and the local CLI
session manager protocol. Previously None was overloaded as "keep",
so a session's base_url could never be cleared back to the provider
default once set.

Verified: tests/coding_agent/test_runtime_replacement_service.py
(5 passed, including new clear + rollback-after-clear cases).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use model_fields_set to distinguish omitted fields from explicit null:
omitted = unchanged, base_url null = reset to provider default, value =
set. Explicit null for model/provider/thinking has no meaningful reset
target and is rejected with 422 via a field validator. Empty body still
returns 400.

Verified: tests/coding_agent/test_runtime_config_schema.py (6 passed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A mode that names a provider now fully describes that provider's
config: an omitted base_url resets to the provider default instead of
leaking the previous mode's endpoint onto the new provider. Model-only
modes (no provider, no base_url) keep the session's current endpoint.

Also updates three stale test assertions that predate the #563 modes
feature (initialize response now advertises modes; unknown-modeId error
message changed) and adds FakeManager.replace_session_runtime_config.

Verified: tests/acp (63 passed, was 3 pre-existing failures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The repl fakes for replace_session_runtime_config and
_build_session_runtime were not updated when #563 added provider_name,
leaving two tests failing on main with TypeError. Widen the fake
signatures to match the real call sites.

Verified: tests/cli/test_repl.py (53 passed, was 2 failures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4319249a-5e98-44dd-a297-d392bce8cba5

📥 Commits

Reviewing files that changed from the base of the PR and between 25b5f60 and 4c90a06.

📒 Files selected for processing (12)
  • coding-agent/src/coding_agent/acp/server.py
  • coding-agent/src/coding_agent/cli/local_runtime.py
  • coding-agent/src/coding_agent/runs/__init__.py
  • coding-agent/src/coding_agent/runs/replacement.py
  • coding-agent/src/coding_agent/runs/runtime_preparation.py
  • coding-agent/src/coding_agent/server/http_server.py
  • coding-agent/src/coding_agent/server/schemas.py
  • coding-agent/src/coding_agent/server/session_manager.py
  • coding-agent/tests/acp/test_server.py
  • coding-agent/tests/cli/test_repl.py
  • coding-agent/tests/coding_agent/test_runtime_config_schema.py
  • coding-agent/tests/coding_agent/test_runtime_replacement_service.py

📝 Walkthrough

Walkthrough

This PR introduces a sentinel-based UNSET type to distinguish "field not provided" from "explicitly set to None" for the base_url parameter across runtime configuration services, HTTP API schema validation, and protocol implementations. The changes propagate from core service definitions through session managers to HTTP endpoint logic.

Changes

Three-State base_url Configuration

Layer / File(s) Summary
Sentinel definition & core replacement logic
coding-agent/src/coding_agent/runs/replacement.py, coding-agent/src/coding_agent/runs/__init__.py
UnsetType class and UNSET sentinel instance are introduced. RuntimeReplacementService.replace_runtime_config and RuntimeReplacementBuilder accept base_url: str | None | UnsetType = UNSET, and session.base_url is only updated when the parameter is not the sentinel. The sentinel is re-exported from the runs package.
Runtime preparation layer
coding-agent/src/coding_agent/runs/runtime_preparation.py
LocalDaemonRuntimePreparationService.build_runtime and _build_runtime_direct adopt the sentinel default and type; the resolved base_url uses session.base_url only when the parameter is UNSET, otherwise the provided value (including explicit None).
Session manager & protocol contracts
coding-agent/src/coding_agent/server/session_manager.py, coding-agent/src/coding_agent/acp/server.py, coding-agent/src/coding_agent/cli/local_runtime.py
SessionManager._build_session_runtime and replace_session_runtime_config, AcpSessionManager.replace_session_runtime_config protocol, and LocalCliSessionManager protocol update their base_url parameter defaults to UNSET and widen the type signature.
ACP mode switching logic
coding-agent/src/coding_agent/acp/server.py
AcpMode docstring clarifies provider/base_url omission behavior. In _session_set_mode, base_url is computed as: the mode's explicit base_url if provided, None if the mode specifies a provider without base_url, or UNSET if neither provider nor base_url are set in the mode.
HTTP API schema & validation
coding-agent/src/coding_agent/server/schemas.py
RuntimeConfigUpdateRequest docstring describes three-state semantics (omitted, explicit null, or value). A field_validator rejects explicit null for model, provider, and thinking but allows null for base_url as a reset operation.
HTTP endpoint implementation
coding-agent/src/coding_agent/server/http_server.py
The PATCH /sessions/{session_id}/runtime-config endpoint uses body.model_fields_set to determine which fields were explicitly provided, rejects requests with no fields set, reworks "thinking-only" detection based on provided fields, and passes base_url=UNSET when base_url was omitted from the request.
ACP integration tests
coding-agent/tests/acp/test_server.py
Test double FakeManager.replace_session_runtime_config records runtime config parameters. Tests verify that provider-mode switching clears base_url to None and model-only mode switching preserves base_url as UNSET. Expected JSON payloads updated.
CLI test doubles
coding-agent/tests/cli/test_repl.py
Test doubles replace_session_runtime_config and _build_session_runtime expand their signatures to accept optional provider_name and base_url parameters (ignored).
Schema validation tests
coding-agent/tests/coding_agent/test_runtime_config_schema.py
New test module validates that omitting fields leaves model_fields_set empty, explicit base_url=None is allowed and recorded, explicit null for non-resettable fields is rejected, and non-null values are accepted and tracked.
Runtime replacement service tests
coding-agent/tests/coding_agent/test_runtime_replacement_service.py
Existing test updated to expect base_url=UNSET and assert session.base_url remains unchanged; new tests verify explicit base_url=None clears the URL and that persistence failures trigger rollback.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • delete-cloud/Coding-Agent-Loop#563: Directly related; this PR refines the runtime-config switching flow introduced in #563 by replacing simple None semantics with the new UNSET tri-state sentinel for more precise omission handling.

Poem

A sentinel marches through the configuration land,
Distinguishing "not set" from None's steady hand, 🐰
Through schemas and modes, it clearly now shows,
What was omitted, reset, or the value that flows. ✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/runtime-config-three-state

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.

@delete-cloud
delete-cloud marked this pull request as ready for review June 11, 2026 17:14
@delete-cloud
delete-cloud merged commit a377960 into main Jun 11, 2026
1 check passed
@delete-cloud
delete-cloud deleted the feat/runtime-config-three-state branch June 11, 2026 17:16
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