search challenge: triangle marker on a crate's back face (rendered in vision, in digest), report tool with distance verification, smooth turn(duration), --free/--search autonomous modes, look_at crates; verified with gpt-5.6-luna

This commit is contained in:
opencode
2026-08-08 21:58:57 +03:00
parent 315762363e
commit daa0371519
9 changed files with 444 additions and 34 deletions
+78 -7
View File
@@ -113,6 +113,15 @@ class WorldQueryOutput(BaseModel):
tick: int
class ReportOutput(BaseModel):
discovery: str
success: bool
verified: bool
distance: float
message: str
tick: int
class EchoOutput(BaseModel):
value: str
@@ -166,6 +175,17 @@ class RoomBridge(Bridge):
def _tick(self) -> int:
return self.world.advance_tick()
async def _animate_turn(
self, yaw_deg: float, pitch_deg: float, duration: float
) -> None:
"""Rotate smoothly over ``duration`` seconds (observable mid-turn)."""
n = max(1, min(int(duration / 0.1), 100))
dt = duration / n
for i in range(n):
self.world.turn(yaw_deg / n, pitch_deg / n)
if i < n - 1:
await asyncio.sleep(dt)
async def _animate_move(
self, forward: float, duration: float
) -> tuple[float, Any | None]:
@@ -333,24 +353,48 @@ class RoomBridge(Bridge):
@self.tool(
cls=ToolClass.ACTUATOR,
description="Rotate the camera: yaw_deg turns left/right, pitch_deg tilts up/down.",
description=(
"Rotate the camera: yaw_deg turns left/right, pitch_deg tilts up/down. "
"duration (seconds) animates the rotation smoothly."
),
)
async def turn(yaw_deg: float = 0.0, pitch_deg: float = 0.0) -> TurnOutput:
async def turn(
yaw_deg: float = 0.0, pitch_deg: float = 0.0, duration: float = 0.0
) -> TurnOutput:
tick = self._tick()
world.turn(yaw_deg, pitch_deg)
if duration < 0.0 or duration > 10.0:
raise ValueError(f"duration must be in [0, 10] s, got {duration}")
if duration > 0.0:
await self._animate_turn(yaw_deg, pitch_deg, duration)
else:
world.turn(yaw_deg, pitch_deg)
return TurnOutput(rotation=self._rotation(), tick=tick).model_dump()
@self.tool(
cls=ToolClass.ACTUATOR,
description="Orient the camera toward a named target (e.g. 'beacon').",
description=(
"Orient the camera toward a named target: 'beacon' or a crate "
"(crate_red, crate_blue, crate_olive)."
),
)
async def look_at(target: str) -> LookAtOutput:
tick = self._tick()
if target != "beacon":
box = next((b for b in world.boxes if b.id == target), None)
if target == "beacon":
yaw, pitch = world.look_at_beacon()
elif box is not None:
dx = box.cx - world.capsule.x
dz = box.cz - world.capsule.z
dist = math.hypot(dx, dz) or 1.0
yaw = math.degrees(math.atan2(dx, dz))
pitch = math.degrees(
math.atan2(box.height / 2 - world.capsule.eye_height, dist)
)
world.face(yaw, pitch)
else:
raise ValueError(
f"unknown target {target!r}; available targets: beacon"
f"unknown target {target!r}; available: beacon, crate_red, crate_blue, crate_olive"
)
yaw, pitch = world.look_at_beacon()
return LookAtOutput(
target=target,
rotation=Rotation(
@@ -383,6 +427,33 @@ class RoomBridge(Bridge):
target=target, success=success, message=message, tick=tick
).model_dump()
@self.tool(
cls=ToolClass.ACTUATOR,
description=(
"Report a discovery to the operator (used in search missions): "
"say what you found. The report is verified against your position."
),
)
async def report(discovery: str = "triangle") -> ReportOutput:
tick = self._tick()
dist = world.distance_to_marker()
verified = world.marker is not None and dist <= 6.0
if verified:
message = f"report verified: {discovery} sighted {dist:.1f} m away"
else:
message = (
f"not verified: nothing matching {discovery!r} within 6 m "
f"(closest check {dist:.1f} m) — keep exploring"
)
return ReportOutput(
discovery=discovery,
success=True,
verified=verified,
distance=round(dist, 2),
message=message,
tick=tick,
).model_dump()
# -- conformance tools (design doc: register alongside world tools) --
@self.tool(