module BBS::AI

A conversational character for a BBS: a persona read from a YAML file, a small model behind any OpenAI-compatible chat endpoint (llama.cpp’s llama-server, Ollama, vLLM, a hosted API, …), a short per-caller memory, and canned replies for when the model is missing or fails.

PERSONA = BBS::AI::Persona.load('lib/oracle.yml')
ORACLE  = BBS::AI::Chat.new(
  persona: PERSONA,
  client:  BBS::AI::Client.new(url: ENV.fetch('ORACLE_LLM_URL', ''))
)

on_unknown do |input, io|
  out = BBS::AI::Typewriter.new(io, prefix: 'ORACLE: ', style: :dim)
  ORACLE.reply(input, io.ctx) { |piece| out.write(piece) }
  out.finish
end

With an empty URL the chat never calls a model and answers from the persona’s canned replies only, so a BBS can ship the character before it has a model to run.