Base broker — every provider implements this. Capabilities (chat,
embed, translate, image, tts, …) live on separate interfaces in
per-modality folders (lib/src/chat/, lib/src/embed/,
lib/src/translate/, …). Concrete provider classes implement only
the capability interfaces their service actually supports.
The assistant's reply plus what the provider said about it: why it
stopped and how many tokens it used. Returned by
AiBroker.completeWithMeta and AiBroker.chatWithMeta.
What every broker call boils down to. system is the persistent
instruction; messages is the turn history (oldest first). Both
complete* and chat* build the same wire payload — complete*
is just chat* with one user message.
aib collections — lists collections in the workbench DB. The
--exists <name> flag turns it into a script-friendly probe: exit 0
if present, exit 1 if not, no output.
Text-embedding capability. Implemented by OpenAiBroker and
GeminiBroker; not by AnthropicBroker (Anthropic doesn't
host first-party embeddings — pair Anthropic with OpenAI or Gemini
for the embed side).
Google Gemini (generateContent / streamGenerateContent).
Pagination on listModels caps at 5 pages × 50; only gemini-* ids
that support generateContent are kept.
Google Cloud Translation v2 (/language/translate/v2). Uses simple
API-key auth — no service-account JSON. Cloud Translation is a
separate service from Gemini and uses a different API key issued
from the Google Cloud Console with the Cloud Translation API
enabled.
Where API keys come from. Flutter apps with secure storage implement
this against their own store; CLI / backend code can use the
built-in EnvKeyResolver or MapKeyResolver.
Wraps any ChatBroker so it can be used wherever a
TranslateBroker is expected. The translation request is converted
into a system prompt that includes the target language plus every
supplied hint (domain, tone, glossary, free-form context).
OpenAI provider — implements ChatBroker (/v1/chat/completions)
and EmbedBroker (/v1/embeddings). Filters listModels to
gpt-* / o<digit>* so the picker doesn't show whisper /
embeddings / dall-e.
aib search <query> — embeds the query with the collection's pinned
model, returns cosine top-K snippets. Default output is human-
readable; --json produces a single JSON object suitable for
piping into Claude (slash-command style).
Sentence-aware sliding window. Packs sentences greedily into windows
of approximately targetChars characters with overlapChars of
trailing context carried forward into the next window.
One parsed Server-Sent Event. OpenAI and Anthropic both use SSE for
their streaming endpoints (Gemini uses a JSON-array stream — see
the Gemini broker for that codepath).
One chunk of source text. Carries enough metadata to cite back to the
original document (source path + ordinal within that document) plus
arbitrary meta for higher-level info (page number, heading path,
etc.).
Translation capability. Implemented natively by
GoogleTranslateBroker (Google Cloud Translation v2). Any
ChatBroker can also be wrapped in LlmTranslator to act as a
TranslateBroker powered by an LLM — useful when context matters
and the dedicated translation service isn't available.
ai_broker translate <text> — translate via Google Cloud
Translation (default) or via any ChatBroker (--broker openai /
anthropic / gemini), with optional context hints and a
client-side glossary.
Output of TranslateBroker.translate. translated is always set;
detectedFrom is non-null when the caller passed from: null and
the provider reported a detected source language; modelUsed is
set when the implementation routed through a specific model
(LLM translators) and null otherwise.
Who authored a message in a chat. system lives on
ChatRequest.system, not here — every provider treats system
instructions specially (Anthropic puts them at top-level; Gemini
uses systemInstruction; OpenAI uses a role:system message). We
only model the back-and-forth.
Status codes that mean "try again later, the request itself is
fine": rate limits (429), transient server errors (500, 502, 504) and
upstream overload (503, Anthropic's 529). Quota-exceeded (a hard 429
with quota in the body) is not retryable — callers pass
isHardFailure to surface that to the user instead of burning attempts.
Builds the aib / ai_broker CLI. Returns a configured
CommandRunner so tests (and bin/ai_broker.dart) can construct +
run it without duplicating wiring.
Decodes a UTF-8 byte stream into SseEvents. Buffers across chunk
boundaries (one event may span several Stream<List<int>> chunks),
joins multi-line data: payloads with \n per the SSE spec, and
filters out keep-alive comments.
Default chat model id for an LLM-based translator wrapping the
given chat broker. Used by TranslateCommand when the user picks
--broker openai|anthropic|gemini without overriding --model.
Opens a POST request and returns the response body as a byte
stream. Throws AiBrokerException on non-2xx (the body is buffered
in that path so we can include the error message).
HTTP retry with exponential backoff: up to maxAttempts tries, waiting
baseDelay × 2ⁿ between them. Shared by every broker so retry policy
lives in one place.
Strips a markdown code fence from text. Model output for "give me
code" prompts usually arrives wrapped in ```lang\n...\n```,
even after an explicit "code only" instruction, and often with a
sentence of prose before or after the block. Call this on the broker's
raw text before parsing or writing it to a file.