robustness: vision/depth render off the event loop (deepcopy snapshot), chat auto-reconnect + friendly errors, demo catches connection failures
This commit is contained in:
@@ -95,3 +95,4 @@
|
||||
[ 183147ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8000/:40
|
||||
[ 188179ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8000/:40
|
||||
[ 192874ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8000/:40
|
||||
[ 1348483ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8000/:40
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
+14
-5
@@ -11,6 +11,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import copy
|
||||
import io
|
||||
import math
|
||||
from typing import Any
|
||||
@@ -206,11 +207,18 @@ class RoomBridge(Bridge):
|
||||
)
|
||||
async def vision() -> VisionOutput:
|
||||
tick = self._tick()
|
||||
img, _ = renderer.render(world)
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format="PNG")
|
||||
# Render off the event loop so frames never stall the bridge under
|
||||
# load; deepcopy keeps the snapshot consistent with this tool call.
|
||||
snapshot = copy.deepcopy(world)
|
||||
img, _ = await asyncio.to_thread(renderer.render, snapshot)
|
||||
|
||||
def _encode() -> str:
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format="PNG")
|
||||
return base64.b64encode(buf.getvalue()).decode("ascii")
|
||||
|
||||
return VisionOutput(
|
||||
png_b64=base64.b64encode(buf.getvalue()).decode("ascii"),
|
||||
png_b64=await asyncio.to_thread(_encode),
|
||||
width=VISION_WIDTH,
|
||||
height=VISION_HEIGHT,
|
||||
tick=tick,
|
||||
@@ -222,7 +230,8 @@ class RoomBridge(Bridge):
|
||||
)
|
||||
async def depth(max_depth: float = 10.0) -> DepthOutput:
|
||||
tick = self._tick()
|
||||
_, grid = renderer.render(world, max_depth=max_depth)
|
||||
snapshot = copy.deepcopy(world)
|
||||
_, grid = await asyncio.to_thread(renderer.render, snapshot, max_depth)
|
||||
return DepthOutput(
|
||||
width=DEPTH_WIDTH,
|
||||
height=DEPTH_HEIGHT,
|
||||
|
||||
+28
-6
@@ -191,12 +191,34 @@ async def chat_loop(client: AICCClient, manifest, args: argparse.Namespace) -> i
|
||||
|
||||
|
||||
async def run(args: argparse.Namespace) -> int:
|
||||
transport = WebSocketClientTransport(args.url)
|
||||
async with AICCClient(transport) as client:
|
||||
manifest = await client.handshake()
|
||||
print(f"[handshake] session {manifest.session_id} world {manifest.world.name}")
|
||||
print(f"[handshake] tools: {[t.id for t in manifest.tools]}")
|
||||
return await chat_loop(client, manifest, args)
|
||||
"""Run the chat session, reconnecting to the bridge if the connection dies."""
|
||||
attempts = 0
|
||||
while True:
|
||||
try:
|
||||
transport = WebSocketClientTransport(args.url)
|
||||
async with AICCClient(transport) as client:
|
||||
manifest = await client.handshake()
|
||||
print(
|
||||
f"[handshake] session {manifest.session_id} world {manifest.world.name}"
|
||||
)
|
||||
print(f"[handshake] tools: {[t.id for t in manifest.tools]}")
|
||||
return await chat_loop(client, manifest, args)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as exc: # noqa: BLE001 - connection lost: reconnect
|
||||
attempts += 1
|
||||
print(f"\n[chat] connection lost ({type(exc).__name__}: {exc})")
|
||||
if attempts >= 3:
|
||||
print(
|
||||
"[chat] giving up after 3 attempts — is the bridge running? (scripts/run_bridge.sh)"
|
||||
)
|
||||
return 1
|
||||
print(
|
||||
"[chat] reconnecting in 2 seconds… (the room keeps its state on the bridge)"
|
||||
)
|
||||
await asyncio.sleep(2.0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
|
||||
+11
-2
@@ -152,7 +152,9 @@ async def run_llm_agent(
|
||||
log=lambda role, msg: print(f"[{role}] {msg}"),
|
||||
)
|
||||
try:
|
||||
return await run_llm_agent_loop(controller, max_steps, log=print_log, recorder=recorder)
|
||||
return await run_llm_agent_loop(
|
||||
controller, max_steps, log=print_log, recorder=recorder
|
||||
)
|
||||
except RuntimeError as exc:
|
||||
return {"steps": 0, "tool_calls": 0, "result": str(exc), "interacted": False}
|
||||
|
||||
@@ -398,7 +400,14 @@ def main() -> int:
|
||||
"into this directory, plus demo.gif animation and demo_summary.png",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
summary = asyncio.run(run_demo(args))
|
||||
try:
|
||||
summary = asyncio.run(run_demo(args))
|
||||
except KeyboardInterrupt:
|
||||
return 2
|
||||
except Exception as exc: # noqa: BLE001 - friendly failure instead of a traceback
|
||||
print(f"\n[demo] failed: {type(exc).__name__}: {exc}")
|
||||
print("[demo] is the bridge running? scripts/run_bridge.sh")
|
||||
return 1
|
||||
return 0 if summary.get("interacted") else 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user