Speko Docs

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

FieldTypeRequiredDescription
spekoSpeko@spekoai/sdk client.
intentIntentValidated at construction time.
temperaturenumber?Forwarded to /v1/complete.
maxTokensnumber?Forwarded to /v1/complete.
constraintsPipelineConstraints?Allow-list constraints.
agentIdstring?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.
apiBaseUrlstring?Deprecated and ignored — the loader reads the base URL from the speko client. Safe to omit.
apiKeystring?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.ChatMessage items are considered. Function-call and handoff items are skipped.
  • Roles are normalised: developersystem; system / user / assistant pass through; anything else is dropped.
  • Empty textContent messages 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. code is one of:
    • 'INVALID_CONTEXT'ChatContext produced no convertible messages.

API-layer errors from the underlying speko.complete() surface unchanged — SpekoApiError, SpekoAuthError, SpekoRateLimitError from @spekoai/sdk.

On this page