feat(cli): show sandbox provider in header sub_title (#3295)

Closes #2304      

---
Auto-populate `sub_title` with the active sandbox provider name (e.g.
`"Sandbox: Daytona"`) so the optional header bar indicates which sandbox
is in use. Display names use proper casing via a lookup dict, with a
`.title()` fallback for unrecognised providers. An explicitly passed
`sub_title` takes precedence over the auto-detected value.

Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
yuvrxj-afk
2026-05-11 09:06:12 +05:30
committed by GitHub
parent 07a973ae5b
commit 779f7f45c5
2 changed files with 52 additions and 0 deletions
+15
View File
@@ -888,6 +888,15 @@ _COMMAND_URLS: dict[str, str] = {
}
"""Slash-command to URL mapping for commands that just open a browser."""
_SANDBOX_DISPLAY_NAMES: dict[str, str] = {
"agentcore": "AgentCore",
"daytona": "Daytona",
"langsmith": "LangSmith",
"modal": "Modal",
"runloop": "Runloop",
}
"""Human-readable display names for sandbox providers."""
_toast_internals_warned: list[bool] = [False]
"""Single-slot flag; once `_Toast._notification` is missing, log warning once.
@@ -1315,6 +1324,12 @@ class DeepAgentsApp(App):
self._sandbox_type: str | None = raw if raw and raw != "none" else None
"""Normalized sandbox type (or `None`), attached to trace metadata."""
if sub_title is None and self._sandbox_type is not None:
display = _SANDBOX_DISPLAY_NAMES.get(
self._sandbox_type, self._sandbox_type.title()
)
self.sub_title = f"Sandbox: {display}"
# Per-turn model overrides
self._model_override: str | None = None
"""Per-turn model override set via `/model`; `None` uses session default."""
+37
View File
@@ -7717,6 +7717,43 @@ class TestHeaderAndTitle:
assert not app.query(Header)
class TestSandboxSubTitle:
"""sub_title reflects the active sandbox provider."""
async def test_sandbox_sets_sub_title(self) -> None:
"""When a sandbox is active, sub_title shows the provider name."""
app = DeepAgentsApp(server_kwargs={"sandbox_type": "daytona"})
assert app.sub_title == "Sandbox: Daytona"
async def test_sandbox_sub_title_proper_casing(self) -> None:
"""Provider display names use proper casing."""
app = DeepAgentsApp(server_kwargs={"sandbox_type": "langsmith"})
assert app.sub_title == "Sandbox: LangSmith"
app2 = DeepAgentsApp(server_kwargs={"sandbox_type": "agentcore"})
assert app2.sub_title == "Sandbox: AgentCore"
async def test_explicit_sub_title_overrides_sandbox(self) -> None:
"""An explicitly passed sub_title is not overwritten by sandbox info."""
app = DeepAgentsApp(sub_title="custom", server_kwargs={"sandbox_type": "modal"})
assert app.sub_title == "custom"
async def test_no_sandbox_leaves_sub_title_default(self) -> None:
"""Without a sandbox, sub_title remains at its Textual default."""
app = DeepAgentsApp()
assert app.sub_title == ""
async def test_sandbox_none_does_not_set_sub_title(self) -> None:
"""The argparse default `'none'` is treated as no sandbox."""
app = DeepAgentsApp(server_kwargs={"sandbox_type": "none"})
assert app.sub_title == ""
async def test_unknown_provider_uses_title_case_fallback(self) -> None:
"""An unrecognized provider falls back to `.title()` casing."""
app = DeepAgentsApp(server_kwargs={"sandbox_type": "kubernetes"})
assert app.sub_title == "Sandbox: Kubernetes"
class TestHandleExternalSignal:
"""Verify routing of `kind=signal` external events."""