Skip to content
Merged
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
2 changes: 1 addition & 1 deletion loopx/capabilities/native_chat/model_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def inspect_agent_model_options(controller: ChatRuntimeController, agent_id: str
if capability is None or not capability.get("available"):
raise agent_endpoint_error(agent_id, reason=str((capability or {}).get("unavailable_reason") or ""))
if agent_id == "codex":
defaults = load_codex_chat_defaults(controller.coordination_runtime_root) if goal_id else {}
defaults = load_codex_chat_defaults(controller.store.root.parent) if goal_id else {}
home = codex_profile_home(controller.codex_home, defaults)
models = providers.codex_model_options(controller.codex_bin, codex_home=home)
if models is None:
Expand Down
2 changes: 1 addition & 1 deletion loopx/chat_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ def open_session(
if (agent_id == "codex" and goal_id != MANAGER_AGENT_GOAL_ID
and conversation_scope(selected_scope)["kind"] == "owner_goal"
and not (latest and (latest.get("active_turn_id") or latest.get("upstream_mode") == CODEX_GOAL_CHAT_MODE))):
codex_defaults = load_codex_chat_defaults(self.coordination_runtime_root)
codex_defaults = load_codex_chat_defaults(self.store.root.parent)
selected_codex_home = codex_profile_home(self.codex_home, codex_defaults)
if latest is not None and (latest.get("codex_chat_configuration") or {}) != codex_defaults:
# New defaults get a new ordinary Session. Resolve them only
Expand Down
51 changes: 49 additions & 2 deletions tests/test_chat_codex_defaults.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Configured Goal Chat defaults use native settings without retargeting work."""
import json
import os
import subprocess
import sys
Expand Down Expand Up @@ -98,15 +99,15 @@ def start(**kwargs):
runtime.close()


def runtime_fixture(tmp_path, monkeypatch):
def runtime_fixture(tmp_path, monkeypatch, *, registry_path=None):
base, gpt = tmp_path / ".codex-ds", tmp_path / ".codex-gpt"
base.mkdir()
gpt.mkdir()
(gpt / "config.toml").write_text('model = "gpt-6.1-sol"\nmodel_reasoning_effort = "max"\n')
monkeypatch.setenv("LOOPX_CHAT_CODEX_HOME", str(base))
monkeypatch.setenv("LOOPX_CODEX_HOMES", str(gpt))
root = tmp_path / "runtime"
runtime = ChatRuntimeController(store=ChatSessionStore(root), codex_bin="fixture")
runtime = ChatRuntimeController(store=ChatSessionStore(root), registry_path=registry_path, codex_bin="fixture")
monkeypatch.setattr(runtime, "capabilities", lambda: [
{"agent_id": "codex", "available": True, "adapter_kind": "codex_app_server"},
])
Expand Down Expand Up @@ -155,6 +156,52 @@ def test_model_effort_and_speed_are_separate_and_reversible_defaults(tmp_path, m
runtime.close()


def test_goal_codex_defaults_follow_chat_settings_when_coordination_uses_a_separate_root(tmp_path, monkeypatch):
from loopx import chat_providers

coordination = tmp_path / "coordination"
registry = tmp_path / "registry.json"
registry.write_text(
json.dumps({"common_runtime_root": str(coordination), "goals": []}), encoding="utf-8"
)
runtime, root, base, gpt, calls = runtime_fixture(tmp_path, monkeypatch, registry_path=registry)
# These are two different valid stores, so a mistaken fallback also fails
# the test when both contain preferences.
configure(coordination, model="other-model", reasoning_effort="low", service_tier="flex")
original_coordination = read_machine_configuration(
coordination, registry=build_builtin_machine_configuration_registry()
)
configure(root, codex_profile="codex-gpt", model="gpt-6.1-sol", reasoning_effort="high", service_tier="fast")
discovered = []

def catalog(_binary, *, codex_home):
discovered.append(codex_home)
return {"options": [{"value": "gpt-6.1-sol", "reasoning_efforts": ["high"]}]}

monkeypatch.setattr(chat_providers, "codex_model_options", catalog)
open_args = dict(goal_id="fixture", agent_id="codex", work_dir=tmp_path, objective="Inspect.")
try:
assert runtime.coordination_runtime_root == coordination
runtime.inspect_agent_model_options("codex", work_dir=tmp_path, goal_id="fixture")
selected, reused = runtime.open_session(**open_args, mode="new")
assert not reused and discovered == [gpt]
assert calls[-1]["codex_home_override"] == gpt
assert (selected["agent_model_id"], selected["agent_reasoning_effort"], selected["agent_service_tier"]) == (
"gpt-6.1-sol", "high", "fast"
)
configure(root)
runtime.inspect_agent_model_options("codex", work_dir=tmp_path, goal_id="fixture")
cleared, _ = runtime.open_session(**open_args, mode="new")
assert discovered == [gpt, base]
assert cleared["agent_model_id"] == "inherited-model"
assert runtime.store.load_session(selected["session_id"])["codex_home"] == str(gpt)
assert read_machine_configuration(
coordination, registry=build_builtin_machine_configuration_registry()
) == original_coordination
finally:
runtime.close()


def test_new_defaults_do_not_replace_an_active_turn_or_its_native_home(tmp_path, monkeypatch):
runtime, root, base, _gpt, calls = runtime_fixture(tmp_path, monkeypatch)
args = dict(goal_id="fixture", agent_id="codex", work_dir=tmp_path, objective="Inspect.")
Expand Down
Loading