SpekoLLM
LiveKit Agents LLM adapter backed by POST /v1/complete.
SpekoLLM is a llm.LLM implementation. It flattens a LiveKit ChatContext into Speko's messages format and calls the proxy. The router picks the best LLM provider per intent and fails over automatically.
import { SpekoLLM } from '@spekoai/adapter-livekit';
const spekoLLM = new SpekoLLM({
speko,
intent: { language: 'en' },
temperature: 0.7,
maxTokens: 400,
});Unlike STT and TTS, SpekoLLM doesn't need a StreamAdapter. It calls the
streaming /v1/complete endpoint through the SDK and emits a LiveKit
LLMStream chunk when the routed completion is ready.
Constructor
new SpekoLLM(options: SpekoLLMOptions)SpekoLLMOptions
| Field | Type | Required | Description |
|---|---|---|---|
speko | Speko | ✅ | @spekoai/sdk client. |
intent | Intent | ✅ | Validated at construction time. |
temperature | number? | Forwarded to /v1/complete. | |
maxTokens | number? | Forwarded to /v1/complete. | |
constraints | PipelineConstraints? | Allow-list constraints. | |
agentId | string? | When set, enables the registered-tools loader. The adapter calls speko.agents.tools.listChatTools(agentId) once per session — using the speko client for auth and base URL — and merges the result with LiveKit's runtime ToolContext. Registered tools win on collision. Omit to keep runtime-only behavior. See tool calling. | |
apiBaseUrl | string? | Deprecated and ignored — the loader reads the base URL from the speko client. Safe to omit. | |
apiKey | string? | Deprecated and ignored — the loader reads the API key from the speko client. Safe to omit. | |
onRegisteredToolsError | (err: Error) => void? | Called once if the registered-tools fetch fails. Soft degradation — the call continues with runtime-only tools rather than crashing. |
Properties
label() → 'speko.LLM'provider = 'speko'model = 'speko-router'
.chat(params)
Standard LiveKit LLM entry point. Returns an LLMStream that emits a ChatChunk
carrying the assistant response or tool calls, then closes.
Signature (from @livekit/agents):
chat(params: {
chatCtx: llm.ChatContext;
toolCtx?: llm.ToolContext;
connOptions?: APIConnectOptions;
parallelToolCalls?: boolean;
toolChoice?: llm.ToolChoice;
extraKwargs?: Record<string, unknown>;
}): llm.LLMStream;The emitted chunk includes usage:
{
id: '<uuid>',
delta: { role: 'assistant', content: result.text },
usage: {
promptTokens: result.usage.promptTokens,
completionTokens: result.usage.completionTokens,
promptCachedTokens: 0,
totalTokens: result.usage.promptTokens + result.usage.completionTokens,
},
}Context conversion — chatContextToSpeko
Exported for when you want to reuse the flattening logic (e.g. unit tests, custom pipelines).
import { chatContextToSpeko } from '@spekoai/adapter-livekit';
const messages = chatContextToSpeko(chatCtx);Rules:
- Only
llm.ChatMessageitems are considered. Function-call and handoff items are skipped. - Roles are normalised:
developer→system;system/user/assistantpass through; anything else is dropped. - Empty
textContentmessages are skipped. - Ordering is preserved.
If the result is empty, .chat() rejects with SpekoAdapterError('INVALID_CONTEXT').
Tool Calls
Runtime tools from LiveKit's toolCtx are forwarded as inline tools. Registered
webhook, builtin, and integration tools can also be loaded by agentId — the
same set speko.agents.tools.listChatTools(agentId) returns — and executed
server-side by Speko before the final response is returned to LiveKit.
Errors
SpekoAdapterError(exported): thrown for adapter-internal problems.codeis one of:'INVALID_CONTEXT'—ChatContextproduced no convertible messages.
API-layer errors from the underlying speko.complete() surface unchanged — SpekoApiError, SpekoAuthError, SpekoRateLimitError from @spekoai/sdk.