lint: ruff-clean testbed (blocking file write to thread, unused vars)

This commit is contained in:
opencode
2026-08-08 04:29:51 +03:00
parent 132eb25c62
commit 4ced623b55
8 changed files with 42 additions and 19 deletions
+21
View File
@@ -0,0 +1,21 @@
# Session Goal
реализуй полностью. автономно
## Plan
1. Read protocol spec (docs/aicc-core.md) and testbed design (docs/testbed-design.md)
2. Inspect aicc-py SDK at ~/Desktop/aicc-py
3. Build testbed bridge skeleton (world, capsule, bridge with tools)
4. Implement tools: proprioception, vision, move, turn, look_at, interact
5. Add headless rendering for vision frames
6. Write agent demo loop
7. Run conformance suite (9/9 green)
8. Verify demo end-to-end, write README, commit per milestone
## Progress
- DONE: world engine (room, capsule physics/collision, beacon, audio) — testbed/room/world.py
- DONE: headless raycaster renderer (vision 160x120 + aligned depth grid) — testbed/room/render.py
- DONE: RoomBridge with all world tools + echo/boom/bump — testbed/bridge.py
- DONE: conformance runner — 9/9 green against testbed bridge (testbed/conformance.py)
- DONE: commits for skeleton + bridge milestones
- NEXT: unit tests (world/render/bridge), demo agent loop (ollama LLM + scripted fallback), README, setup.sh, BUILDLOG
+1 -1
View File
@@ -13,7 +13,7 @@ import asyncio
import base64 import base64
import io import io
import math import math
from typing import Any, Literal from typing import Any
from aicc.bridge import Bridge from aicc.bridge import Bridge
from aicc.protocol import TickMode, ToolClass from aicc.protocol import TickMode, ToolClass
+7 -3
View File
@@ -417,7 +417,7 @@ async def run_scripted_agent(
detour_turns += 1 detour_turns += 1
t = (await client.call_tool("turn", {"yaw_deg": 45.0})).output t = (await client.call_tool("turn", {"yaw_deg": 45.0})).output
summary["tool_calls"] += 1 summary["tool_calls"] += 1
log("tool", f'turn({{"yaw_deg": 45.0}}) [detour]') log("tool", 'turn({"yaw_deg": 45.0}) [detour]')
log("bridge", f"ok {json.dumps(t)}") log("bridge", f"ok {json.dumps(t)}")
else: else:
detour_steps -= 1 detour_steps -= 1
@@ -516,8 +516,12 @@ async def run_demo(args: argparse.Namespace) -> dict[str, Any]:
frame = (await client.call_tool("vision", {})).output frame = (await client.call_tool("vision", {})).output
if args.frame: if args.frame:
raw = base64.b64decode(frame["png_b64"]) raw = base64.b64decode(frame["png_b64"])
with open(args.frame, "wb") as fh:
fh.write(raw) def _write_frame() -> None:
with open(args.frame, "wb") as fh:
fh.write(raw)
await asyncio.to_thread(_write_frame)
print(f"\n[final frame saved] {args.frame}") print(f"\n[final frame saved] {args.frame}")
print( print(
f"\n[demo done] steps={summary['steps']} tool_calls={summary['tool_calls']} " f"\n[demo done] steps={summary['steps']} tool_calls={summary['tool_calls']} "
+6 -7
View File
@@ -13,7 +13,7 @@ import math
from PIL import Image from PIL import Image
from testbed.room.world import ROOM_HEIGHT, ROOM_SIZE, Box, Room from testbed.room.world import ROOM_HEIGHT, ROOM_SIZE, Room
# Palette # Palette
FOG = (14, 14, 20) FOG = (14, 14, 20)
@@ -83,10 +83,10 @@ class Raycaster:
row_top = self._row_of(ROOM_HEIGHT, t_wall, eye, tan_pitch) row_top = self._row_of(ROOM_HEIGHT, t_wall, eye, tan_pitch)
row_bot = self._row_of(0.0, t_wall, eye, tan_pitch) row_bot = self._row_of(0.0, t_wall, eye, tan_pitch)
r_top = max(0, int(math.ceil(min(row_top, row_bot)))) r_top = max(0, math.ceil(min(row_top, row_bot)))
r_bot = min(h, int(math.floor(max(row_top, row_bot)))) r_bot = min(h, math.floor(max(row_top, row_bot)))
base = c * 3 c * 3
for r in range(h): for r in range(h):
v = self.tan_fy * (1.0 - 2.0 * (r + 0.5) / h) v = self.tan_fy * (1.0 - 2.0 * (r + 0.5) / h)
down = v + tan_pitch down = v + tan_pitch
@@ -252,7 +252,7 @@ class Raycaster:
return _fog(col, dist) return _fog(col, dist)
def _shade_floor(self, wx: float, wz: float, t: float) -> tuple[int, int, int]: def _shade_floor(self, wx: float, wz: float, t: float) -> tuple[int, int, int]:
cell = int(math.floor(wx)) + int(math.floor(wz)) cell = math.floor(wx) + math.floor(wz)
col = FLOOR_A if cell % 2 == 0 else FLOOR_B col = FLOOR_A if cell % 2 == 0 else FLOOR_B
fx = wx - math.floor(wx) fx = wx - math.floor(wx)
fz = wz - math.floor(wz) fz = wz - math.floor(wz)
@@ -285,8 +285,7 @@ class Raycaster:
vv = (b.height - eye) / along - tan_pitch vv = (b.height - eye) / along - tan_pitch
row_c = (1.0 - vv / self.tan_fy) / 2.0 * h row_c = (1.0 - vv / self.tan_fy) / 2.0 * h
r_px = b.radius / along / self.tan_fx * w / 2.0 r_px = b.radius / along / self.tan_fx * w / 2.0
if r_px < 1.2: r_px = max(r_px, 1.2)
r_px = 1.2
glow = r_px * 3.4 glow = r_px * 3.4
pulse = 1.0 pulse = 1.0
+1 -1
View File
@@ -7,7 +7,7 @@ agent except through the sensor tools in ``testbed.bridge``.
from __future__ import annotations from __future__ import annotations
import math import math
from dataclasses import dataclass, field from dataclasses import dataclass
ROOM_SIZE = 16.0 ROOM_SIZE = 16.0
ROOM_HEIGHT = 3.0 ROOM_HEIGHT = 3.0
-1
View File
@@ -15,7 +15,6 @@ from testbed.bridge import (
VISION_WIDTH, VISION_WIDTH,
build_bridge, build_bridge,
) )
from testbed.room.world import Room
@pytest.fixture @pytest.fixture
+4 -4
View File
@@ -21,7 +21,7 @@ def test_wall_nearby_is_bright_gray():
room = Room() room = Room()
room.capsule.yaw_deg = 180.0 # face north wall 1.5m away room.capsule.yaw_deg = 180.0 # face north wall 1.5m away
px = Raycaster().render(room)[0].load() px = Raycaster().render(room)[0].load()
r, g, b = px[80, 60] r, g, _b = px[80, 60]
assert abs(r - g) < 8 and r > 80 # gray wall, little fog at 1.5m assert abs(r - g) < 8 and r > 80 # gray wall, little fog at 1.5m
@@ -30,11 +30,11 @@ def test_beacon_glow_visible_when_facing_it():
room.capsule.x, room.capsule.z, room.capsule.yaw_deg = 11.0, 11.0, 45.0 room.capsule.x, room.capsule.z, room.capsule.yaw_deg = 11.0, 11.0, 45.0
img, _ = Raycaster().render(room) img, _ = Raycaster().render(room)
px = img.load() px = img.load()
r, g, b = px[80, 60] r, _, b = px[80, 60]
assert b > r # inactive beacon glows cyan assert b > r # inactive beacon glows cyan
room.beacon.active = True room.beacon.active = True
px = Raycaster().render(room)[0].load() px = Raycaster().render(room)[0].load()
r, g, b = px[80, 60] r, _, b = px[80, 60]
assert r > b # active beacon glows warm yellow assert r > b # active beacon glows warm yellow
@@ -42,7 +42,7 @@ def test_beacon_occluded_by_crate():
room = Room() room = Room()
# Beacon behind crate_red from spawn: center pixel must not be cyan. # Beacon behind crate_red from spawn: center pixel must not be cyan.
px = Raycaster().render(room)[0].load() px = Raycaster().render(room)[0].load()
r, g, b = px[80, 60] _r, _g, b = px[80, 60]
assert b < 90 assert b < 90
+2 -2
View File
@@ -4,7 +4,7 @@ import math
import pytest import pytest
from testbed.room.world import ROOM_SIZE, Beacon, Box, Room from testbed.room.world import ROOM_SIZE, Room
def test_spawn_state(): def test_spawn_state():
@@ -79,7 +79,7 @@ def test_turn_clamps_pitch():
def test_look_at_beacon(): def test_look_at_beacon():
room = Room() room = Room()
yaw, pitch = room.look_at_beacon() yaw, _pitch = room.look_at_beacon()
dx = room.beacon.x - room.capsule.x dx = room.beacon.x - room.capsule.x
dz = room.beacon.z - room.capsule.z dz = room.beacon.z - room.capsule.z
assert yaw == pytest.approx(math.degrees(math.atan2(dx, dz))) assert yaw == pytest.approx(math.degrees(math.atan2(dx, dz)))