Skip to content

nwestfall/coign

Repository files navigation

Coign SDK

A private, page-aware AI agent SDK that runs entirely in the visitor's browser.

No API keys. No servers. No per-message cost. Chat mounts instantly; a ~79 MB quick model answers first, then the full model upgrades in the background with tools. All inference is 100% offline after the first download (WebGPU / WebLLM).

Quick start

Zero-config — mount the shell, download on first ask:

<script>
  window.Coign = window.Coign || function() {
    (window.Coign.q = window.Coign.q || []).push(arguments);
  };
  Coign('init'); // mounts chat; never waits on model download
</script>
<script type="module" src="https://cdn.coign.dev/coign-loader.es.js"></script>
<!-- or classic IIFE: -->
<!-- <script src="https://cdn.coign.dev/coign-sdk.iife.js" crossorigin="anonymous"></script> -->
import { init, ask, warmUp, hasModelCached, on } from 'coign-sdk';

await init();                 // shellReady — widget up
await ask('What is this?');   // loads quick (~79 MB) if needed, streams answer
// full model (coign-lite) upgrades in background; tools unlock on upgraded

Installation

CDN

  • Loader (recommended): coign-loader.es.js (~0.3 KB gzip) → dynamic-imports core (~14 KB) + WebLLM only on engage (~2.1 MB gzip chunk, in the engine worker by default)
  • IIFE (single file): coign-sdk.iife.js (~2.1 MB gzip) — convenience when you cannot use ES modules; pays full WebLLM cost up front

npm

npm install coign-sdk

Progressive loading

Phase What happens
init() Config + widget shell. Outline deferred until ask when engage: 'ask'. Never awaits model download. Emits shellReady.
Engage First ask / warmUp / panel open (when engage: 'open') / or engage: 'init'
Quick coign-quick (~79 MB SmolLM2-135M). Streamed Q&A + page outline. No tools.
Full Background upgrade to coign-lite (or your preset). Manual tool loop unlocked.
on('downloadProgress', (p) => console.log(p.phase, p.stage, p.progress));
on('modelReady', ({ tier }) => console.log('ready', tier));
on('upgraded', () => console.log('tools unlocked'));
on('token', ({ token }) => process.stdout?.write?.(token));

await hasModelCached('quick'); // true if weights already in browser cache

Model presets

Preset Download VRAM (approx) Tools Best for
coign-quick ~79 MB ~200 MB none First answer (default progressive path)
coign-tiny ~207 MB ~376 MB none Quick fallback (SmolLM2-360M)
coign-lite ~700 MB ~1.1 GB manual Default full — docs, FAQ
coign-balanced ~1.8 GB ~2.3 GB manual Stronger reasoning
coign-quality ~4.5 GB ~5.1 GB manual Long-form reasoning
coign-tools ~4.5 GB ~5.1 GB native Tool-call reliability (native loop stubbed)

Config knobs (defaults shown):

Option Default Role
preset / model coign-lite Target full model
quick true Progressive path (false = full only)
quickPreset coign-quick First-answer model
engage 'ask' 'ask' | 'open' | 'init'
engineMode 'worker' 'worker' | 'main'
stream true Token streaming
cacheBackend 'cache' WebLLM cache backend
widget true Mount chat UI

Offline mode

Coign uses WebLLM exclusively (no Chrome AI, no cloud APIs). Weights download once and cache locally. Inference runs on-device via WebGPU. Default engine placement is a Web Worker so the UI stays responsive during download/compile/generate.

Built-in tools

Available after the full tier upgrade:

  • agent.searchPage — Full-text search (MiniSearch, lazy-loaded)
  • agent.getPageOutline — Structured page outline
  • agent.getElement — DOM element inspection

Custom tools

Coign.tool({
  name: 'addToCart',
  description: 'Add an item to the shopping cart.',
  parameters: { type: 'object', properties: { item: { type: 'string' } } },
  risk: 'write',
  execute: async ({ item }) => {
    cart.add(item);
    return { success: true };
  },
});

API

init(config?)Promise<CoignSDK>

Shell-first. Mounts widget, patches config (including prompt), emits shellReady. Does not download a model.

warmUp()Promise<void>

Start quick (then full) download without asking. Idempotent.

ask(question, opts?)Promise<string>

Queues until a usable tier is ready. Streams via opts.onToken and token events.

hasModelCached(tier?)Promise<boolean>

Wraps WebLLM hasModelInCache for 'quick' | 'full'.

getTier()'none' | 'quick' | 'full'

on(event, cb)

Events: shellReady, downloadStart, downloadProgress, downloadComplete, modelReady, upgraded, token, ask, answer, error, toolCall, toolResult, …

destroy()

Tear down widget + worker engine.

Also: config, mount / unmount, show / hide, open / close, tool, clearHistory / exportHistory, checkSupport, swapModel, cancelEngineInit.

Examples & Demo

🔗 https://nwestfall.github.io/coign/

npm run build
npm run build:site
npm run preview:site

Development

npm install
npm run dev         # Vite → /demo/phase1.html
npm run build       # ES + CJS (code-split) + IIFE + SRI
npm run test:unit
npm run test        # unit + e2e (build first for IIFE e2e)

Browser requirements

  • Chrome 113+, Edge 113+, or other WebGPU browsers
  • Disk for model cache (~79 MB quick; more for full presets)

Architecture

  • Inference: @mlc-ai/web-llm (WASM + WebGPU), default CreateWebWorkerMLCEngine
  • Search: MiniSearch (lazy)
  • Build: Vite — coign-loader / coign-sdk ES chunks + IIFE CDN bundle + engine worker
  • UI: Shadow DOM widget, phase-aware loading overlay, streaming tokens

License

MIT

About

A JavaScript SDK that puts a private, page-aware AI agent on any website in just a few lines of HTML. All inference happens in the visitor's browser. No server, no API key, no per-message cost.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages