lint: ruff-clean testbed (blocking file write to thread, unused vars)
This commit is contained in:
@@ -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
@@ -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
@@ -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']} "
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)))
|
||||||
|
|||||||
Reference in New Issue
Block a user