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

@mentingo/luma-sdk

v0.4.1

Published

Luma API SDK

Readme

Luma SDK

TypeScript SDK for the Luma platform used by Mentingo.

It provides two separate clients:

  • HTTP client for durable course authoring, Mentor chat, assets, administration and configuration
  • Socket client for realtime audio/voice mentor flows

Installation

pnpm add @mentingo/[email protected]
# or
npm install @mentingo/[email protected]
# or
yarn add @mentingo/[email protected]

Quick Start (HTTP)

import { createLumaClient } from "@mentingo/luma-sdk";

const client = createLumaClient({
  baseURL: "https://your-luma-api.example.com",
  apiKey: process.env.LUMA_API_KEY,
});

const session = await client.authoring.createSession({
  commandId: crypto.randomUUID(),
  courseId: "00000000-0000-4000-8000-000000000001",
  actorId: "author-123",
  language: "en",
});

const snapshot = await client.authoring.getSession({ sessionId: session.sessionId });
console.log(snapshot.tasks);

Each client uses one apiKey. Supply an administration key for admin operations or an organization feature key for AI and course operations. The API validates the key's type and permissions; using a different SDK method does not grant additional access. To perform both kinds of operations, create separate clients with the appropriate keys.

The SDK sends that key as X-Admin-API-Key for luma.admin and as X-API-Key for feature operations, matching the existing API contracts.

const luma = createLumaClient({
  baseURL: "https://your-luma-api.example.com",
  apiKey: process.env.LUMA_ADMIN_API_KEY,
});

const keys = await luma.admin.apiKeys.list({ organizationId: "org-123" });
const created = await luma.admin.apiKeys.create({
  organizationId: "org-123",
  name: "Course generation",
});

await luma.admin.apiKeys.update({
  organizationId: "org-123",
  apiKeyId: created.id,
  name: "Updated course generation",
});

const configuration = await luma.admin.apiKeys.getConfiguration({
  organizationId: "org-123",
  apiKeyId: created.id,
});
const assignments = await luma.admin.apiKeys.listAssignments({
  organizationId: "org-123",
  apiKeyId: created.id,
});

Quick Start (Socket)

import {
  createLumaSocket,
  LUMA_AUDIO_ACTIONS,
  LUMA_AUDIO_FORMATS,
  LUMA_SOCKET_MESSAGE_TYPES,
} from "@mentingo/luma-sdk";

const socket = createLumaSocket({
  baseURL: "https://your-luma-api.example.com",
  apiKey: process.env.LUMA_API_KEY,
  socketData: {
    sessionId: "session-123",
    userId: "user-123",
    lessonId: "lesson-123",
  },
});

socket
  .onServerConnected((payload) => console.log("connected", payload))
  .onMentorTranscription((payload) => console.log("transcription", payload))
  .onAudioOutputChunk((payload) => console.log("audio chunk", payload));

socket.connect();

socket.startAudio({
  type: LUMA_SOCKET_MESSAGE_TYPES.AUDIO_START,
  audioAction: LUMA_AUDIO_ACTIONS.VOICE_MENTOR,
  meta: { sr: 16000, channels: 1, format: LUMA_AUDIO_FORMATS.PCM_S16LE },
});

socket.sendAudioChunk(
  {
    type: LUMA_SOCKET_MESSAGE_TYPES.AUDIO_CHUNK,
    meta: { seq: 1, sr: 16000, samples: 320, tsMs: Date.now() },
  },
  new Uint8Array([0, 1, 2]),
);

socket.stopAudio();

Recovery responses expose stable public constants for state handling:

import {
  AUDIO_PROVIDER_STATES,
  AUDIO_RECOVERY_STATES,
  type AudioRecoveryPayload,
} from "@mentingo/luma-sdk";

socket.onAudioRecovered((payload: AudioRecoveryPayload) => {
  if (payload.state === AUDIO_RECOVERY_STATES.MENTOR_ACTIVE) {
    // Keep the playback UI active after reconnecting.
  }

  if (payload.providerState === AUDIO_PROVIDER_STATES.RESTARTED) {
    // The transcription provider was recreated; replay unacknowledged chunks.
  }
});

HTTP Client API

createLumaClient(opts)

Options:

  • baseURL?: string - Luma API base URL.
  • apiKey?: string - single client credential; sent as X-Admin-API-Key for client.admin and X-API-Key for feature operations. The API enforces its type and permissions.
  • httpsAgent?: Agent - custom Node.js HTTPS agent.
  • allowInsecureTls?: boolean - if true, uses rejectUnauthorized: false (dev only).

Namespaces:

  • client.mentor.streamChat(opts) - stream mentor chat through the public custom-runtime endpoint. Pass voiceSessionId for voice mentor sessions so Luma can forward mentor text directly to the voice session.
  • client.mentor.chat(opts) - alias for client.mentor.streamChat(opts).
  • client.mentor.generateChat(opts, { signal? }) - generate a native non-stream chat response, with optional cancellation.
  • client.mentor.judge(opts)
  • client.ai.createEmbeddings(opts)
  • client.ai.generateJudgeConfiguration(opts)
  • client.ai.validateJudgeConfiguration(opts)
  • client.ai.generateTranslations(opts)
  • client.ai.transcribeDictation(opts)
  • client.configuration.get()
  • client.admin.apiKeys.list(opts)
  • client.admin.apiKeys.create(opts)
  • client.admin.apiKeys.get(opts)
  • client.admin.apiKeys.update(opts)
  • client.admin.apiKeys.revoke(opts)
  • client.admin.apiKeys.getConfiguration(opts)
  • client.admin.apiKeys.listAssignments(opts)
  • client.admin.apiKeys.updateAssignment(opts)
  • client.admin.modelProfiles.list(opts)

The HTTP client intentionally exposes public API operations through namespaces instead of flat top-level methods.

Runtime Configuration

Use client.configuration.get() to inspect which public AI capabilities are enabled for the API key. The SDK exports AiCapability, AiCapabilityMode, AiCapabilityProvider, AiRuntimeConfiguration, and convenience constants such as LUMA_AI_CAPABILITIES and LUMA_AI_CAPABILITY_MODES.

Custom model names should use the backend provider:model format, for example openai:gpt-4.1-mini or ollama:llama3.1.

Voice TTS capabilities expose an optional vendor (TTSProvider) for core-mode routing. API key settings use extensible non-secret metadata, for example metadata: { textToSpeechProvider: TextToSpeechProvider.Elevenlabs } in admin.apiKeys.update. Omitted metadata entries stay unchanged; setting an entry to null removes it. Credentials remain in the write-only textToSpeechApiKey field; hasTextToSpeechApiKey reports whether one is saved.

For voice mentor flows, use client.mentor.streamChat({ ..., voiceSessionId }) so streamed mentor text can be forwarded to the active socket session without a separate polling or relay step. Use client.mentor.generateChat(opts) for normal one-shot text responses. Tool-capable assistant calls use the native options below and do not attach a voice session.

Native Tool-Capable Chat

The existing Mentor client also carries assistant tool calls through Luma's native chat API. Luma resolves the API key's configured Custom chat profile; the SDK does not choose a vendor or contact an OpenAI chat-completions endpoint.

const result = await client.mentor.generateChat(
  {
    messages: [{ role: "user", content: "Read the course title." }],
    tools: [
      {
        name: "read_course",
        description: "Read an authorized course",
        inputSchema: { type: "object", properties: { courseId: { type: "string" } } },
      },
    ],
    toolChoice: "required",
    maxOutputTokens: 2500,
    streamFormat: "events",
  },
  { signal },
);
// result.toolCalls contains native { id, name, arguments } calls.
// Execute tools with the application's normal authorization checks, then append
// assistant toolCalls and role: "tool" / toolCallId messages to the next request.

For streaming, call client.mentor.streamChat(opts, { signal }) with streamFormat: "events". The existing /api/public/v1/ai/mentor/chat route returns UTF-8 NDJSON records: text-delta, complete tool-call, finish, or a stable error code. The response body remains the transport's readable stream; callers must decode UTF-8 and newline framing incrementally rather than treating each network chunk as one JSON event. The SDK does not execute tools or retry a stream. Generation uses the existing /api/public/v1/ai/mentor/chat/generate route.

Calls omitting tool/event options retain the existing { message } generation response and plain-text streaming behavior. streamChat already supports request cancellation in SDK 0.4.0; the optional generation signal parameter is added by SDK 0.4.1. Model execution, provider availability and fallback policy stay with Luma and the consuming application. Deploy the matching Luma native tool-chat contract before enabling event-mode callers.

Native Embeddings

Use the existing AI client to embed text with the API key's configured Custom embedding profile:

const result = await client.ai.createEmbeddings({
  texts: ["Customer onboarding policy"],
  dimensions: 1536,
});
// result.embeddings contains the vectors; result.model identifies the profile model.

This calls POST /api/public/v1/ai/embeddings with the normal X-API-Key transport. dimensions is optional and must be supported by the configured model. Luma validates the returned vector count, dimensions and finite values. The model identity comes from the same runtime resolution that produced the vectors. Texts-only calls remain valid. Older Luma responses may omit model; consumers that persist or compare vector spaces must reject missing identity rather than assuming a model. Matching dimensions alone do not make embedding spaces compatible.

The public contract is generated from Mentingo AI PR #63. The SDK update adds types and transport regressions; published SDK 0.4.0 already forwards these additive body and response fields unchanged at runtime. No OpenAI-format embeddings relay is used.

Durable Course Authoring

Use client.authoring to create/list sessions, read snapshots and events, subscribe to SSE, submit commands, upload source documents, answer authorized context requests, prepare frozen exports, and record application receipts. Course changes remain reviewable proposals; the SDK never applies them to the consuming application's database.

Snapshot tasks expose optional failure metadata with a stable code and recovery action. Clients should use retry_failed_parts, answer_question, retry_provider, or service_fix to present the appropriate next step rather than retrying every failure automatically.

Download generated visuals through client.authoring.downloadAsset({ sessionId, assetId, revision }). The download is authenticated and revision-bound; import the bytes into the consuming application's storage and render its native image node. Do not persist temporary download URLs.

Socket Client API

createLumaSocket(opts)

Options:

  • baseURL?: string
  • apiKey?: string
  • allowInsecureTls?: boolean
  • socketData?: { sessionId?: string; userId?: string; lessonId?: string }

Emit helpers:

  • startAudio(payload) -> emits start_audio
  • sendAudioChunk(payload, chunk) -> emits audio_chunk
  • sendClientSpeechStart(payload) -> emits client_speech_start
  • sendClientSpeechEnd(payload) -> emits client_speech_end
  • stopAudio(payload?) -> emits audio_stop
  • sendMentorTextDelta(payload) -> emits mentor_text_delta
  • sendMentorTextEnd(payload) -> emits mentor_text_end
  • sendMentorTextError(payload) -> emits mentor_text_error
  • sendPing(payload?) -> emits ping

Listener helpers:

  • onServerConnected(handler) -> listens server:connected
  • onAudioStarted(handler) -> listens audio:started
  • onAudioChunked(handler) -> listens audio:chunked
  • onAudioRecovered(handler) -> listens audio:recovered
  • onAudioStopped(handler) -> listens audio:stopped
  • onMentorTranscription(handler) -> listens mentor:transcription
  • onAudioOutputChunk(handler) -> listens audio:output:chunk
  • onAudioOutputInterrupted(handler) -> listens audio:output:interrupted
  • onAudioOutputError(handler) -> listens audio:output:error
  • onAudioOutputComplete(handler) -> listens audio:output:complete

Public Exports

  • HTTP: createLumaClient, LumaClient, LumaClientOptions, namespaced HTTP clients
  • Socket: createLumaSocket, LumaSocket, socket payload/event types from src/socket/types.ts
  • Shared API/domain types from src/types.ts

Development

pnpm install
pnpm --filter @mentingo/luma-sdk typecheck
pnpm --filter @mentingo/luma-sdk test
pnpm --filter @mentingo/luma-sdk build
pnpm --filter @mentingo/luma-sdk lint

Regenerate API client from OpenAPI schema

pnpm generate:client

Uses src/api/api-schema-public.json to regenerate src/api/generated-api.ts.

Notes

  • Built with tsup and ships ESM + CJS.
  • HTTP auth uses the X-API-Key header.
  • Keep API keys out of source control.