Skip to content

Commit c6b9fc3

Browse files
shuvebclaude
andcommitted
Fix TUI Ralph using cached API client for completion verification
The TUI passed its cached APIClient to the Ralph orchestrator, causing verify_feature_completed to return stale responses. Feature status mutated externally by the coding agent via MCP was invisible to the cached client, leading to false retry loops. Create a separate uncached client for the orchestrator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dbd60e2 commit c6b9fc3

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "mfbt-cli"
7-
version = "0.1.7"
7+
version = "0.1.8"
88
description = "CLI tool for the mfbt platform — interactive TUI and subcommands for managing mfbt projects"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/mfbt/tui/screens/ralph_panel.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(
5656
self._config = config
5757
self._phase_id = phase_id
5858
self._orchestrator: Any = None
59+
self._orchestrator_client: APIClient | None = None
5960
self._ralph_config: Any = None
6061
self._phases_progress: dict[str, dict] = {}
6162
self._orphan_modules: list[dict[str, Any]] = []
@@ -373,6 +374,12 @@ def stop(self) -> None:
373374
self._orchestrator.stop()
374375
except Exception:
375376
pass
377+
if self._orchestrator_client is not None:
378+
try:
379+
self._orchestrator_client.close()
380+
except Exception:
381+
pass
382+
self._orchestrator_client = None
376383

377384
def pause_orchestrator(self) -> None:
378385
"""Show pause modal — lets user continue or stop the orchestration loop."""
@@ -509,7 +516,7 @@ def _run_single_retry(
509516
from mfbt.commands.ralph.progress import resolve_feature_task
510517
from mfbt.commands.ralph.types import FeatureOutcome
511518

512-
feature = resolve_feature_task(self._api_client, feature_info)
519+
feature = resolve_feature_task(self._orchestrator_client, feature_info)
513520
if feature is None:
514521
def _notify_error() -> None:
515522
self.app.notify(
@@ -655,6 +662,29 @@ def _glisten_tick(self) -> None:
655662
except Exception:
656663
pass
657664

665+
def _build_uncached_client(self) -> APIClient:
666+
"""Create an APIClient without response caching for the orchestrator.
667+
668+
The orchestrator needs fresh API responses (especially for
669+
verify_feature_completed) because feature status is mutated
670+
externally by the coding agent via MCP.
671+
"""
672+
from mfbt.api_client import APIClient
673+
from mfbt.auth_flow import run_interactive_auth
674+
from mfbt.token_manager import TokenManager
675+
676+
base_url = self._config.get("base_url", "https://app.mfbt.ai")
677+
tm = TokenManager(base_url)
678+
679+
def _on_auth_required() -> bool:
680+
from rich.console import Console
681+
682+
c = Console()
683+
c.print("\n[yellow]Session expired. Re-authenticating...[/yellow]")
684+
return run_interactive_auth(base_url, tm, c)
685+
686+
return APIClient(base_url, tm, cache=None, on_auth_required=_on_auth_required)
687+
658688
def _run_orchestrator(self) -> None:
659689
"""Run the orchestrator in a worker thread."""
660690
from mfbt.commands.ralph.log_capture import RalphLogger
@@ -668,7 +698,8 @@ def _run_orchestrator(self) -> None:
668698
log_base_dir, self._ralph_config.coding_agent
669699
)
670700

701+
self._orchestrator_client = self._build_uncached_client()
671702
self._orchestrator = RalphOrchestrator(
672-
self._ralph_config, self._api_client, display, logger=ralph_logger
703+
self._ralph_config, self._orchestrator_client, display, logger=ralph_logger
673704
)
674705
self._orchestrator.run()

0 commit comments

Comments
 (0)