---
title: Chat plugin
description: Single- or multi-turn chat completions against any Ollama-compatible endpoint.
---

The Chat plugin is the simplest piece of the AI module. It wraps Ollama's `/api/chat` with a fluent builder, conversation memory, automatic fallback to a backup model, and a one-shot `ask()` shortcut.

## API at a glance

```php
$ai   = new \Nibiru\Module\Ai\Ai();
$chat = $ai->chat();

$chat->system('Be terse.');           // optional system prompt
$chat->model('qwen2.5-coder:14b');    // override the configured model
$chat->temperature(0.2);              // override config
$chat->maxTokens(512);                // override config

$chat->user('Hello');                 // append a user message
$chat->assistant('Hi.');              // append an assistant message (rare)

$reply = $chat->complete();           // run the call, return text
$reply = $chat->ask('How are you?');  // = ->user(...)->complete()

$chat->reset();                       // clear messages, keep model + system
$chat->history();                     // [{role, content}, …]
```

## One-shot

```php
echo (new \Nibiru\Module\Ai\Ai())
    ->chat()
    ->ask('In one sentence, what does Form::create() do?');
```

## Multi-turn

```php
$chat = $ai->chat();

$chat->user('Name three Nibiru singletons.');
$singletons = $chat->complete();        // appended to history

$chat->user('What does the second one do?');
$detail = $chat->complete();            // model has full context
```

## Overriding model + style per call

```php
$german = $ai->chat()
    ->system('Answer in German. Be precise.')
    ->model('qwen2.5-coder:14b')
    ->temperature(0.1)
    ->ask('Wie definiere ich einen Controller?');
```

## Automatic fallback

If `chat.model` (e.g. `nibiru-coder:1.0`) isn't on the Ollama server, the plugin re-runs the call with `chat.fallback_model` (e.g. `qwen2.5-coder:14b`). This keeps your app working while you're still building the fine-tune.

```ini
[AI]
chat.model          = "nibiru-coder:1.0"
chat.fallback_model = "qwen2.5-coder:14b"
```

## Switching providers

Default: Ollama. To use Anthropic Claude as the backend:

```ini
[AI]
chat.provider       = "anthropic"
anthropic.api_key   = "sk-ant-..."
anthropic.model     = "claude-haiku-4-5-20251001"
```

The Chat plugin doesn't ship Anthropic transport in the framework module yet — for now, the docs site's `scripts/lib/providers.mjs` pattern is the reference. (See the [Roadmap](/en/ai/roadmap/).)

## A practical pattern: chat-as-an-action

```php
namespace Nibiru;
use Nibiru\Adapter\Controller;
use Nibiru\Module\Ai\Ai;

class supportController extends Controller
{
    public function askAction(): void {
        View::forwardToJsonHeader();
        $q = trim($this->getPost('question', ''));
        if ($q === '') {
            View::assign(['data' => ['error' => 'question required']]);
            return;
        }
        $reply = (new Ai())->chat()
            ->system('You are the Nibiru support assistant. Be brief.')
            ->ask($q);
        View::assign(['data' => ['answer' => $reply]]);
    }

    public function pageAction(): void {}
    public function navigationAction(): void {
        JsonNavigation::getInstance()->loadJsonNavigationArray();
    }
}
```

Six lines plus boilerplate, and you've got an AJAX-callable AI endpoint backed by your own Ollama.

## Common pitfalls

- **Forgetting `complete()`.** The fluent builder doesn't run anything until `complete()` or `ask()` is called.
- **Calling `assistant()` between user turns.** It's there for replaying a saved conversation, not for normal use.
- **Long conversations.** Each turn re-sends the full history. Trim with `reset()` or by slicing `history()` when you no longer need older context.
- **Setting temperature too low.** 0 makes the model rigid; 0.3–0.5 is the sweet spot for technical answers.
