refactor(agent): use agent-neutral runtime names

Assisted-by: Codex
This commit is contained in:
2026-05-28 17:59:24 -04:00
parent c08b09dc9f
commit 1cbedc91c0
23 changed files with 200 additions and 191 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ container that mimics the agent's name + filesystem layout (PRD 0016).
The real `cli.py start <agent>` flow is too heavy for an integration
test (it builds the agent image, brings up all the sidecars, attaches
an interactive claude session). Instead, this test stages the
an interactive agent session). Instead, this test stages the
minimum the orchestrator interacts with:
- A lightweight `alpine:latest sleep infinity` container named
+5 -5
View File
@@ -1,7 +1,7 @@
"""Unit: cli/start.py session-end state capture (crash preservation).
The launch-context machinery is covered by integration; this isolates
the post-exec_claude decision: snapshot transcript + mark for
the post-exec_agent decision: snapshot transcript + mark for
preservation if non-zero exit, no-op for clean exit."""
import tempfile
@@ -45,25 +45,25 @@ class TestCaptureSessionState(_FakeHomeMixin, unittest.TestCase):
self._teardown_fake_home()
def test_clean_exit_snapshots_but_does_not_mark(self):
start_mod.capture_session_state("dev-abc", exit_code=0)
start_mod.capture_claude_session_state("dev-abc", exit_code=0)
self.assertEqual(["dev-abc"], self._snap_calls)
self.assertFalse(bottle_state.is_preserved("dev-abc"))
def test_crash_snapshots_and_marks(self):
start_mod.capture_session_state("dev-abc", exit_code=137)
start_mod.capture_claude_session_state("dev-abc", exit_code=137)
self.assertEqual(["dev-abc"], self._snap_calls)
self.assertTrue(bottle_state.is_preserved("dev-abc"))
def test_ctrl_c_treated_as_crash(self):
# SIGINT delivers exit 130; the operator may have Ctrl-C'd
# because something went wrong, so we preserve.
start_mod.capture_session_state("dev-abc", exit_code=130)
start_mod.capture_claude_session_state("dev-abc", exit_code=130)
self.assertTrue(bottle_state.is_preserved("dev-abc"))
def test_empty_identity_is_noop(self):
# Backends without an identity field shouldn't crash this
# path (the _identity_from_plan helper falls back to "").
start_mod.capture_session_state("", exit_code=137)
start_mod.capture_claude_session_state("", exit_code=137)
self.assertEqual([], self._snap_calls)
+5 -5
View File
@@ -369,24 +369,24 @@ class TestResumeArgvWithFallback(unittest.TestCase):
class TestClaudeRuntimeArgs(unittest.TestCase):
"""The argv passed to `bottle.claude_argv` on each
"""The argv passed to `bottle.agent_argv` on each
attach. Locked here so the tmux + foreground paths build
identical claude invocations."""
identical agent invocations."""
def test_default_skip_permissions_only(self):
self.assertEqual(
["--dangerously-skip-permissions"],
dashboard._claude_runtime_args(resume=False),
dashboard._agent_runtime_args(resume=False),
)
def test_resume_appends_continue(self):
self.assertEqual(
["--dangerously-skip-permissions", "--continue"],
dashboard._claude_runtime_args(resume=True),
dashboard._agent_runtime_args(resume=True),
)
def test_remote_control(self):
args = dashboard._claude_runtime_args(
args = dashboard._agent_runtime_args(
resume=False, remote_control=True,
)
self.assertIn("--remote-control", args)
+15 -15
View File
@@ -1,6 +1,6 @@
"""Unit: DockerBottle's argv builder (PRD 0021 chunk 1).
`claude_argv` is the pure helper that `exec_claude` and the
`agent_argv` is the pure helper that `exec_agent` and the
PRD-0021 tmux helpers both build on. It encodes two non-trivial
rules — the optional `--append-system-prompt-file` flag and the
optional `-it` for TTY mode — that we lock down here so the tmux
@@ -28,20 +28,20 @@ def _codex_bottle(prompt_path: str | None = None) -> DockerBottle:
teardown=lambda: None,
prompt_path_in_container=prompt_path,
agent_command="codex",
agent_prompt_mode="codex_read_prompt_file",
agent_prompt_mode="read_prompt_file",
)
class TestClaudeArgv(unittest.TestCase):
def test_minimal_argv_no_prompt(self):
argv = _bottle().claude_argv([])
argv = _bottle().agent_argv([])
self.assertEqual(
["docker", "exec", "-it", "bot-bottle-dev-abc", "claude"],
argv,
)
def test_appends_passed_args_after_claude(self):
argv = _bottle().claude_argv(
argv = _bottle().agent_argv(
["--dangerously-skip-permissions", "--continue"],
)
self.assertEqual(
@@ -51,7 +51,7 @@ class TestClaudeArgv(unittest.TestCase):
)
def test_appends_prompt_file_flag_when_set(self):
argv = _bottle("/home/node/.bot-bottle-prompt.txt").claude_argv(
argv = _bottle("/home/node/.bot-bottle-prompt.txt").agent_argv(
["--dangerously-skip-permissions"],
)
self.assertEqual(
@@ -63,34 +63,34 @@ class TestClaudeArgv(unittest.TestCase):
)
def test_no_prompt_flag_when_none(self):
argv = _bottle(None).claude_argv(["--continue"])
argv = _bottle(None).agent_argv(["--continue"])
self.assertNotIn("--append-system-prompt-file", argv)
def test_empty_prompt_string_is_treated_as_no_prompt(self):
# Matches the existing exec_claude behavior: falsy
# Matches the existing exec_agent behavior: falsy
# prompt_path means "skip the flag." The synth path in
# dashboard.py relies on this when metadata is missing.
argv = _bottle("").claude_argv(["--continue"])
argv = _bottle("").agent_argv(["--continue"])
self.assertNotIn("--append-system-prompt-file", argv)
def test_tty_false_drops_it_flag(self):
argv = _bottle().claude_argv([], tty=False)
argv = _bottle().agent_argv([], tty=False)
self.assertEqual(
["docker", "exec", "bot-bottle-dev-abc", "claude"],
argv,
)
def test_caller_argv_not_mutated(self):
# `claude_argv` builds `full_argv` from a copy, so a
# `agent_argv` builds `full_argv` from a copy, so a
# caller passing a long-lived list (e.g., the dashboard's
# _claude_args fixture) doesn't get extra flags appended to
# _agent_args fixture) doesn't get extra flags appended to
# it on subsequent calls.
original = ["--continue"]
_bottle("/x").claude_argv(original)
_bottle("/x").agent_argv(original)
self.assertEqual(["--continue"], original)
def test_codex_provider_uses_codex_command(self):
argv = _codex_bottle().claude_argv(
argv = _codex_bottle().agent_argv(
["--dangerously-bypass-approvals-and-sandbox"],
)
self.assertEqual(
@@ -100,7 +100,7 @@ class TestClaudeArgv(unittest.TestCase):
)
def test_codex_provider_passes_prompt_reference_as_initial_prompt(self):
argv = _codex_bottle("/home/node/.bot-bottle-prompt.txt").claude_argv([])
argv = _codex_bottle("/home/node/.bot-bottle-prompt.txt").agent_argv([])
self.assertEqual(
["docker", "exec", "-it", "bot-bottle-dev-abc", "codex",
"Read and follow the instructions in "
@@ -109,7 +109,7 @@ class TestClaudeArgv(unittest.TestCase):
)
def test_codex_resume_does_not_append_initial_prompt(self):
argv = _codex_bottle("/home/node/.bot-bottle-prompt.txt").claude_argv(
argv = _codex_bottle("/home/node/.bot-bottle-prompt.txt").agent_argv(
["--dangerously-bypass-approvals-and-sandbox", "resume", "--last"],
)
self.assertEqual(
+15 -15
View File
@@ -1,9 +1,9 @@
"""Unit: SmolmachinesBottle's `claude_argv` builder.
"""Unit: SmolmachinesBottle's `agent_argv` builder.
The dashboard's tmux pane-respawn path calls `bottle.claude_argv`
The dashboard's tmux pane-respawn path calls `bottle.agent_argv`
directly (it spawns claude inside a tmux pane rather than as a
child of the current process), so the argv shape is the
non-trivial part. `exec_claude` is a thin wrapper around the same
non-trivial part. `exec_agent` is a thin wrapper around the same
builder + `subprocess.run`; we lock the shape here.
The TTY-mode argv is wrapped in the pty_resize helper (issue #82
@@ -40,7 +40,7 @@ class TestClaudeArgvWrapped(unittest.TestCase):
"""TTY-mode argv: pty_resize wrapper + inner smolvm exec."""
def test_pty_resize_wrapper_prefix(self):
argv = _bottle().claude_argv([])
argv = _bottle().agent_argv([])
# Absolute script path (not `-m <dotted>`) so the tmux
# pane's cwd doesn't matter — see the `_PTY_RESIZE_SCRIPT`
# docstring in bottle.py.
@@ -53,7 +53,7 @@ class TestClaudeArgvWrapped(unittest.TestCase):
)
def test_minimal_inner_argv_no_prompt(self):
argv = _unwrap(_bottle().claude_argv([]))
argv = _unwrap(_bottle().agent_argv([]))
self.assertEqual(
[
"smolvm", "machine", "exec", "--name",
@@ -69,7 +69,7 @@ class TestClaudeArgvWrapped(unittest.TestCase):
)
def test_appends_passed_args_after_claude(self):
argv = _unwrap(_bottle().claude_argv(
argv = _unwrap(_bottle().agent_argv(
["--dangerously-skip-permissions", "--continue"],
))
self.assertEqual(
@@ -79,7 +79,7 @@ class TestClaudeArgvWrapped(unittest.TestCase):
def test_appends_prompt_file_flag_when_set(self):
argv = _unwrap(
_bottle("/home/node/.bot-bottle-prompt.txt").claude_argv(
_bottle("/home/node/.bot-bottle-prompt.txt").agent_argv(
["--dangerously-skip-permissions"],
)
)
@@ -94,11 +94,11 @@ class TestClaudeArgvWrapped(unittest.TestCase):
)
def test_no_prompt_flag_when_none(self):
argv = _bottle(None).claude_argv(["--continue"])
argv = _bottle(None).agent_argv(["--continue"])
self.assertNotIn("--append-system-prompt-file", argv)
def test_empty_prompt_string_is_treated_as_no_prompt(self):
argv = _bottle("").claude_argv(["--continue"])
argv = _bottle("").agent_argv(["--continue"])
self.assertNotIn("--append-system-prompt-file", argv)
def test_guest_env_forwarded_as_e_flags(self):
@@ -106,7 +106,7 @@ class TestClaudeArgvWrapped(unittest.TestCase):
None,
HTTPS_PROXY="http://127.0.0.1:1234",
NO_PROXY="localhost",
).claude_argv([]))
).agent_argv([]))
self.assertIn("-e", argv)
self.assertIn("HTTPS_PROXY=http://127.0.0.1:1234", argv)
self.assertIn("NO_PROXY=localhost", argv)
@@ -116,11 +116,11 @@ class TestClaudeArgvWrapped(unittest.TestCase):
# the `claude` token to split exec-framing from the claude
# tail. `runuser -u node --` must sit on the prefix side so
# the shell wrap inherits the UID switch.
argv = _bottle().claude_argv([])
claude_idx = argv.index("claude")
argv = _bottle().agent_argv([])
agent_idx = argv.index("claude")
self.assertEqual(
["runuser", "-u", "node", "--"],
argv[claude_idx - 4:claude_idx],
argv[agent_idx - 4:agent_idx],
)
@@ -129,12 +129,12 @@ class TestClaudeArgvNoTTY(unittest.TestCase):
PTY whose SIGWINCH we'd need to bridge."""
def test_no_wrapper_when_tty_false(self):
argv = _bottle().claude_argv([], tty=False)
argv = _bottle().agent_argv([], tty=False)
self.assertEqual("smolvm", argv[0])
self.assertFalse(any("pty_resize" in a for a in argv))
def test_tty_false_drops_it_flags(self):
argv = _bottle().claude_argv([], tty=False)
argv = _bottle().agent_argv([], tty=False)
self.assertNotIn("-i", argv)
self.assertNotIn("-t", argv)