From 33fa720392abf01d7ba455449b93f68194f0626f Mon Sep 17 00:00:00 2001 From: Vri6500 Date: Sun, 26 Jul 2026 02:50:12 -0400 Subject: [PATCH] fix: extend bundled advisor MCP timeout --- CHANGELOG.md | 8 ++++++- .../.codex-plugin/plugin.json | 2 +- plugins/codex-orchestration/.mcp.json | 3 +++ .../skills/codex-orchestration/SKILL.md | 6 +++++ .../scripts/configure_native_routing.py | 2 +- tests/plugin_lifecycle_smoke.py | 2 +- tests/test_packaging.py | 23 ++++++++++++++++--- tests/test_release_check.py | 2 +- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e239a..3a78e35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## 0.9.3 — Unreleased +## 0.9.4 — Unreleased + +- Give every bundled Claude MCP launcher a 660-second Codex tool timeout so + Opus 5 XHigh reviews can use the bridge's full 600-second subprocess budget + and still return a schema-validated decision or fail-closed timeout result. + +## 0.9.3 — 2026-07-26 - Raise the bounded Advisor approval loop from five to eight reviews while preserving immediate approval exit and fail-closed plan, ledger, and diff --git a/plugins/codex-orchestration/.codex-plugin/plugin.json b/plugins/codex-orchestration/.codex-plugin/plugin.json index 9986c84..0d7c157 100644 --- a/plugins/codex-orchestration/.codex-plugin/plugin.json +++ b/plugins/codex-orchestration/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "codex-orchestration", - "version": "0.9.3", + "version": "0.9.4", "description": "Give Codex and audited external models safe, provider-pinned roles.", "author": { "name": "CJ Zafir", diff --git a/plugins/codex-orchestration/.mcp.json b/plugins/codex-orchestration/.mcp.json index f84f66d..3e13d8b 100644 --- a/plugins/codex-orchestration/.mcp.json +++ b/plugins/codex-orchestration/.mcp.json @@ -6,6 +6,7 @@ "skills/codex-orchestration/scripts/fable_advisor_mcp.py" ], "cwd": ".", + "tool_timeout_sec": 660, "enabled": false }, "fable-advisor-python": { @@ -14,6 +15,7 @@ "skills/codex-orchestration/scripts/fable_advisor_mcp.py" ], "cwd": ".", + "tool_timeout_sec": 660, "enabled": false }, "fable-advisor-py": { @@ -23,6 +25,7 @@ "skills/codex-orchestration/scripts/fable_advisor_mcp.py" ], "cwd": ".", + "tool_timeout_sec": 660, "enabled": false } } diff --git a/plugins/codex-orchestration/skills/codex-orchestration/SKILL.md b/plugins/codex-orchestration/skills/codex-orchestration/SKILL.md index 46e5fe5..67cc235 100644 --- a/plugins/codex-orchestration/skills/codex-orchestration/SKILL.md +++ b/plugins/codex-orchestration/skills/codex-orchestration/SKILL.md @@ -476,6 +476,12 @@ Prerequisites: The plugin packages three disabled MCP launcher variants for macOS, Linux, and Windows. Setup enables exactly one compatible variant through the plugin's namespaced config when either bundled Claude model is selected. At planning or review time the MCP server gives authentication and model subprocesses only a minimal platform environment. It preserves `HOME` plus canonical operating-system `USER` and `LOGNAME` on POSIX, or `USERPROFILE` on Windows, for first-party login discovery. It does not trust ambient POSIX identity values and does not inherit credential, config-redirection, provider/model/effort, endpoint/gateway, proxy/CA/mTLS, or telemetry override families. It invokes `claude --print --model ` with `--safe-mode`, no tools, no session persistence, prompt suggestions disabled, and JSON output. Advisor review additionally requires Claude Code's `--json-schema` capability. Each saved seat pins its model and effort; the root cannot replace them through tool arguments. +Each bundled launcher gives Codex a 660-second MCP tool timeout, slightly longer +than the bridge's 600-second Claude subprocess timeout. Keep the outer timeout +strictly greater than the inner timeout so an XHigh call can return either its +schema-validated result or the bridge's fail-closed timeout error instead of being +cancelled first by Codex's shorter default. + Fable effort is configurable per setup. The default is `high`; supported Claude Code values are `low`, `medium`, `high`, `xhigh`, and `max`. Accept `ultra` as an alias for `max`, save the effective Claude Code value, and disclose the alias mapping in setup output. Existing saved `max` routes remain valid. Opus effort is also configurable and defaults to `high`. Its sealed set is diff --git a/plugins/codex-orchestration/skills/codex-orchestration/scripts/configure_native_routing.py b/plugins/codex-orchestration/skills/codex-orchestration/scripts/configure_native_routing.py index 6993e69..055c0d0 100644 --- a/plugins/codex-orchestration/skills/codex-orchestration/scripts/configure_native_routing.py +++ b/plugins/codex-orchestration/skills/codex-orchestration/scripts/configure_native_routing.py @@ -457,7 +457,7 @@ def __init__( "clientInfo": { "name": "codex_orchestration_installer", "title": "Codex Orchestration Installer", - "version": "0.9.3", + "version": "0.9.4", }, "capabilities": {"experimentalApi": True}, }, diff --git a/tests/plugin_lifecycle_smoke.py b/tests/plugin_lifecycle_smoke.py index d1fbaa9..9d46465 100755 --- a/tests/plugin_lifecycle_smoke.py +++ b/tests/plugin_lifecycle_smoke.py @@ -32,7 +32,7 @@ MARKETPLACE_NAME = "codex-orchestration" OLD_RELEASE = "a1d9c546665c3253cdcaa8fe5c0c060199a6126c" OLD_VERSION = "0.5.0" -NEW_VERSION = "0.9.3" +NEW_VERSION = "0.9.4" COMMAND_TIMEOUT_SECONDS = 60 diff --git a/tests/test_packaging.py b/tests/test_packaging.py index 61a18f7..177f065 100644 --- a/tests/test_packaging.py +++ b/tests/test_packaging.py @@ -255,7 +255,7 @@ def test_plugin_marketplace_and_skill_names_are_aligned(self) -> None: self.assertEqual(manifest["name"], "codex-orchestration") self.assertEqual(manifest["skills"], "./skills/") - self.assertEqual(manifest["version"], "0.9.3") + self.assertEqual(manifest["version"], "0.9.4") self.assertEqual(manifest["mcpServers"], "./.mcp.json") self.assertRegex( manifest["version"], @@ -278,7 +278,7 @@ def test_native_and_custom_configurators_are_packaged(self) -> None: self.assertFalse((SKILL_ROOT / "scripts" / "update_plugin.py").exists()) self.assertIn("config/batchWrite", native.read_text(encoding="utf-8")) self.assertIn('"--repair"', native.read_text(encoding="utf-8")) - self.assertIn('"version": "0.9.3"', native.read_text(encoding="utf-8")) + self.assertIn('"version": "0.9.4"', native.read_text(encoding="utf-8")) self.assertIn("validate_routing_state", routing_state.read_text(encoding="utf-8")) self.assertIn("Standalone custom agent", custom.read_text(encoding="utf-8")) @@ -332,7 +332,24 @@ def test_fable_mcp_is_packaged_and_disabled_until_selected(self) -> None: for server in servers.values(): self.assertFalse(server["enabled"]) self.assertEqual(server["cwd"], ".") + self.assertEqual(server["tool_timeout_sec"], 660) self.assertIn("fable_advisor_mcp.py", server["args"][-1]) + bridge = ( + SKILL_ROOT / "scripts" / "fable_advisor_mcp.py" + ).read_text(encoding="utf-8") + timeout_match = re.search( + r"(?m)^CLAUDE_TIMEOUT_SECONDS\s*=\s*(\d+)$", + bridge, + ) + self.assertIsNotNone(timeout_match) + assert timeout_match is not None + bridge_timeout = int(timeout_match.group(1)) + self.assertTrue( + all( + server["tool_timeout_sec"] > bridge_timeout + for server in servers.values() + ) + ) self.assertTrue((SKILL_ROOT / "scripts" / "fable_advisor_mcp.py").is_file()) def test_explicit_and_natural_language_invocation_metadata_is_consistent(self) -> None: @@ -453,7 +470,7 @@ def test_ci_runs_dual_version_plugin_lifecycle(self) -> None: self.assertIn("@openai/codex@0.144.1", workflow) smoke_text = smoke.read_text(encoding="utf-8") self.assertIn('OLD_VERSION = "0.5.0"', smoke_text) - self.assertIn('NEW_VERSION = "0.9.3"', smoke_text) + self.assertIn('NEW_VERSION = "0.9.4"', smoke_text) self.assertIn("old Advisor-only cache unexpectedly supports Planner", smoke_text) self.assertIn("Upgraded installed skill is missing Planner contract", smoke_text) self.assertIn("reused the Advisor-only 0.5.0 cache directory", smoke_text) diff --git a/tests/test_release_check.py b/tests/test_release_check.py index fdad956..75129fd 100644 --- a/tests/test_release_check.py +++ b/tests/test_release_check.py @@ -69,7 +69,7 @@ def commit(self, message: str) -> str: class ReleaseCheckTests(unittest.TestCase): def test_checkout_release_metadata_is_consistent(self) -> None: - self.assertEqual(RELEASE.run_check(REPO_ROOT, require_tag=False), "0.9.3") + self.assertEqual(RELEASE.run_check(REPO_ROOT, require_tag=False), "0.9.4") def test_unreleased_checkout_is_not_tag_ready(self) -> None: with self.assertRaisesRegex(RELEASE.ReleaseCheckError, "not tagged"):