UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

75 lines (74 loc) • 2.6 kB
/** * Transport-agnostic voice brain. * * Given a user transcript and a stable conversation id, it streams the * assistant's reply as text deltas by calling `neurolink.stream()`. NeuroLink * owns history (via the conversation id and its memory layer) and tools (the * tool-calling loop runs inside `stream()`); this module never touches a * transport. The LiveKit worker (or any other transport) consumes the text * deltas and converts them to audio. * * See docs/features/livekit-voice-agent.md. */ import { logger } from "../../utils/logger.js"; /** * Extract spoken text from a stream chunk without type assertions. * * `StreamResult.stream` yields a union: text chunks (`{ content: string }`), * a no-output sentinel, and audio/image events. Only text chunks carry a * string `content`; everything else yields `undefined` and is skipped. */ function extractTextDelta(chunk) { if (typeof chunk === "object" && chunk !== null && "content" in chunk) { const value = chunk.content; if (typeof value === "string" && value.length > 0) { return value; } } return undefined; } /** * Create a voice brain bound to a configured NeuroLink instance. * * The returned `streamReply` is an async generator of text deltas for a single * turn. Aborting `turn.signal` stops the in-flight LLM and tool calls and ends * the generator promptly (barge-in support). */ export function createVoiceBrain(config) { const { neurolink, provider, model, systemPrompt, temperature, maxTokens, userId, } = config; async function* streamReply(turn) { const { transcript, conversationId, signal } = turn; if (signal?.aborted) { return; } const context = { sessionId: conversationId, conversationId, }; if (userId !== undefined) { context.userId = userId; } const result = await neurolink.stream({ input: { text: transcript }, provider, model, systemPrompt, temperature, maxTokens, context, abortSignal: signal, disableTools: false, }); for await (const chunk of result.stream) { if (signal?.aborted) { logger.debug("voice.brain.turnAborted", { reason: "signal-aborted" }); return; } const delta = extractTextDelta(chunk); if (delta !== undefined) { yield delta; } } } return { streamReply }; }