// src/robot-tools.ts — extracted from the reference app's main.ts import { MovePlayer, MOVE_CATALOG, MOVE_IDS, type MoveId, } from "./move-player.js"; import type { ReachyMiniInstance } from "./globals.d.ts"; import type { RealtimeTool } from "./openai-realtime.js"; const HEAD_POSES = { center: { roll: 0, pitch: 0, yaw: 0 }, up: { roll: 0, pitch: -18, yaw: 0 }, down: { roll: 0, pitch: 18, yaw: 0 }, left: { roll: 0, pitch: 0, yaw: 25 }, right: { roll: 0, pitch: 0, yaw: -25 }, tilt_left: { roll: -15, pitch: 0, yaw: 0 }, tilt_right: { roll: 15, pitch: 0, yaw: 0 }, } as const; export const ROBOT_TOOLS: RealtimeTool[] = [ { name: "move_head", description: "Point the robot's head in a named direction. Use to accompany speech with a tiny gesture.", parameters: { type: "object", properties: { direction: { type: "string", enum: Object.keys(HEAD_POSES), description: "Named head pose to assume." }, }, required: ["direction"], }, }, { name: "play_move", description: "Trigger a short pre-recorded body-language move (1-4s) from the Reachy library.\n" + MOVE_CATALOG.map((m) => ` - ${m.id} | ${m.kind} | ${m.description}`).join("\n"), parameters: { type: "object", properties: { name: { type: "string", enum: [...MOVE_IDS], description: "Catalog id." }, }, required: ["name"], }, }, ]; export class RobotToolDispatcher { private movePlayer: MovePlayer; constructor(robot: ReachyMiniInstance) { this.movePlayer = new MovePlayer(robot); } async handle(robot: ReachyMiniInstance, name: string, args: Record): Promise { if (name === "move_head") { const dir = args.direction as keyof typeof HEAD_POSES; const pose = HEAD_POSES[dir]; if (!pose) return `Unknown direction: ${args.direction}`; robot.setHeadPose(pose.roll, pose.pitch, pose.yaw); return `Head moved to ${dir}.`; } if (name === "play_move") { const moveId = args.name as MoveId; await this.movePlayer.play(moveId); return `Played move: ${moveId}.`; } return `Unknown robot tool: ${name}`; } }