fix(pi): keep interactive sessions open
lint / lint (push) Successful in 1m29s
test / unit (pull_request) Successful in 30s
test / integration (pull_request) Successful in 17s

This commit is contained in:
2026-06-09 06:00:40 -04:00
parent c8b5ba3812
commit 598a20a3f0
7 changed files with 55 additions and 10 deletions
+8 -1
View File
@@ -45,7 +45,12 @@ PROVIDER_TEMPLATES = frozenset({PROVIDER_CLAUDE, PROVIDER_CODEX, PROVIDER_PI})
# forward_host_credentials is enabled. Pipelock must pass these through
# (no TLS MITM) or its header DLP blocks the injected JWT.
CODEX_HOST_CREDENTIAL_HOSTS = ("api.openai.com", "chatgpt.com")
PromptMode = Literal["append_file", "read_prompt_file", "print_read_prompt_file"]
PromptMode = Literal[
"append_file",
"read_prompt_file",
"print_read_prompt_file",
"append_system_prompt",
]
@dataclass(frozen=True)
@@ -381,4 +386,6 @@ def prompt_args(
return [f"Read and follow the instructions in {prompt_path}."]
if prompt_mode == "print_read_prompt_file":
return ["-p", f"Read and follow the instructions in {prompt_path}."]
if prompt_mode == "append_system_prompt":
return ["--append-system-prompt", prompt_path]
raise ValueError(f"unknown provider prompt mode: {prompt_mode}")
+1 -1
View File
@@ -111,7 +111,7 @@ _RUNTIME = AgentProviderRuntime(
template="pi",
command="pi",
image="bot-bottle-pi:latest",
prompt_mode="print_read_prompt_file",
prompt_mode="append_system_prompt",
bypass_args=(),
resume_args=(),
remote_control_args=(),
+1 -1
View File
@@ -93,7 +93,7 @@ endpoint.
The Pi runtime uses:
- `command="pi"`
- `prompt_mode="read_prompt_file"`
- `prompt_mode="append_system_prompt"`
- `image="bot-bottle-pi:latest"`
- `bypass_args=()`
- `resume_args=()`
+4 -4
View File
@@ -273,7 +273,7 @@ class TestAgentProviderRuntime(unittest.TestCase):
models = json.loads(Path(tmp, "pi-models.json").read_text())
self.assertEqual("pi", plan.template)
self.assertEqual("pi", plan.command)
self.assertEqual("print_read_prompt_file", plan.prompt_mode)
self.assertEqual("append_system_prompt", plan.prompt_mode)
self.assertEqual("/tmp/Dockerfile.pi", plan.dockerfile)
self.assertEqual("bot-bottle-pi:latest", plan.image)
self.assertEqual(
@@ -354,10 +354,10 @@ class TestAgentProviderRuntime(unittest.TestCase):
self.assertNotIn("OPENROUTER_API_KEY", plan.guest_env)
self.assertTrue(provider["compat"]["supportsReasoningEffort"])
def test_pi_prompt_mode_uses_print_flag(self):
def test_pi_prompt_mode_appends_system_prompt_interactively(self):
self.assertEqual(
["-p", "Read and follow the instructions in /home/node/.bot-bottle-prompt.txt."],
prompt_args("print_read_prompt_file", "/home/node/.bot-bottle-prompt.txt"),
["--append-system-prompt", "/home/node/.bot-bottle-prompt.txt"],
prompt_args("append_system_prompt", "/home/node/.bot-bottle-prompt.txt"),
)
+3 -3
View File
@@ -77,7 +77,7 @@ def _plan(
supervise_plan=None,
use_runsc=False,
agent_provision=agent_provision or AgentProvisionPlan(
template="pi", command="pi", prompt_mode="print_read_prompt_file",
template="pi", command="pi", prompt_mode="append_system_prompt",
image="bot-bottle-pi:latest", dockerfile="",
guest_home="/home/node",
instance_name="bot-bottle-demo-abc12",
@@ -144,7 +144,7 @@ class TestPiProvisionSkills(unittest.TestCase):
class TestPiProvision(unittest.TestCase):
def test_creates_dir_and_copies_models_config(self):
provision = AgentProvisionPlan(
template="pi", command="pi", prompt_mode="print_read_prompt_file",
template="pi", command="pi", prompt_mode="append_system_prompt",
image="", dockerfile="", guest_home="/home/node",
instance_name="bot-bottle-demo-abc12",
prompt_file=Path("/tmp/prompt.txt"),
@@ -172,7 +172,7 @@ class TestPiProvision(unittest.TestCase):
def test_dies_when_dir_creation_fails(self):
provision = AgentProvisionPlan(
template="pi", command="pi", prompt_mode="print_read_prompt_file",
template="pi", command="pi", prompt_mode="append_system_prompt",
image="", dockerfile="", guest_home="/home/node",
instance_name="bot-bottle-demo-abc12",
prompt_file=Path("/tmp/prompt.txt"),
+19
View File
@@ -31,6 +31,16 @@ def _codex_bottle(prompt_path: str | None = None) -> DockerBottle:
)
def _pi_bottle(prompt_path: str | None = None) -> DockerBottle:
return DockerBottle(
container="bot-bottle-dev-abc",
teardown=lambda: None,
prompt_path_in_container=prompt_path,
agent_command="pi",
agent_prompt_mode="append_system_prompt",
)
class TestClaudeArgv(unittest.TestCase):
def test_minimal_argv_no_prompt(self):
argv = _bottle().agent_argv([])
@@ -117,6 +127,15 @@ class TestClaudeArgv(unittest.TestCase):
argv,
)
def test_pi_provider_appends_system_prompt_without_print_mode(self):
argv = _pi_bottle("/home/node/.bot-bottle-prompt.txt").agent_argv([])
self.assertEqual(
["docker", "exec", "-it", "bot-bottle-dev-abc", "pi",
"--append-system-prompt", "/home/node/.bot-bottle-prompt.txt"],
argv,
)
self.assertNotIn("-p", argv)
if __name__ == "__main__":
unittest.main()
+19
View File
@@ -28,6 +28,15 @@ def _bottle(prompt_path: str | None = None, **env: str) -> SmolmachinesBottle:
)
def _pi_bottle(prompt_path: str | None = None) -> SmolmachinesBottle:
return SmolmachinesBottle(
"bot-bottle-dev-abc",
prompt_path=prompt_path,
agent_command="pi",
agent_prompt_mode="append_system_prompt",
)
def _unwrap(argv: list[str]) -> list[str]:
"""Strip the pty_resize wrapper from the front of a TTY-mode
argv, return the inner smolvm argv. Mirrors what the kernel
@@ -122,6 +131,16 @@ class TestClaudeArgvWrapped(unittest.TestCase):
argv[agent_idx - 7:agent_idx - 2],
)
def test_pi_provider_appends_system_prompt_without_print_mode(self):
argv = _unwrap(
_pi_bottle("/home/node/.bot-bottle-prompt.txt").agent_argv([])
)
self.assertEqual(
["pi", "--append-system-prompt", "/home/node/.bot-bottle-prompt.txt"],
argv[argv.index("pi"):],
)
self.assertNotIn("-p", argv)
class TestClaudeArgvNoTTY(unittest.TestCase):
"""`tty=False` paths skip the pty_resize wrapper — there's no