Add chat-friendly shell read rendering
Make workspace shell reads usable as direct chat-model input without changing the PTY or cursor model. This adds optional plain rendering and idle-window batching across CLI, SDK, and MCP while keeping raw reads backward-compatible. Implement the rendering and wait-for-idle logic in the manager layer so the existing guest/backend shell transport stays unchanged. The new helper strips ANSI and other terminal control noise, handles carriage-return overwrite and backspace, and preserves raw cursor semantics even when plain output is requested. Refresh the stable shell docs/examples to recommend --plain --wait-for-idle-ms 300, mark the 3.5.0 roadmap milestone done, and bump the package/catalog version to 3.5.0. Validation: uv lock; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed Firecracker smoke covering shell open/write/read with ANSI plus delayed output.
This commit is contained in:
parent
eecfd7a7d7
commit
21a88312b6
22 changed files with 539 additions and 45 deletions
|
|
@ -37,7 +37,7 @@ def test_pyro_run_in_vm_delegates_to_manager(tmp_path: Path) -> None:
|
|||
assert str(result["stdout"]) == "ok\n"
|
||||
|
||||
|
||||
def test_pyro_create_server_registers_vm_run(tmp_path: Path) -> None:
|
||||
def test_pyro_create_server_registers_full_profile_and_shell_read_schema(tmp_path: Path) -> None:
|
||||
pyro = Pyro(
|
||||
manager=VmManager(
|
||||
backend_name="mock",
|
||||
|
|
@ -46,13 +46,17 @@ def test_pyro_create_server_registers_vm_run(tmp_path: Path) -> None:
|
|||
)
|
||||
)
|
||||
|
||||
async def _run() -> list[str]:
|
||||
async def _run() -> tuple[list[str], dict[str, dict[str, Any]]]:
|
||||
server = pyro.create_server()
|
||||
tools = await server.list_tools()
|
||||
return sorted(tool.name for tool in tools)
|
||||
tool_map = {tool.name: tool.model_dump() for tool in tools}
|
||||
return sorted(tool_map), tool_map
|
||||
|
||||
tool_names = asyncio.run(_run())
|
||||
tool_names, tool_map = asyncio.run(_run())
|
||||
assert tuple(tool_names) == tuple(sorted(PUBLIC_MCP_WORKSPACE_FULL_PROFILE_TOOLS))
|
||||
shell_read_properties = tool_map["shell_read"]["inputSchema"]["properties"]
|
||||
assert "plain" in shell_read_properties
|
||||
assert "wait_for_idle_ms" in shell_read_properties
|
||||
|
||||
|
||||
def test_pyro_create_server_vm_run_profile_registers_only_vm_run(tmp_path: Path) -> None:
|
||||
|
|
@ -977,6 +981,8 @@ def test_pyro_create_server_workspace_status_shell_and_service_delegate() -> Non
|
|||
*,
|
||||
cursor: int = 0,
|
||||
max_chars: int = 65536,
|
||||
plain: bool = False,
|
||||
wait_for_idle_ms: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
calls.append(
|
||||
(
|
||||
|
|
@ -986,6 +992,8 @@ def test_pyro_create_server_workspace_status_shell_and_service_delegate() -> Non
|
|||
"shell_id": shell_id,
|
||||
"cursor": cursor,
|
||||
"max_chars": max_chars,
|
||||
"plain": plain,
|
||||
"wait_for_idle_ms": wait_for_idle_ms,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
|
@ -1097,6 +1105,8 @@ def test_pyro_create_server_workspace_status_shell_and_service_delegate() -> Non
|
|||
"shell_id": "shell-1",
|
||||
"cursor": 5,
|
||||
"max_chars": 1024,
|
||||
"plain": True,
|
||||
"wait_for_idle_ms": 300,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
|
@ -1212,6 +1222,8 @@ def test_pyro_create_server_workspace_status_shell_and_service_delegate() -> Non
|
|||
"shell_id": "shell-1",
|
||||
"cursor": 5,
|
||||
"max_chars": 1024,
|
||||
"plain": True,
|
||||
"wait_for_idle_ms": 300,
|
||||
},
|
||||
),
|
||||
(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue