@layrs_ai/dsa-tutor-sdk
v0.1.33
Published
Shared React SDK for the Layrs DSA voice tutor.
Readme
@layrs/dsa-tutor-sdk
Shared React SDK for opening the Layrs DSA voice tutor from another product.
The SDK owns:
- LiveKit room connection and microphone publishing.
- Agent audio playback.
app.controldata-channel publishing and receiving.- Tutor transcript state.
- A reusable
DsaTutorLauncherroom UI.
The host app owns:
- Authentication.
- Entitlement checks.
- Token minting.
- Problem lookup.
- Code execution, submissions, history, and app-level theme state through
optional
DsaTutorLaunchercallbacks.
Microphone & audio requirements (voice mode)
The SDK asks for the microphone before joining the room, so the tutor never greets a student it can't hear. Host-app checklist:
- If the SDK is rendered inside an
<iframe>, the frame MUST declareallow="microphone; autoplay"— without it,getUserMediafails instantly in every browser and no student audio ever reaches the tutor (this presents as sessions where the tutor talks and the student is silent). - Serve over HTTPS (
getUserMediarequires a secure context). - Start the session from a click handler so the browser autoplay policy
lets the tutor's audio play. If playback is still blocked, the hook
exposes
audioBlocked+resumeAudio()and the launcher shows an "Enable audio" button. - A denied/missing mic does not kill the session: the state becomes
mic_blocked, the tutor says it can't hear the student, typing keeps working, andretryMic()(the "Retry mic" button) re-attempts capture after the user fixes the permission.
Usage
import {
DsaTutorLauncher,
type DsaTutorTokenProvider,
} from "@layrs/dsa-tutor-sdk";
const tokenProvider: DsaTutorTokenProvider = async ({ problem, sheetId }) => {
const session = await api.voiceTutor.createDsaSession.mutate({
questionId: problem.id,
sheetId: Number(sheetId),
});
return {
token: session.token,
livekitUrl: session.livekitUrl,
roomName: session.roomName,
identity: session.identity,
problemSlug: session.problemSlug,
problemId: session.problemId,
};
};
<DsaTutorLauncher
problem={{
id: question.id,
title: question.title,
difficulty: question.difficulty,
problemLink: question.problemLink,
}}
sheetId={sheetId}
tokenProvider={tokenProvider}
onRun={async ({ code, language, problem }) => {
await runCode({ code, language, problemId: problem.id });
}}
onSubmit={async ({ code, language, problem }) => {
await submitCode({ code, language, problemId: problem.id });
}}
/>;Without onRun / onSubmit, those buttons remain visible but show a host-not-wired
notice instead of silently doing nothing.
Token Provider Contract
tokenProvider must return a LiveKit participant token that dispatches the
existing voice-agent worker with metadata including:
agentType: "dsa_practice_coach"problemSlug/problem_slugproblemId/problem_iduserId/user_id
In LearnYard, the browser calls the LearnYard API. LearnYard API calls Tryst. Tryst mints the LiveKit token and injects the agent metadata.
Publishing
This package is configured for a private npm publish under the @layrs scope.
cd /Users/sameer/Documents/voice-agent/dsa-tutor-sdk
pnpm run clean
pnpm run check-types
pnpm run build
npm login
npm publish --access restrictedConsumers can then install it as:
"@layrs/dsa-tutor-sdk": "^0.1.0"