@digdir/brui-client
v0.1.0
Published
TypeScript client that lets an LLM control your web application through tool calls
Readme
brui-client
TypeScript client that orchestrates LLM inference, tool-call routing, and action execution. It connects your application logic to an LLM via the brui proxy server.
Install
npm install brui-clientUsage
1. Create a configuration
A Configuration defines what the LLM can do (tools), what your app executes (actions), and how they connect (decisions).
import type { Configuration } from 'brui-client';
const config: Configuration = {
// Tools are OpenAI-compatible function definitions sent to the LLM
tools: [
{
type: 'function',
function: {
name: 'fillContactForm',
description: 'Fill in the contact form.',
parameters: {
type: 'object',
properties: {
fullName: { type: 'string', description: 'Full name' },
email: { type: 'string', description: 'Email address' },
},
required: ['fullName', 'email'],
},
},
},
],
// Actions map to local functions you register
actions: [
{
name: 'fillFields',
type: 'function',
args: ['fullName', 'email'],
message: 'Filled form for {fullName}.',
},
],
// Decisions connect tool calls to actions
decisions: [
{ tool: 'fillContactForm', actions: ['fillFields'] },
],
// Inference target (must match a key in server/config.yaml)
inference: {
kind: 'inference',
name: 'proxy',
spec: {
name: 'envoy-default',
endpoint: 'http://localhost:8091',
},
},
};2. Register functions and set up
import { Setup } from 'brui-client';
import type { FunctionRegistry } from 'brui-client';
const functions: FunctionRegistry = {
fillFields: (args: Record<string, unknown>) => {
console.log('Filling form with', args);
return { success: true };
},
};
const run = Setup(config, functions);3. Execute
const result = await run('Fill the form for Alice at [email protected]');
// result: { success: true, content: "Filled form for Alice." }API
Setup(config, functions)
Returns an async function (input, metadata?, events?) => Promise<ExecutionResult>.
Parameters:
config—Configurationobject (tools, actions, decisions, inference)functions—FunctionRegistrymapping action names to handler functions
Metadata (optional):
interactionMode—'Act'(call tools) or'Info'(text-only responses)conversationHistory— array of{ role, content }messages for multi-turn contextcontext— arbitrary JSON context passed to the LLM
Event handlers
const result = await run('Do something', { interactionMode: 'Act' }, {
onThinking: (text) => { /* LLM thinking/reasoning text */ },
onContentStream: (text) => { /* streamed response chunks */ },
onToolCallsKnown: (actions) => { /* all planned actions */ },
onActionPending: (event) => { /* action queued */ },
onActionStart: (event) => { /* action executing */ },
onActionComplete: (event, result) => { /* action succeeded */ },
onActionError: (event, error) => { /* action failed */ },
});Types
interface ExecutionResult {
success: boolean;
content?: string;
error?: string;
}
type FunctionRegistry = Record<string, Function>;
interface Configuration {
tools: ToolDefinition[];
actions: Action[];
decisions: Decision[];
inference?: Inference;
transcribe?: TranscribeEndpoint; // optional Whisper-compatible STT endpoint
}Voice / STT
If you set transcribe, the UI sidebar enables a microphone button that posts recorded audio to any Whisper-compatible endpoint:
transcribe: {
endpoint: 'https://your-whisper-endpoint/v1/audio/transcriptions',
// optional:
// headers, model, language, responseFormat,
// silenceThreshold, silenceAutoFlushMs, minUtteranceMs, requestTimeoutMs,
}You can also drive transcription directly without the UI:
import { startTranscribe } from 'brui-client';
const session = await startTranscribe({
endpoint: '…',
onSegment: (text) => console.log(text),
onState: (s) => console.log(s), // 'starting' | 'listening' | 'speaking' | 'processing' | 'stopped'
onRms: (rms) => { /* live audio level 0..1 */ },
onError: (e) => console.error(e),
});
// later: await session.stop();How it works
Setupcreates a resource store from your config and functions.- When called, it sends the user input + tool definitions to the proxy server.
- The LLM either responds with text or tool calls.
- Tool calls are mapped via decisions to actions, which execute your registered functions.
- A summary response is generated and returned.
