# Robots

Give a robot Nur's conversation: it listens while it talks, stops when someone cuts in, and runs the robot's actions as tools that report back.

A robot is an ordinary Nur session with a body attached. Nur does the
listening, the turn-taking and the talking. Your code moves the robot when the
conversation says so.

What you get:

- A live conversation through the robot's own microphone and speaker. Nur hears
  people while it speaks and stops the moment someone cuts in.
- Events your body code follows: someone started talking, the robot started a
  reply, the robot was cut off.
- Actions as tools. Each one answers "started" at once and reports back when
  the motors finish, so the conversation never waits on a wheel or an arm.
- Voices told apart. With more than one person in the room, transcripts label
  each voice `Speaker 1`, `Speaker 2`, so the robot can turn to whoever spoke.

## Run it

On the robot's computer, or your laptop while you try it:

```bash
pip install "eesi-sdk[audio] @ git+https://github.com/eesi-ai/eesi-sdk-python"
export EESI_API_KEY=sk-eesi-...
python robot.py
```

```python robot.py
import asyncio

from eesi import NurClient, Started


class Body:
    """Swap these for your robot's own motion calls."""

    def look_at_speaker(self):
        print("(turns to whoever is talking)")

    def stop_gestures(self):
        print("(stops moving)")

    async def wave(self):
        await asyncio.sleep(2)  # the arm moving
        return "Waved."


body = Body()
nur = NurClient()
robot = nur.character(name="Nova", persona="A friendly robot at the front desk of our lab.")


@robot.tool
async def wave() -> Started:
    """Wave at the person you are talking with."""
    return Started("Waving now.", body.wave())


async def main():
    async with robot.connect("visitor", audio=nur.audio.local()) as session:
        session.on("audio.input.started", lambda event: body.look_at_speaker())
        session.on("speech.interrupted", lambda event: body.stop_gestures())
        await session.run()


asyncio.run(main())
```

Say hello and ask it to wave. Nova says it is waving and keeps talking. When
`body.wave()` returns, Nova is told and mentions it as soon as nobody is
talking. Talk over Nova and both its voice and its gestures stop.

## On a real robot

- **Audio.** `nur.audio.local()` takes the computer's default microphone and
  speaker. Pick the robot's own with `input_device` and `output_device`. If its
  audio already cancels echo, pass `echo="off"`. Otherwise the SDK keeps the
  microphone from hearing the robot, and people cut in by speaking up.
- **What it sees and does.** Send perception as live state, not as
  conversation: `await session.context.update({"seen": {"blue mug": "on the counter"}, "holding": "nothing"})`.
  Nur reads the latest state before each reply, and an update never starts a
  reply by itself.
- **Who is talking.** `transcript.final` events carry `turns`, each with its
  `speaker` number. Bind a number to the direction your microphone array heard
  it from, and turn the head there.
- **Your own audio pipeline.** Leave `audio` out and stream 16 kHz mono PCM
  with `await session.send_audio(pcm)`; play the `audio.output.chunk` events.

Our own robot client, built on the same protocol, drives Reachy Mini in its
simulator and on the robot, and a TIAGo in a simulated kitchen that fetches a
mug and hands it over while it talks (navigation, grasping and the microphone
array are simulated there). Write to founders@eesi.ai if you want it for your
robot.

## Next

<CardGroup cols={2}>
  <Card title="Characters" icon="user" href="/realtime/characters">
    Personas, voices, tools, live state, memory and several people in one room.
  </Card>
  <Card title="Tools and MCP servers" icon="wrench" href="/realtime/tools">
    How Nur calls your functions, and servers EESI runs for you.
  </Card>
  <Card title="Live conversation" icon="bolt" href="/realtime/live">
    The protocol underneath, for robots that speak it directly.
  </Card>
  <Card title="Languages" icon="language" href="/realtime/live#languages">
    More than a hundred, Arabic dialects included, switching as people do.
  </Card>
</CardGroup>
