Skip to content
megapromotingLet's talk

Expertise · Voice agents

An agent that speaks — on your page and on the phone — and that can be interrupted.

We build voice agents on Kallina: a written role, an approved knowledge base, tools they call during the conversation and a limit beyond which they hand the discussion over to a human. Romanian is the default language of new agents.

Already builtThree in-house implementations, cited below. (1) The Kallina platform — 472 Deno edge functions and 559 database migrations, counted today in the repository; `https://app.kallina.info` returns 200. (2) The component on this site, `src/components/agents/KallinaVoiceAgent.tsx`, which implements the correct session path and documents the two ways a voice agent fails silently. (3) The `elevenlabs-bridge` bridge and the `openai-realtime-session`, where the real interruption and speech detection parameters live. The reserve we state: the phone part depends on a SIP host, and the host through which our test lines pass does not respond at the time of writing — see the telephony page. On the web, the path is verifiable today.

A voice agent, for us, is not "a bot that reads a script". It has four things written before the first call: a role, a knowledge base approved by you, a set of tools it is allowed to call, and a limit beyond which it hands the discussion to a person. What comes out of the conversation is not just a transcript: the call has duration, cost broken down by provider, recording and analysis, all linked to the business account.

The engine is not one single thing, and that is a decision, not an accident. In the agent configuration you choose between ElevenLabs Conversational AI, OpenAI Realtime and Gemini Live, or leave "auto" and the platform chooses according to language, load and availability. On top of it you separately choose the textual brain, from a catalogue in which each model has the latency and cost per minute displayed in the interface. When someone asks "why does it answer slowly", the answer has numbers, not opinions.

The part people feel most strongly is interruption. On OpenAI Realtime, speech detection is semantic, with threshold 0.5, a 300 ms cushion before and 500 ms of silence to consider that you have finished speaking; the "allow interruptions" switch is on by default. On ElevenLabs, the interruption event is passed on to the telephone exchange, so that playback stops immediately. And the time after which the agent considers your silence an answer is configurable per agent — on a sales agent written by us it is tightened to 12 seconds, compared with the default 15.

The agent lives in two different places, with different constraints. On the web page it enters with a single script line or with a custom component, and the golden rule is that the page never holds the agent identifier or any provider key — it asks the platform for a session and receives a signed, short-lived URL. On the phone it enters through a SIP trunk, and there the constraints are those of the operator and the exchange, not of the agent; we write about that separately, on the telephony page.

AI voice agents in the Republic of Moldova — how they work, in practice · video in Romanian, with subtitles and a transcript in English

Full transcription

All right, let’s go straight to the point. Today we’re doing an extremely precise technical analysis of how voice agents really work in the business environment. We’ll rely exclusively on the architecture of the Kallina platform, developed right here in the Republic of Moldova by MEGA PROMOTING S.R.L.. No marketing language, no inflated promises, just facts, pure infrastructure and, of course, operational reality. For any team that runs a business and relies on clear processes, understanding the technology under the hood is, frankly, absolutely essential. We have a very methodical path today. We go through six points. First we address the problem, then the mechanism of operation, then the anatomy of a failure, the engine and interruptions section, the technical limits and, finally, the next step.

It’s a totally transparent look at the system. So, the first section, the problem, time and requests. Let’s see exactly where we start. This is exactly the question that keeps operations managers up at night. Where exactly is operational time lost and, very importantly, how many unverified requests disappear every day. In a regular company, time simply evaporates between missed calls, requests that are not handled in time and all sorts of interactions that, well, simply cannot be checked later. And it’s not just a small discomfort issue. We’re talking about a huge operational resource that is lost day after day in an unoptimised workflow. Let’s move to part two, the mechanism, how it works. Let’s get into the actual engineering of the platform.

Take a look at this number, 472. This is the exact number of new Edge functions that keep the platform running at this moment. So, clearly, we’re not talking about a weekend prototype or a nice façade interface. It is massive infrastructure on a real server designed to handle extremely complex routing and business logic. And, to underline the level of maturity, there are exactly 559 database migrations on the PostgreSQL infrastructure, which is hosted through Supabase. These figures show us a rock-solid foundation with row-level security policies implemented. In practice, it’s a system built to scale and to keep data in impeccable order. Now, look at what the operation order on a web agent looks like, because this detail is absolutely brilliant.

At step 1, the page requests microphone access. At step 2, the visitor must accept. And only at step 3 is a request sent to the server to open a session, receiving back a signed URL valid only for a short period. Why is this such an important strategic move? Simple: if at step 2 the microphone is refused, the system does not go any further. Mathematically, that means 0 minutes consumed and 0 money thrown out the window for phantom sessions. Section 3 is probably my favourite. The anatomy of a failure. Because nothing builds trust more than total transparency, right? Imagine this nightmare scenario. A voice agent had been implemented on a web page, but when you pressed the button absolutely nothing happened.

No sound, no warning message, no error in the developer console. Complete silence. For anyone, even an experienced technician, such a fault seemed impossible to locate at first glance. Why? Because there was no error log. A completely silent failure. When we dug deeper, the technical analysis uncovered two completely invisible enemies. First, the server was sending a header that completely forbade microphone use. The browser, being obedient, followed the rule and refused the request, but did so without warning the visual interface. Second, a voice component was imported statically on the page. The file simply was not found, returning a 404 error. Because of that, the entire script crashed in the background, silently, blocking any further configuration. But look how elegant the solution was.

The problem, obviously, was not with AI, but directly with the network. The server header was changed to allow the microphone from its own source, you can see that there, in the repaired state, and the code import was moved exactly inside the button press action. The fault disappeared completely. Now, if someone presses the button and the microphone is blocked by the browser, the failure is no longer silent. A clear message appears instantly in Romanian that explains exactly what you need to change. That means engineering done properly, eliminating unpleasant surprises entirely. We move on to section four, engines, languages and interruptions. It’s time to examine exactly what this system is capable of. Here we leave subjective opinions aside and talk only in milliseconds.

When you use the Flash model from ElevenLabs, latency is only 75 milliseconds. To give you an idea, for the human ear, that is practically instant. On the other hand, if you prefer absolutely premium voice quality, as provided by the Turbo model, latency reaches around 250 milliseconds. In a phone call, every millisecond is critical, and the platform lets you choose exactly which engine you want, strictly according to the company’s operational needs. A super common question we hear is: OK, but can I interrupt the agent while it’s speaking? The answer is a firm yes, only the mechanism differs. For example, on OpenAI Realtime, detection is semantic. It has a threshold set at 0.5 and a technical safety buffer of 300 milliseconds.

In contrast, for ElevenLabs, the second an interruption occurs, an event goes straight to the PBX telephone switchboard to cut the sound instantly. Moreover, the period of silence the agent waits before responding in turn can be adjusted very precisely. It can be tightened to 12 seconds instead of the default value of 15, for example, which makes the conversation much more natural and alert. From the point of view of the supported languages, the official agent configuration successfully handles 32 different languages. But there is one operational aspect of maximum importance for us here? Romanian is set by default for absolutely all new agents created on this platform. We have reached the fifth section, technical limits and responsibilities, because sometimes it is just as important to know what a system cannot do, so that you have the right expectations.

Let us draw a very clear line. The agent can execute external functions, can trigger internal tools directly on the server, and can transfer the call to a human colleague without any problem. But the system forbids agents from improvising in strictly regulated fields. Think about it for a moment. An agent that starts improvising where legislation is extremely strict becomes a huge risk for the company, by no means an advantage. Moreover, things such as the automatic execution of data deletions after a certain term are not simply some ticks in a menu. They represent separate procedural projects that must be implemented specifically by the organisation. Security, on the other hand, is treated with absolute rigour. The web pages that host the agents receive exclusively that signed URL I was talking about.

Never, but absolutely never, do they receive an agent ID or an API key that could be stolen and used at the company’s expense. On the voice side, telephony depends 100% on a functional external SIP trunk and, to be as transparent as possible about the current limitations, the external SIP test lines are not answering at the moment. It is an extremely sincere approach from the engineers, showing that technical reality always comes first, beyond any commercial discussion. And here we are at the sixth section, the last one, by the way, the next step in the process. What do we do next with all this information? This whole technical dissection should lead us to a super objective assessment of your workflows.

That is the real stake. Which operational process inside the organisation actually needs to work more efficiently? We are not implementing artificial intelligence just for the sake of being trendy, right? The goal is to identify that exact, logical place where a voice agent can integrate rationally, can scale, and can function under the highest safety conditions. As a final point, here you have the operational coordinates of the company MEGA PROMOTING S.R.L. from Chișinău, including the IDNO and the web address? That is for a possible strictly technical discussion, meant to clarify how these complex structures can be integrated into the systems you already use in your business. Before any decision, I would leave a provocative question for us all to reflect on.

Would the current customer management processes in our companies really withstand a technical analysis as harsh and transparent as the one this system has gone through? In a market defined by constant innovation, a view based strictly on facts and figures remains by far the most powerful tool we have at our disposal. See you next time!

What it covers

The work, by component

The session is requested from the platform, not from the voice provider

The page sends `POST /functions/v1/widget-voice-session` with the widget's public identifier and receives a signed URL back. It never has the agent identifier or any key. The wrong variant — `startSession({ agentId })` directly in HTML — completely bypasses the platform's session, credit and log layer, and exposes the agent to anyone who opens the page source. It is the first check we make on any implementation we take over.

The microphone is requested before the session, so a refusal costs nothing

The order is fixed and it matters: request the microphone with `getUserMedia({audio:true})`, and only if the person accepts request the session. If the visitor refuses, no signed URL is issued and no minute is consumed. The microphone request is made inside the button press, before any wait that could outlast the gesture — otherwise the browser ignores the request.

The agent can be interrupted, and this is adjusted with numbers

On OpenAI Realtime: semantic speech detection, threshold 0.5, 300 ms cushion, 500 ms of silence, interruption enabled by default. On ElevenLabs: the `interruption` event is passed to the controller to stop playback. On top of that, per-agent `turn_timeout` decides after how much silence the agent considers it is their turn — 15 seconds by default, tightened to 12 on a sales agent. And a client-reported “I can’t interrupt it” often has another cause than the thresholds: responses that are too long. We address that in the prompt and in the token limit, not in speech detection.

Call tools during the conversation

The agent is not trapped in what it knows. It can call server functions while speaking — to read availability, write an appointment, send an SMS, or query a catalogue. Tools are declared per agent, with typed parameters and their own execution timeout, so a slow tool does not block the conversation.

Handing off to a human is part of the scenario, not an exception

In messaging, handover to a colleague has its own state on the thread — `handoff_status`, handover time, reason, who is assigned, resolution notes — implemented in a dedicated 619-line module. On the phone, the transfer is handled by the switch: blind transfer via `##` and assisted transfer via `*2`, with the call landing in a dialplan context written for that purpose. These are two different mechanisms because they are two different channels; we write both into the scenario.

The engine and the voice are chosen explicitly, not implicitly

Four supplier positions: `elevenlabs`, `openai-realtime`, `gemini-live` and `auto`. For speech synthesis in languages other than English, the default is `eleven_flash_v2_5` — 32 languages, around 75 ms; the higher-quality version, `eleven_turbo_v2_5`, is around 250 ms. On OpenAI Realtime there are ten voices and engines up to `gpt-realtime-2.1`. The choice is a field in the agent configuration, not an assumption on our part.

Languages

The agent configuration supports 32 languages, the platform’s internal language map has 41 entries, and the administration panel is translated into 20. These are three numbers for three different things and must not be mixed up. Romanian is the default language for a new agent.

What remains after the call

Transcript, audio recording, duration, cost broken down by supplier, plus a post-call analysis and a short summary of the conversation, generated for the client’s memory. The analysis is not an end in itself: it underpins the decision on whether the agent did what it was supposed to do or whether the scenario has a gap.

Consumption is checked before action, not on the invoice

Before any operation that costs, the platform checks the available credit, and consumption is recorded broken down by supplier and by agent. The gate sits before the call. In practice: an agent lost in a loop cannot consume endlessly without hitting a limit.

What it looks like

The path, step by step.

01

We choose a single route and write its boundaries

A scenario with a clear input and a clear output: incoming call to reception, order confirmation, availability check. We state explicitly what the agent is not allowed to do, what it is not allowed to say, and by which route it hands the discussion to a human. An agent without written boundaries is not more capable, only more unpredictable.

02

We build the agent: role, knowledge, tools, limits

The prompt, the knowledge base approved by you, the tools it can call and the conversation thresholds — supplier, voice, text model, silence time, interruption behaviour. In the end we have a configured agent, not a demo.

03

We put it on the channel and check the route without consuming minutes

On the web: a line of script or a custom component over the start and stop API. There is a script that follows the exact path of a browser — the row in the configuration, the widget configuration, the session request — and stops at the signed URL, without opening the audio connection. It runs on one widget or on all of them, returns an exit code, so it can be part of a scheduled check. On the phone: the number comes in on the trunk, and incoming and outgoing calls are tested separately, because they break separately.

04

We measure what came out and correct the scenario

After the first real conversations, we read the transcripts and the post-call analysis, not the impressions. What we most often correct is not the model, but the length of the responses and the scenario boundaries — two things that are changed in the prompt, on the same day.

IntrareVerificareDeciziePublicareNothing passes on unverified.ORDER IS THE ARGUMENT
The path of a conversation: the page requests the microphone, the platform issues a signed session, the agent speaks and can be interrupted, calls a tool, and anything beyond its role is handed over to a person.

The data

What we touch, where it lives, and how long it stays

The questions anyone with a data protection officer would ask — asked here before they do.

Where the data lives
PostgreSQL via Supabase hosted on our own infrastructure, with 559 versioned migrations, of which 195 touch Row Level Security policies. Files — recordings, knowledge documents, voice samples — are stored in separate repositories, with the path starting with the workspace identifier, so that isolation is in the structure, not only in the query.
What never reaches your page
The voice provider key and the agent identifier. The page receives only a short-lived signed URL issued by the platform. The practical consequence: someone who reads your page source cannot use your agent at your expense.
What is recorded from a call
Audio, transcript, duration, caller number, call outcome and post-call analysis. For cases where the agent remembers the client between calls, a short summary of the previous conversation is also saved. All are tied to a workspace; there is no shared repository across clients.
Deletion on request exists; automatic deletion at term does not yet
We say it as it is, because that is the difference between a promise and a feature. Deletion on request is implemented: a dedicated function deletes objects from the file repository, calls the database deletion procedure and invalidates sessions; there is separate data export and a function for call data. What is not implemented: configurable retention terms per workspace. They are designed in an internal document from April, but the configuration column does not appear in any migration — so today deletion at term is done by procedure, not by clock. If your project needs automatic deletion, it is included as work, not as a setting.
Who is informed that they are speaking to an agent
The notice that the interlocutor is speaking to an automated system, the basis for recording the conversation and the text that is read at the beginning of the call are agreed with you and included in the scenario. They are not a technical setting: they are a decision of the data controller, that is, of you.

A case

The button that did nothing — and did not even give an error

The situation

A voice agent placed in a web page. On press, absolutely nothing happened: no sound, no message, no error in the console that an uninitiated person could see. The kind of fault that gets reported as “it does not work” and is searched for in the wrong place for a day.

What we built

The causes were two, both silent by nature. First: the server’s `Permissions-Policy` header contained `microphone=()`, and the browser rejects the microphone request without raising anything visible to the user. Second: the voice SDK was imported statically, and a module that returns 404 on static import brings down the entire script — so the session request died with it, which makes the fault look exactly like “nothing happened”. We moved the SDK import inside the button press, placed the microphone request before the session request and wrote the server header as `microphone=(self)`, with the content policy that explicitly allows the SDK distribution network.

What came out

Today, on this site, the header served in production is `camera=(), microphone=(self), geolocation=(self)`, and the content security policy explicitly lists the SDK source. A failure is no longer silent: microphone refusal produces a message in Romanian saying what needs to be changed, and the refusal costs nothing, because the session is not even requested.

What the case does not say

The two causes are infrastructure-related, not agent-related. If your site is served by someone else and the headers are not under our control, checking them becomes an initial condition of the work, not a surprise at the end.

Questions

What people ask us before they call

What does it speak with, concretely? What engine is behind it?

You choose between ElevenLabs Conversational AI, OpenAI Realtime and Gemini Live, or leave “auto” and the platform chooses according to language and availability. For voice 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 greater delay, `eleven_turbo_v2_5` is around 250 ms. On OpenAI Realtime there are ten voices, and the engine goes up to `gpt-realtime-2.1`. The text brain is chosen separately, from a catalogue in which each model has its latency and cost per minute written next to it.

Can I interrupt it when it speaks, or do I have to wait for it to finish?

You can. On OpenAI Realtime, speech detection is semantic, with a 0.5 threshold, a 300 ms buffer and 500 ms of silence, and the interruption switch is on by default. On ElevenLabs, the interruption event is sent to the telephone exchange to stop playback. If you still feel that you “can’t interrupt it”, the cause is usually something else: the agent replies in paragraphs, not in sentences. That is fixed in the prompt and in the token limit, not in thresholds.

How many languages does it speak?

The agent configuration supports 32 languages. The platform’s internal language map has 41 entries, and the admin panel is translated into 20 — three numbers for three different things. Romanian is the default language for a new agent. For a specific language, we first check which combination of voice model and provider actually covers it, because not all models cover the same languages.

How does it get onto my site and what do I need to change on my side?

A script line with the widget’s public identifier, or your own component over `start()` / `stop()` / `toggle()`. Two things must be true on your server, otherwise the button does nothing and no error appears: the `Permissions-Policy` header must allow `microphone=(self)` — with `microphone=()` the browser refuses the microphone silently — and the content security policy must allow loading the SDK from the distribution network used. We check them before publishing.

Can it call first, not just answer?

Yes, the platform has batch calling, with contact import, retries and real-time tracking. But outbound calls do not depend only on us: in our issue register there is a documented case in which the operator’s exchange started returning `403 Forbidden` for all outbound calls, with our configuration unchanged and incoming calls working normally. That is why we test outbound calls separately before promising a calling campaign, and why we do not sell an outbound call volume before that test.

What happens when the agent does not know the answer?

It hands over. Each agent has written limits and a configured transfer path. In messaging, the thread moves into human takeover state, with a reason and allocation to a colleague. By phone, the exchange performs the transfer — blind or assisted — to an extension or an external number. Anything beyond the agent’s role stops, it is not improvised; that is a design choice, because an agent that improvises in a regulated field is a risk, not a saving.

Are calls recorded? How long are they kept?

Yes, they are recorded, transcribed and analysed, and everything is tied to your workspace. How long they are kept is your decision as data controller, not a default value we impose on you — and it must be said clearly that automatic deletion on expiry is not today a simple setting in the platform: deletion on request is implemented, deletion on expiry is done by procedure. If you need an automatic clock, it is built in the project.

Does it cost money if the visitor presses the button and then refuses the microphone?

No. The microphone is requested before the session. If the person refuses, the session request is not made at all, so no signed URL is issued and nothing is consumed. Separately, before any operation that costs, the platform checks the available credit — the gate is before the call, not on the bill at the end of the month.

Can I have an agent today that answers a landline number?

It depends on a piece that is not the agent: the SIP host through which the call comes in. The agent side is ready and can be shown on the page immediately. The telephony side needs a functional trunk from the operator and an exchange that answers; at the time of writing, the host through which our test lines pass does not answer, and we do not present as available something we cannot start in front of you. For a real project, telephony is sized separately — see the telephony and contact centre page.

What the statements above rest on (21 sources)
  1. app.kallina.info responds 200 today; supabase.kallina.info responds to edge functionshttps://app.kallina.info/ · 2026-09-06
  2. The headers served today in production on megapromoting.com allow the microphone and the SDK sourcehttps://www.megapromoting.com/ · 2026-09-06

19 of them are code and files from our repositories. We don't publish their name or line: together, on a single page, they would describe too precisely how systems that aren't only ours are built. We go through them with you, in the repository, on request — verification stays possible, it just happens in a conversation.

What would you want to work better?

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

Let's talk