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
npm install ultron-live-sdkImport
// ESM (recommended)
import { UltronLive } from "ultron-live-sdk";
// CommonJS
const { UltronLive } = require("ultron-live-sdk");Or via UMD in a plain browser page:
<script src="https://cdn.skypack.dev/ultron-live-sdk"></script>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:
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.
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,
});| Field | Type | Required | Notes |
|---|---|---|---|
| apiKey | string | required | Your key (ulk_…). Either apiKey or token is required. |
| token | string | optional | JWT from auth.verifyOtp(). |
| baseUrl | string | optional | Backend URL. Defaults to the production API. |
| apiVersion | 'v1' | 'v2' | optional | Backend workflow. Default 'v1'. See Versioning. |
| model | ModelValue | optional | Default vision model. Default gemini-3.1-flash-lite-preview. |
| historyWindow | number | optional | Recent commentary strings kept for context. Default 5. |
| frameInterval | number | optional | ms between frame captures. Default 1500. |
| frameQuality | number | optional | JPEG quality 0–1. Default 0.4. |
| maxFrameWidth | number | optional | Max capture width px. Default 1280. |
| maxFrameHeight | number | optional | Max 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 pipeline | One model call per frame | Golden Frame pipeline (filter + two-tier) |
| Extra features | — | Assessment engine, MCP servers |
| Realtime voice | Standard relay | Relay with realtime tools |
// 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" });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:
// (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.
// 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();| Method | Description |
|---|---|
| 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.
// 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;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.
// 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
ultron.attachPreview(document.getElementById("preview")); // attach captured stream to a <video>
const stream = ultron.getPreviewStream(); // or wire it up yourselfVoice narration
ultron.setAudioEnabled(true);
ultron.configureAudio({ voiceProvider: "gemini", geminiVoiceName: "Zephyr" });| Method | Description |
|---|---|
| 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 / sessionId | Stream state + active session id. |
Frame Analysis & Chat
Low-level REST calls when you want to drive frames/chat yourself.
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,
});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:
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.
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 streamingMethods & callbacks
| Method | Description |
|---|---|
| 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.
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();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
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:
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.
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.
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.
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):
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/Blob directly; in Node pass { data: buffer, filename, contentType }. Live assessment over a screen share uses the WebRTC client (see WebRTC → v2).MCP Servers
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).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| Method | Description |
|---|---|
| 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:
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:
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:
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);
}| Method | Description |
|---|---|
| UltronAPIError | Base error — has .statusCode and .message. |
| UltronAuthError | 401 — missing/invalid/expired credentials. |
| UltronCreditsError | 402 — insufficient credits. |
Full Method Reference
The complete surface of the main UltronLive instance.
| Method | Description |
|---|---|
| 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 / getPreviewStream | Live preview. |
| setAudioEnabled / configureAudio | Voice narration. |
| tts(opts) | Text-to-speech → audio Blob. |
| models / getModelMeta / getModelsByProvider / setModel | Model 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 / apiVersion | Credentials, config, active version. |