feat(runtime): add user-controlled turn recovery

This commit is contained in:
Xubin Ren
2026-08-24 00:58:04 +08:00
parent ffa58aa5ef
commit 12029f8812
60 changed files with 4027 additions and 169 deletions
+17 -7
View File
@@ -103,6 +103,16 @@ class _GatewayAgentContractStub:
return None
class _EmptyGatewaySessionManager:
"""Minimal session-manager contract for gateway assembly tests."""
def list_sessions(self) -> list[dict[str, object]]:
return []
def flush_all(self) -> int:
return 0
def test_gateway_signal_handler_first_signal_stops_and_second_forces() -> None:
class _FakeLoop:
def __init__(self) -> None:
@@ -2756,7 +2766,7 @@ def _patch_serve_runtime(monkeypatch, config: Config, seen: dict[str, object]) -
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
)
monkeypatch.setattr("nanobot.cli.commands.AgentLoop", _FakeAgentLoop)
monkeypatch.setattr("nanobot.api.server.create_app", _fake_create_app)
@@ -2823,7 +2833,7 @@ def test_gateway_uses_workspace_directory_for_cron_store(monkeypatch, tmp_path:
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
cron_service=_StopCron,
)
@@ -3329,7 +3339,7 @@ def test_gateway_workspace_override_does_not_migrate_legacy_cron(
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
cron_service=_StopCron,
get_cron_dir=lambda: legacy_dir,
)
@@ -3368,7 +3378,7 @@ def test_gateway_custom_config_workspace_does_not_migrate_legacy_cron(
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
cron_service=_StopCron,
get_cron_dir=lambda: legacy_dir,
)
@@ -3569,7 +3579,7 @@ def test_gateway_health_endpoint_binds_and_serves_expected_responses(
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
)
monkeypatch.setattr("nanobot.cli.gateway_runtime.AgentLoop", _FakeAgentLoop)
monkeypatch.setattr("nanobot.channels.manager.ChannelManager", _FakeChannelManager)
@@ -3771,7 +3781,7 @@ def test_gateway_agent_task_owns_initial_mcp_provider_close(
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
)
monkeypatch.setattr("nanobot.cli.gateway_runtime.AgentLoop", _FakeAgentLoop)
monkeypatch.setattr("nanobot.cli.gateway_runtime.MCPProvider", _FakeMCPProvider)
@@ -3894,7 +3904,7 @@ def test_gateway_shutdown_event_exits_forever_runtime_tasks(
monkeypatch,
config,
message_bus=lambda: object(),
session_manager=lambda _workspace: object(),
session_manager=lambda _workspace: _EmptyGatewaySessionManager(),
)
monkeypatch.setattr("nanobot.cli.gateway_runtime.AgentLoop", _FakeAgentLoop)
monkeypatch.setattr("nanobot.channels.manager.ChannelManager", _FakeChannelManager)