npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-client

Usage

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:

  • configConfiguration object (tools, actions, decisions, inference)
  • functionsFunctionRegistry mapping 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 context
  • context — 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

  1. Setup creates a resource store from your config and functions.
  2. When called, it sends the user input + tool definitions to the proxy server.
  3. The LLM either responds with text or tool calls.
  4. Tool calls are mapped via decisions to actions, which execute your registered functions.
  5. A summary response is generated and returned.