Chat plugin
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
Section titled “API at a glance”$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
Section titled “One-shot”echo (new \Nibiru\Module\Ai\Ai()) ->chat() ->ask('In one sentence, what does Form::create() do?');Multi-turn
Section titled “Multi-turn”$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 contextOverriding model + style per call
Section titled “Overriding model + style per call”$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
Section titled “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.
[AI]chat.model = "nibiru-coder:1.0"chat.fallback_model = "qwen2.5-coder:14b"Switching providers
Section titled “Switching providers”Default: Ollama. To use Anthropic Claude as the backend:
[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.)
A practical pattern: chat-as-an-action
Section titled “A practical pattern: chat-as-an-action”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
Section titled “Common pitfalls”- Forgetting
complete(). The fluent builder doesn’t run anything untilcomplete()orask()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 slicinghistory()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.