Sari la conținut
megapromotingHai să discutăm
Produse Kallina

Agenți vocali AI Platformă

A good conversation carries on into an action.

We build agents that take and place calls, use the business's own information, and work with your systems. From the first question through to a complete request, a confirmation, or a handover to a colleague.

AscultăVerificăAcționeazăVOCE + CONTEXT + ACȚIUNE
Cum funcționează Kallina

Kallina

From information to work done.

01

Ascultă

Understands the request in the context of the conversation and the rules of the business.

02

Verifică

Consults the knowledge base and the authorised integrations before answering.

03

Acționează

Fills in the data, performs the permitted action, or hands the conversation to a person.

Where it earns its place.

Reception and support

Frequent questions, taking requests, and calling back the people who asked to be contacted.

Orders and deliveries

Confirmations and coordination, using the data from the connected order system.

Qualification and appointments

Gathers the details needed. Calendar access and booking are agreed per integration.

The scenarios, the phone number, the languages and the actions are configured for each deployment. The team keeps the ability to take a conversation over.

Kallina in detail

What you can do with this project.

Kallina is the platform on which we build agents that speak on the phone and in the web page. An agent has a written role, an approved knowledge base, a set of tools it may call, and a boundary past which it hands the conversation to a person. The conversation does not end in the transcript: a call has a duration, a per-provider cost, a recording and an analysis, all tied to the business's account.

There is no single voice engine. In the agent's configuration you choose between ElevenLabs Conversational AI, OpenAI Realtime, Gemini Live, or "auto", in which case Kallina picks the provider by language, load and availability. On top of that you choose the text brain separately — the catalogue in the code holds 78 entries from OpenAI, Google, Anthropic, xAI and ElevenLabs, each with its latency and its cost per minute shown in the interface, so that the choice is an informed one rather than hearsay.

We run the telephony ourselves; it is not rented from the voice provider. Calls pass through our own Asterisk, with routing by opening hours and time zone, overnight schedules (22:00 → 06:00, for example) and priority matching: the SIP Diversion header, then the Kallina number, then the fallback rule. For OpenAI Realtime there is an AudioSocket bridge that converts the codec both ways, g711_ulaw ↔ PCM16.

01

Three voice providers plus an "auto" position

`AGENT_PROVIDERS` holds four options: `elevenlabs` (ConvAI), `openai-realtime`, `gemini-live` and `auto`. For text-to-speech in languages other than English the default is `eleven_flash_v2_5` — 32 languages, roughly 75 ms of latency; the higher-quality alternative, `eleven_turbo_v2_5`, costs roughly 250 ms. The choice is not buried in the code, it is a field in the agent's configuration.

02

A model catalogue with latency and cost on show

78 models in `LLM_MODELS`, grouped by provider in the interface together with the measured latency and the cost per minute — from `gpt-5-nano` at roughly 806 ms and about $0.0004/min, up to `claude-sonnet-4-6` at roughly 1.55 s and about $0.0225/min. A client who asks "why is it answering slowly" gets an answer in numbers, not an opinion.

03

Our own telephony on Asterisk

Call forwarding is configured by working hours and time zone, with support for overnight schedules and priority matching (SIP Diversion header → Kallina number → fallback rule). The `openai-realtime-bridge` performs the AudioSocket conversion between g711_ulaw and PCM16 for the two-way audio stream.

04

A one-line voice embed, with no agent id in the page

`<script src="https://app.kallina.info/embed.js" data-widget="WIDGET_ID"></script>`. The page never learns which agent is answering and holds no provider key: it asks Kallina for a session, and Kallina returns a short-lived signed URL. There is also `data-mode="inline"`, in which the embed draws nothing at all and the page builds its own interface on top of the `start()` / `stop()` / `toggle()` / `on(event, fn)` API.

05

Outbound call campaigns

Batch dialling with 1–10 concurrent calls, contact import from CSV, retry logic, live tracking with pause, resume and stop, plus SMS follow-up.

06

Limbi

The agent configuration accepts 32 languages (`LANGUAGES`), the platform's full language map has 41 entries, and the admin panel is translated into 20 (`src/i18n/locales`). Romanian is the default in `DEFAULT_VALUES`.

Data and operation

What goes into the system. What has to be checked.

Where the data lives
PostgreSQL through Supabase, with Row Level Security and pg_cron; 559 versioned migrations. The server logic is Deno edge functions — 472 in the repository at the date of checking.
What never reaches the client's page
The voice provider's key and the agent's identifier. The embed calls `POST /functions/v1/widget-voice-session` with `widget_id` — the public key from `chat_widget_configs.widget_id`, not the row's internal id — and the server itself asks ElevenLabs for a signed URL through `convai/conversation/get_signed_url` and returns it. The older variant, which put `agentId` straight into the HTML, bypassed Kallina entirely.
The knowledge base
Documents uploaded into the platform, synchronised with the ElevenLabs RAG. On top of them sit conversation guardrails, data-collection schemas and success criteria for the call, defined per agent.
Usage measured before, not after
The `usage_events` table holds consumption broken down by provider and by agent. Before any action that costs money, the `check-can-use` function verifies the credit — the gate sits in front of the call, not in the invoice at the end of the month.

From exploration to deployment

How we prepare a project with Kallina.

01

We pick a single path and write its edges

One scenario with a clear entry and a clear exit — an inbound call to reception, an order confirmation, a calling campaign. We write down explicitly what the agent must not do, and by which route it hands the conversation to a person.

02

We connect the number and test in both directions

The number joins the SIP trunk of our own Asterisk. Inbound and outbound calls are tested separately, because they break separately: a carrier restriction on outbound calls leaves inbound working perfectly.

03

We verify the path without burning minutes

`scripts/verify-voice-path.mjs` walks exactly the route a browser takes — the configuration row, `get-widget-config`, then `widget-voice-session` — and stops at the signed URL, without opening the websocket. It runs against a single widget or against every widget with voice enabled, 1–3 in parallel, and returns an exit code, so it can go straight into a cron job.

Questions worth settling.

Which voice engine does it use, exactly?

You choose between ElevenLabs Conversational AI, OpenAI Realtime and Gemini Live, or leave it on "auto" and let Kallina decide by language and availability. For speech synthesis in languages other than English the default is `eleven_flash_v2_5` — 32 languages, around 75 ms; if you want higher quality and accept more delay, `eleven_turbo_v2_5` is around 250 ms. OpenAI Realtime has ten voices, and their engine goes up to `gpt-realtime-2.1`.

How do you put it on a website?

One line: `<script src="https://app.kallina.info/embed.js" data-widget="WIDGET_ID"></script>`, loaded as an ordinary script, not as a module. The file is served today and is 13,762 bytes. If you want your own interface, `data-mode="inline"` draws nothing and leaves you `start()`, `stop()`, `toggle()` and the `state`, `message` and `error` events. Watch the hostname: the file sits on `app.kallina.info`, not on `kallina.info` — two applications on two different servers.

Are minutes used if the visitor refuses the microphone?

No. The order in `embed.js` is: load the SDK, request the microphone with `getUserMedia({audio:true})`, and only then call `widget-voice-session`. If the person refuses the microphone, the session request is never made at all, so no signed URL is issued and nothing is consumed.

Can it call first, not only answer?

Yes — batch dialling, 1–10 at a time, contacts from CSV, retries and SMS follow-up. But outbound calls depend on the telephone carrier, not only on us: our issue log documents a case in which the carrier's switch started returning `403 Forbidden` on every outbound call, with our configuration unchanged and inbound calls working normally. That is why we test outbound separately before promising a campaign.

How many languages does it speak, and how many is it administered in?

The agent configuration accepts 32 languages, the internal language map has 41 entries, and the admin panel is translated into 20. Romanian is the default language for new agents.

Does it deploy automatically on every code change?

No, and it is worth knowing before you plan a launch. The GitHub workflow in the repository targets a Supabase Cloud project that has been deleted, so "push to main = deploy" has not been true since the move to our own infrastructure. The real deployment goes over SSH, by copying and restarting. The practical consequence: an urgent change needs a person, not just a commit.

What happens if the agent does not know the answer?

Handing over to a person is part of the scenario, not an exception. Every agent has written boundaries and a transfer route configured on the telephony; and within the conversation there are guardrails and success criteria, precisely so that a case outside the role is stopped rather than improvised.

Illustrative example

A call that comes in at night and reaches the right place

A usage scenario, with no client data and no commercial results attributed.

The starting situation

Someone rings the business's number at 23:40, outside reception hours.

How it works

Asterisk applies the overnight rule (22:00 → 06:00, for example) and matches on priority: the SIP Diversion header, then the Kallina number, then the fallback rule. The night agent answers on the provider set in the configuration, clarifies the request, and calls the tools it is allowed to use.

Rezultatul

The call stays in the history with its transcript, audio recording, duration and cost broken down by provider. Anything beyond the agent's role is stopped and passed on, instead of being improvised.

Ce este necesar:Numărul conectat pe trunkul SIP al Asterisk-ului nostru, apelurile ieșite permise de operator dacă se dorește și sunat înapoi, plus un agent cu prompt, bază de cunoștințe aprobată și limite scrise.

Ways of working together

Kallina, in the context of your organisation.

Information and intake of requests

Voice assistance over approved information, with a route to a human operator and clear rules on recording and retaining conversations.

Private companies

We define a pilot around one real process: users, data, integrations, costs and acceptance criteria. Expansion follows once the result has been assessed.

Public institutions and state-owned companies

We establish the requirements for accessibility, hosting, data protection and interoperability. Any connection to services run by Moldova's e-Governance Agency (AGE) or its state information-technology service (STISC) requires eligibility, access and approvals to be validated.

These are adaptation scenarios, not statements about existing contracts or partnerships. The proposed capabilities are confirmed within the project's scope of work.

Discută un pilot

Part of an ecosystem.

What would you like to work better?

Tell us about your process. Together we work out what is worth building, what we can connect, and how we check the result.

Hai să discutăm