Ultron Live

SDK Documentation

The official JavaScript / TypeScript SDK (ultron-live-sdk). Viewing the v2 surface.

Overview & Install

The official JavaScript / TypeScript SDK for Ultron Live — real-time AI vision, screen commentary, WebRTC streaming, realtime voice, assessment, and TTS. It works in the browser and in Node, and ships with full TypeScript types.

Install

bash
npm install ultron-live-sdk

Import

ts
// ESM (recommended)
import { UltronLive } from "ultron-live-sdk";

// CommonJS
const { UltronLive } = require("ultron-live-sdk");

Or via UMD in a plain browser page:

html
<script src="https://cdn.skypack.dev/ultron-live-sdk"></script>
You need an API key (ulk_…) or a JWT to use protected features. Get a key from your dashboard, or via the auth flow below.

Quick Start

Initialize with your key and start a screen-share commentary loop in three lines:

ts
import { UltronLive } from "ultron-live-sdk";

const ultron = new UltronLive({ apiKey: "ulk_your_api_key" });

await ultron.startScreenShare({
  model: "gemini-2.5-flash",
  onTranscript: (text) => console.log("AI:", text),
  onCreditsUpdate: (remaining) => console.log("credits:", remaining),
  onCreditsExhausted: () => alert("Top up to continue"),
});

// later…
ultron.stop();

Configuration

Create one instance with new UltronLive(config). Everything (REST, WebRTC, realtime voice) inherits these settings — including the API version.

ts
const ultron = new UltronLive({
  apiKey: "ulk_your_api_key",   // or token: "<jwt>"
  apiVersion: "v1",             // "v1" (default) or "v2"
  model: "gemini-3.1-flash-lite-preview",
  frameInterval: 1500,          // ms between captured frames
  frameQuality: 0.4,            // JPEG quality 0–1
  maxFrameWidth: 1280,
  maxFrameHeight: 720,
});
FieldTypeRequiredNotes
apiKeystringrequiredYour key (ulk_…). Either apiKey or token is required.
tokenstringoptionalJWT from auth.verifyOtp().
baseUrlstringoptionalBackend URL. Defaults to the production API.
apiVersion'v1' | 'v2'optionalBackend workflow. Default 'v1'. See Versioning.
modelModelValueoptionalDefault vision model. Default gemini-3.1-flash-lite-preview.
historyWindownumberoptionalRecent commentary strings kept for context. Default 5.
frameIntervalnumberoptionalms between frame captures. Default 1500.
frameQualitynumberoptionalJPEG quality 0–1. Default 0.4.
maxFrameWidthnumberoptionalMax capture width px. Default 1280.
maxFrameHeightnumberoptionalMax capture height px. Default 720.

Read it back any time via ultron.config, and check the active version with ultron.apiVersion. Update credentials at runtime with ultron.setApiKey(key) or ultron.setToken(jwt).

API Versions (v1 & v2)

The backend runs two parallel workflows. Choose one per instance with apiVersion — it flows through REST, createWebRTC(), and createRealtimeVoice() automatically.

v1 — Stable (default)v2 — Current
Vision pipelineOne model call per frameGolden Frame pipeline (filter + two-tier)
Extra featuresAssessment engine, MCP servers
Realtime voiceStandard relayRelay with realtime tools
ts
// Stable (default) — unchanged behavior
const ultron = new UltronLive({ apiKey: "ulk_..." });

// Current — golden frames, assessment, MCP, realtime tools
const ultronV2 = new UltronLive({ apiKey: "ulk_...", apiVersion: "v2" });
Backward compatible: v1 is the default, so upgrading the package never changes behavior. Calling a v2-only API (assessment.*, mcp.*) on a v1 instance throws a clear error.

Running non-golden (legacy per-frame)

On v2 the Golden Frame pipeline is on by default — omitting golden does not turn it off. Two ways to run the classic one-call-per-frame mode:

ts
// (a) Per session on v2 — keep tools/assessment, skip golden filtering
rtc.startSession({ golden: { enabled: false } });

// (b) Whole instance — the entire stable pipeline
const ultron = new UltronLive({ apiKey: "ulk_...", apiVersion: "v1" });

Authentication

The flow is always: request an OTP → verify it → get a JWT + API key. Use signup for a new account, login for an existing one.

ts
// 1. Request an OTP (emails a 6-digit code)
await ultron.auth.signup({ email: "user@example.com", firstName: "Ada" }); // new user
// or: await ultron.auth.login({ email: "user@example.com" });            // existing user

// 2. Verify the code → JWT + user (incl. permanent apiKey)
const { data } = await ultron.auth.verifyOtp({ email: "user@example.com", otp: "123456" });
ultron.setToken(data.token);
console.log(data.user.apiKey, data.user.credits);

// 3. Live profile + credits any time
const me = await ultron.auth.getMe();
MethodDescription
auth.signup(opts)New account → emails an OTP.
auth.login(opts)Existing account → emails an OTP.
auth.sendOtp(opts)Legacy get-or-create + OTP (kept for compatibility).
auth.verifyOtp(opts)Verify OTP → { token, user }.
auth.getMe()Current profile + live credit balance.
setToken(jwt) / setApiKey(key)Update credentials at runtime.

Account & Billing

Profile, transaction history, subscription, and checkout helpers.

ts
// Profile
await ultron.auth.updateProfile({ firstName: "Ada", dateOfBirth: "1990-12-10" });
await ultron.auth.updateTimezone({ timezone: "Asia/Kolkata" });

// Billing info
const { data } = await ultron.auth.getTransactions({ page: 1, limit: 20 });
const sub = await ultron.auth.getSubscription();
await ultron.auth.cancelSubscription();   // cancels at period end

// Start a checkout — redirect the user to pay
const session = await ultron.billing.createCheckoutSession({ planID: "price_123" });
window.location.href = session.data.url;
After the user returns from checkout, refresh state with auth.getSubscription() and auth.getMe(). Plan and credits are activated server-side, so the client never confirms payment itself.

Screen & Video Streaming

The high-level streaming API requests screen/camera access, runs a capture loop, and emits callbacks — no manual frame handling.

ts
// Screen share
await ultron.startScreenShare({
  onTranscript: (text) => render(text),
  onCreditsUpdate: (n) => setCredits(n),
  onError: (e) => console.error(e),
});

// Any MediaStream (camera, <video>.captureStream(), etc.)
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
await ultron.startVideoStream({ stream, onTranscript: console.log });

ultron.stop();

Live preview

ts
ultron.attachPreview(document.getElementById("preview"));  // attach captured stream to a <video>
const stream = ultron.getPreviewStream();                   // or wire it up yourself

Voice narration

ts
ultron.setAudioEnabled(true);
ultron.configureAudio({ voiceProvider: "gemini", geminiVoiceName: "Zephyr" });
MethodDescription
startScreenShare(opts?)Request screen share + run the commentary loop.
startVideoStream(opts)Run commentary on any MediaStream.
stop()Stop the active loop and clean up.
attachPreview(el) / detachPreview(el)Attach/detach the live stream to a <video>.
getPreviewStream()The active MediaStream, or null.
setAudioEnabled(bool) / configureAudio(opts)Toggle and configure TTS narration.
isStreaming / sessionIdStream state + active session id.

Frame Analysis & Chat

Low-level REST calls when you want to drive frames/chat yourself.

ts
const { sessionId } = await ultron.startSession();

const result = await ultron.analyseFrame({
  image: "data:image/jpeg;base64,...",
  history: previousCommentaries,
  sessionId,
});
console.log(result.response, result.creditsRemaining);

const reply = await ultron.chat({
  sessionId,
  message: "What was I working on?",
  enableAudio: true,
});
For high-frequency live use, prefer WebRTC (below) — it avoids per-frame HTTP overhead.

WebRTC (Low-Latency)

A persistent peer connection with data channels for frames, chat, and control — much lower latency than REST. Create one pre-wired with your credentials and version:

ts
const rtc = ultron.createWebRTC();

rtc.onFrameResult = (r) => render(r.response, r.creditsRemaining);
rtc.onConnected = () => rtc.startSession();
await rtc.connect();

// Send frames (binary preferred — no base64 bloat)
canvas.toBlob((blob) => rtc.sendFrame(blob), "image/jpeg", 0.4);

// Chat over the data channel
rtc.sendChat("What changed on screen?", { enableAudio: true });

rtc.stopSession();
rtc.disconnect();

v2: Golden pipeline & live assessment

On apiVersion: "v2" the session runs the Golden Frame pipeline and can act as a live assessment session. Pass seq + captureTs so frames can be ordered, and read info.ingestFps to pace your capture.

ts
const ultron = new UltronLive({ apiKey: "ulk_...", apiVersion: "v2" });
const rtc = ultron.createWebRTC();

rtc.onFrameResult = (f) => console.log("frame:", f.response);
rtc.onFlowResult  = (s) => console.log("summary:", s.response);   // tier-2 narrative

// Assessment session — structured verdict instead of commentary
rtc.onAssessmentResult = (r) => console.log("verdict:", r.assessment);
rtc.onConnected = () => rtc.startSession({
  outputType: "json",
  prompt: "Verify the procedure.",
  responseSchema: { type: "object", properties: { verdict: { type: "string" } }, required: ["verdict"] },
});
await rtc.connect();

let seq = 0;
setInterval(() => rtc.sendFrameBase64(base64, { seq: seq++, captureTs: Date.now() }), 150);
// rtc.stopSession()  → emits the final assessment:result
// rtc.finalize()     → verdict mid-stream, keep streaming

Methods & callbacks

MethodDescription
connect()Connect; resolves when all 3 channels are open.
sendFrame(blob | buffer)Send a binary JPEG frame.
sendFrameBase64(b64, { seq?, captureTs? })Send a base64 frame with ordering metadata (v2).
sendChat(message, opts?)Send a chat message.
startSession(config?)Start a session; pass golden/assessment config on v2.
stopSession() / finalize()End the session / emit a verdict mid-stream (v2).
setModel(m) / ping() / disconnect()Change model, measure latency, tear down.

Callbacks: onFrameResult, onFrameError, onChatResult, onSessionStarted(id, info?), onConnected, onDisconnected, and (v2) onFlowResult, onAssessmentProgress, onAssessmentResult, onAssessmentError, onSessionStartError.

Realtime Voice

Two-way live voice with OpenAI Realtime or Gemini Live, normalized to one protocol. Audio plays back automatically by default.

ts
const voice = ultron.createRealtimeVoice({ provider: "gemini" });

voice.onReady = () => console.log("ready — start streaming mic");
voice.onTranscriptDelta = (t) => appendCaption(t);
voice.onUserTranscript = (t) => showUserSaid(t);

await voice.connect();                 // waits for relay:ready
voice.sendAudio(base64Pcm16Chunk);     // PCM16 mono, 16kHz (gemini) / 24kHz (openai)
voice.disconnect();
Wait for onReady before sending audio. The relay does not resample — send 16 kHz for Gemini, 24 kHz for OpenAI; playback is 24 kHz. Server VAD handles turn-taking and barge-in.

Assessment

Requires apiVersion: "v2". Turns media (a video, frames, or documents) into a calibrated PASS / FAIL / UNCERTAIN verdict with a confidence score.

assessAndWait uploads the media and polls until the verdict is ready:

ts
const ultron = new UltronLive({ apiKey: "ulk_...", apiVersion: "v2" });

const result = await ultron.assessment.assessAndWait({
  media: [fileInput.files[0]],            // video, frames, or documents (≤30, ≤18 MB each)
  outputType: "json",
  prompt: "Verify the sample-collection procedure.",
});

// Calibrated verdict (json output):
const v = JSON.parse(result.assessment);
v.verdict;        // 'PASS' | 'FAIL' | 'UNCERTAIN'
v.confidence;     // 0–100 (lowest per-check confidence)
v.needs_review;   // true → route to a human
v.checks;         // [{ name, result, confidence, observed }]

Calibrated verdict & human-in-the-loop

For outputType: "json" the fields verdict, confidence, needs_review and per-question checks[] are guaranteed. An element that can't be directly verified is capped low and marked UNCERTAIN (absence of evidence is never a confident PASS/FAIL). When confidence is below the template's confidenceThreshold (default 70), the verdict is forced to UNCERTAIN + needs_review: true — so a human is engaged automatically.

ts
const v = JSON.parse(result.assessment);
if (v.needs_review) routeToHumanReviewer(v);   // low confidence or genuinely uncertain
else applyAutomatically(v.verdict);

Add or skip questions

Adjust a template's questions for one run without editing it — append extraChecks or drop existing ones with skipChecks (by 1-based index or title). The same fields work on a live rtc.startSession() call.

ts
await ultron.assessment.assessAndWait({
  media: [file],
  templateId: tpl.id,
  extraChecks: [{ title: "Gloves worn", instruction: "Were gloves worn the whole time?" }],
  skipChecks: [2, "Identity Match"],          // drop question #2 and "Identity Match"
});

// Permanent change to the test's questions:
await ultron.assessment.templates.update(tpl.id, { checks: [...tpl.checks, newCheck] });

Off-camera collections

For privately-collected types (urine, vaginal, rectal) where only the post-collection sealing/packaging is on camera, set collectionMode: "off_camera". It auto-skips every check marked onCameraOnly: true and tells the model not to penalize the unseen collection — evaluating only what's on screen.

ts
await ultron.assessment.assessAndWait({ media: [file], templateId, collectionMode: "off_camera" });
rtc.startSession({ outputType: "json", templateId, collectionMode: "off_camera" });

// Mark collection-step questions so they drop automatically in off-camera mode:
//   checks: [{ title: "Proper Collection", instruction: "…", onCameraOnly: true }, …]

Single frame, and saved presets (templates):

ts
await ultron.assessment.assessFrame(base64DataUrl, { outputType: "json", prompt: "Gauge in green?" });

const { data: templates } = await ultron.assessment.templates.list();
await ultron.assessment.assessAndWait({ media: [file], templateId: templates[0].id, fields: { type: "swab" } });
File inputs: in the browser pass File/Blob directly; in Node pass { data: buffer, filename, contentType }. Live assessment over a screen share uses the WebRTC client (see WebRTC → v2).

MCP Servers

Requires apiVersion: "v2". Manage the user's own MCP (web-MCP) tool endpoints. HTTP transport only; secret header values are encrypted at rest and never returned (only a masked hint).
ts
const ultron = new UltronLive({ apiKey: "ulk_...", apiVersion: "v2" });

const { data: server } = await ultron.mcp.servers.create({
  name: "docs",
  url: "https://example.com/mcp",
  headers: { "X-Workspace": "acme" },
  secrets: [{ key: "Authorization", value: "Bearer abc123" }],   // encrypted at rest
});

await ultron.mcp.servers.test(server.id);     // connect + list tools to validate
const { data: servers } = await ultron.mcp.servers.list();
const { data: tools }   = await ultron.mcp.tools();   // effective tools for the user
MethodDescription
mcp.servers.list() / get(id)List / fetch the user's servers (secrets masked).
mcp.servers.create(input)Add a server { name, url, headers?, secrets? }.
mcp.servers.update(id, input) / remove(id)Update (re-encrypts secrets) / delete.
mcp.servers.test(id)Connect + list tools to validate config.
mcp.tools()Effective tools available to the user.

Text-to-Speech

Convert text to speech and play it:

ts
const blob = await ultron.tts({ text: "Hello!", voiceName: "Zephyr" });
new Audio(URL.createObjectURL(blob)).play();

Models

Browse the model catalogue and switch models at runtime:

ts
ultron.models;                          // ModelMeta[] — full catalogue
ultron.getModelsByProvider("gemini");   // filter by provider
ultron.getModelMeta("gpt-4o");          // metadata for one model
ultron.setModel("gemini-2.5-flash");    // change the default (no restart)

Error Handling

All API failures throw typed errors you can branch on:

ts
import { UltronAuthError, UltronCreditsError, UltronAPIError } from "ultron-live-sdk";

try {
  await ultron.analyseFrame({ image });
} catch (err) {
  if (err instanceof UltronCreditsError) promptTopUp();        // 402
  else if (err instanceof UltronAuthError) redirectToLogin();  // 401
  else if (err instanceof UltronAPIError) console.error(err.statusCode, err.message);
}
MethodDescription
UltronAPIErrorBase error — has .statusCode and .message.
UltronAuthError401 — missing/invalid/expired credentials.
UltronCreditsError402 — insufficient credits.

Full Method Reference

The complete surface of the main UltronLive instance.

MethodDescription
auth.{ signup, login, sendOtp, verifyOtp, getMe, updateProfile, updateTimezone, getTransactions, getSubscription, cancelSubscription }Account & session.
billing.createCheckoutSession(opts)Start a Stripe checkout.
startSession() / analyseFrame(opts) / chat(opts)Low-level REST session, frame, chat.
startScreenShare(opts?) / startVideoStream(opts) / stop()High-level streaming.
attachPreview / detachPreview / getPreviewStreamLive preview.
setAudioEnabled / configureAudioVoice narration.
tts(opts)Text-to-speech → audio Blob.
models / getModelMeta / getModelsByProvider / setModelModel catalogue & selection.
createWebRTC(overrides?)Low-latency WebRTC client.
createRealtimeVoice(overrides?)Realtime voice client.
assessment.* (v2)assess, assessAndWait, get, list, assessFrame, templates.*
mcp.* (v2)servers.{ list,get,create,update,remove,test }, tools()
setApiKey / setToken / config / apiVersionCredentials, config, active version.