> For the complete documentation index, see [llms.txt](https://docs.spoof.dev/asteroid/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.spoof.dev/asteroid/configuration/artificial-intelligence.md).

# Artificial Intelligence

Asteroid can let fake players hold real conversations in chat, with your real players and with each other, through AI language models accessed via OpenRouter.

This is optional and off by default. It is the one feature that needs an external account and an API key.

```yaml
ai:
  enabled: false
  apiKey: "api-key-here"
```

## Setup

1. Create an account at <https://openrouter.ai/>.
2. Go to <https://openrouter.ai/settings/keys> and click Create API Key.
3. Paste the key into `ai.apiKey`.
4. Set `ai.enabled` to true and reload.

OpenRouter offers both free and paid models. Free models are good enough for most servers.

## Chat delivery

```yaml
ai:
  chat:
    way: "normal"
    broadcast_format: "{playerDisplayName}: {message}"
```

| Setting                 | What it does                                                                                                                                                                 |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chat.way`              | `normal` sends messages through the regular chat system. `broadcast` sends them as broadcasts instead, which helps if a chat plugin blocks or reformats the fake's messages. |
| `chat.broadcast_format` | The format used when `way` is `broadcast`. Supports PlaceholderAPI. Built-in: `{playerName}`, `{playerDisplayName}`, `{message}`.                                            |

## Player-to-AI conversations

Lets real players talk to fake players by chatting near them.

```yaml
ai:
  basic:
    delay: "{random[2,5]}"
    answer_in_same_world: false
    playerToAI:
      enabled: true
      response_chance: 5
```

| Setting                      | What it does                                                                                                       |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `basic.delay`                | Seconds the AI waits before replying, to simulate typing.                                                          |
| `basic.answer_in_same_world` | If true, fakes only reply to players in the same world.                                                            |
| `playerToAI.enabled`         | Turns player-to-AI conversations on or off.                                                                        |
| `playerToAI.response_chance` | Percent chance a fake replies to any given real chat message. Low values make fakes seem busy and less suspicious. |

## AI-to-AI conversations (beta)

Fake players can start conversations with each other, creating background chatter.

```yaml
ai:
  basic:
    AItoAI:
      enabled: false
      chance: 20
      response_chance: 70
      initiation: "Initiate a brief Minecraft conversation with {selectedTarget}..."
```

| Setting                  | What it does                                                                              |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| `AItoAI.enabled`         | Turns fake-to-fake conversations on or off.                                               |
| `AItoAI.chance`          | Percent chance a fake starts talking to another fake.                                     |
| `AItoAI.response_chance` | Percent chance the other fake replies.                                                    |
| `AItoAI.initiation`      | The prompt used to start the conversation. `{selectedTarget}` is the other player's name. |

You can also start an AI conversation on a timer using the `{initAIConv}` scheduler function.

## Advanced behavior

The `ai.advanced` section shapes how the AI writes. Most servers can leave these at their defaults.

### The system prompt

`advanced.rule` is the core instruction sent to the model. It defines the personality and the strict rules that keep replies looking like a real player: short, lowercase, casual, and never revealing that it is an AI. Placeholders inside it: `{listener}` (the fake's name), `{sender}` (the real player), and `{personality}`, `{speaking_style}`, `{description}` from the AI config files.

### Timeouts and length

| Setting                          | What it does                                                                   |
| -------------------------------- | ------------------------------------------------------------------------------ |
| `timeouts.receiver`              | Cooldown before a fake can be talked to again after a conversation.            |
| `timeouts.sender`                | Same cooldown, for the fake that started the conversation.                     |
| `timeouts.conversation`          | If nobody speaks for this long, the conversation ends.                         |
| `addRuleReminder` and `reminder` | Periodically re-send the rules during long chats to keep replies in character. |
| `maxResponses`                   | The conversation ends after this many AI replies.                              |

### Safety filter

`safeguards.stop_on_breach` stops a conversation immediately if a reply contains banned content, like admitting it is an AI. `safeguards.conditions` is a list of regex patterns that trigger this.

### Text cleanup

| Setting                     | What it does                                                                                                                  |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `nameThreshold`             | How closely an AI-mentioned name must match a real name to count. 0.0 matches anything, 1.0 is exact only, 0.5 catches typos. |
| `removeNonASCII`            | Strips emojis and non-English characters. Recommended on.                                                                     |
| `forceNoPunctuation`        | Removes punctuation so messages look more like player chat.                                                                   |
| `forceOnlySmallLetters`     | Converts replies to lowercase.                                                                                                |
| `closeOnNewPlayerMentioned` | Ends the conversation if the AI mentions a different player.                                                                  |

### Model settings

```yaml
advanced:
  openrouter:
    referer: "asteroid"
    ai_model: "deepseek/deepseek-r1-0528:free"
    responseType: "temperature"
    frequencyPenalty: 2.0
    presencePenalty: 1.5
    temperature: 0.2
    topp: 0.15
```

| Setting            | What it does                                                                                                         |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `referer`          | The HTTP referer header sent to OpenRouter. Can be anything.                                                         |
| `ai_model`         | Which model to use. Browse options at <https://openrouter.ai/models>. Free option: `deepseek/deepseek-r1-0528:free`. |
| `responseType`     | `temperature` controls randomness directly. `topp` uses nucleus sampling. Most people use `temperature`.             |
| `frequencyPenalty` | Higher reduces repeated words. Range -2.0 to 2.0.                                                                    |
| `presencePenalty`  | Higher encourages topic changes. Range -2.0 to 2.0.                                                                  |
| `temperature`      | 0.0 is robotic, 1.0 balanced, 2.0 very random. 0.2 keeps replies focused.                                            |
| `topp`             | Only used when `responseType` is `topp`. Lower is more focused.                                                      |
