Skip to content

OpenRing 0.1.6: call limits, voicemail detection, recordings, squads, knowledge bases, SIP, Plivo and Vonage

Latest

Choose a tag to compare

@elifalanrocha elifalanrocha released this 09 Nov 03:49
· 19 commits to main since this release

Added

  • The phone line in a call's cost (costBreakdown.line, included in total): Twilio's list prices for US and Canadian
    numbers, rounded up to the minute. Other carriers and countries are named in unpriced until you add a rate in
    ~/.openring/prices.json ("line").

  • The Calls page exports to CSV, with formula cells made safe for spreadsheets, and a call's page copies its transcript
    (thanks to Vaibhav R Valakunde, vaibhavrvalakunde2006-gif).

  • Provider logos on the Providers page.

  • OmniRoute takes an API key on the Providers page (OMNIROUTE_API_KEY), for when its API key protection is on;
    it is checked against OmniRoute's model list before it's saved.

  • OAuth sign-in (/oauth/*) for xAI, Anthropic and OpenAI with the server owner's own OAuth client
    (<PROVIDER>_CLIENT_ID). OpenRing never signs in as another vendor's app. OpenRouter keeps its own sign-in.

  • Calls in and out through Plivo and Vonage, and out through Telnyx (beta): signed webhooks, campaigns, and
    transferCall on Plivo and Vonage. Connect them on the Providers page. The import brings Telnyx and Vonage numbers.

  • openring --version (thanks to Vaibhav R Valakunde, vaibhavrvalakunde2006-gif) and openring --host, which wins over
    HOST and warns in its help that anything but localhost exposes the dashboard (thanks to Arin Aeruva, arin30).

  • Vapi's createdAtGt, createdAtLt, createdAtGe and createdAtLe on GET /call, /assistant, /tool and
    /phone-number, filtered in SQL, in any ISO 8601 offset, with a 400 for a date that isn't one (thanks to
    k_s_neeraj, Neeraj111010). Importing from another OpenRing with more than 100 items now gets every page.

  • Disconnect on the Providers page asks for a second click, labeled Confirm disconnect, before it removes a key
    (thanks to Arin Aeruva, arin30).

  • Prices for Rime's Coda and Smallest.ai's Lightning voices, and "*" in ~/.openring/prices.json now covers every
    model of a provider, including the ones with a price of their own (thanks to Mohit Anand, coughlmao).

  • Squads (beta), in Vapi's format: several assistants on one call, each with its own prompt, tools, model and voice.
    /squad, the handoff tool and assistantDestinations, squadId on numbers, calls and assistant-request,
    contextEngineeringPlan, firstMessageMode and tools:append; the call's handoffs lists each change. The import
    brings squads.

  • Knowledge bases (beta), in Vapi's format: POST /file, the query tool, /knowledge-base and
    model.knowledgeBaseId. The search runs on your server with SQLite's full-text index, matching words, or asks your
    own with custom-knowledge-base. PDFs are read with pypdf, a new dependency, in a process of their own with a time
    limit.

  • SIP trunks (beta), in Vapi's format: byo-sip-trunk credentials in /credential and byo-phone-number numbers, in and
    out, with login, registration and transfers, over UDP with G.711. Only your trunks' gateways get an answer.
    customer.sipUri works, and Twilio and Telnyx SIP calls find their number.

  • Words the transcriber should get right, in Vapi's transcriber.keyterm, keytermsPrompt and keywords, or
    Words to recognize in the assistant editor. Each goes to the field its transcriber and model take, since Deepgram
    refuses a connection given the wrong one.

  • Call recording, in Vapi's artifactPlan.recordingEnabled: a stereo WAV per call on your server, played on the
    call's page, with artifact.recordingUrl on the call and in the end-of-call-report.
    GET /call/{id}/recording needs the API key or a dashboard session, and DELETE removes the file. It's off by
    default, unlike on Vapi: many places require telling people they are being recorded. Recordings are deleted after
    365 days; change it under Settings > Recordings or with PATCH /settings/recordings (0 keeps them for good).

  • Call limits, in Vapi's fields: a call ends by itself after maxDurationSeconds or after silenceTimeoutSeconds
    without activity (the clock waits while someone talks, the model thinks or a tool runs), with Vapi's endedReason
    (exceeded-max-duration, silence-timed-out),
    saying endCallMessage first. When the caller goes quiet after the assistant spoke,
    messagePlan.idleMessages are said ("Are you still there?"), after idleTimeoutSeconds, up to
    idleMessageMaxSpokenCount times. The assistant editor has the length, the silence and the idle message.
    These limits apply to assistants you already have: give maxDurationSeconds a higher value if their calls can run
    past 10 minutes. endCallMessage is also said when an endCall tool has no message of its own, as on Vapi.

  • Voicemail detection on outgoing calls (beta), in Vapi's fields: with voicemailDetection or a voicemailMessage,
    Twilio's answering machine detection checks who picked up and waits for the beep. A voicemail gets the message, in
    the assistant's voice (or a recording, from the URL of a .wav or .mp3), and the call ends with endedReason: "voicemail", which campaigns count in callsCounterEndedVoicemail; without a message it just hangs up. It stays
    off unless asked for. The assistant editor has the switch and the message.

  • The apiRequest tool, in Vapi's format: the model fills in the body and OpenRing sends it to your URL, such as
    an n8n, Make or Zapier webhook, with no server of your own. The URL, headers and parameters stay yours and
    can use {{variables}}; the model can only send the fields body declares. Only a 2xx answer counts; nothing is
    retried or redirected, a caller's interruption doesn't
    cancel a request already sent, and cloud metadata addresses are refused. Vapi's credentialId isn't available.

  • Tools: request-response-delayed messages are said when a tool runs late, and a request-failed message with
    "role": "system" now goes to the model instead of being read out to the caller.

Changed

  • Calls now have Vapi's default limits: 10 minutes at most, and 30 seconds of silence from the caller. Before,
    a call with nobody on the line kept running (and billing the providers) until the phone company dropped it.

Fixed

  • Only OpenAI is sent the developer message role now. Pipecat adds such messages during a call (a tool's late answer, a
    caller's empty turn), and a provider that refuses the role ended the call. Mistral, DeepSeek and Perplexity go through
    Pipecat's own services for them, which follow their rules for messages.

  • A caller speaking during a transfer no longer cancels it, and a transfer that fails now gets an answer: the model tells
    the caller, or the tool's request-failed message does, instead of leaving them in silence.

  • When a provider stopped working during a call (a rejected key, no credit left, an outage) and no fallback could
    take over, the caller heard silence until they hung up, and the call was recorded as customer-ended-call,
    a success. The call now ends right away with pipeline-error: the voice (11labs ...) stopped working: ...,
    naming the layer, the provider and its error.

  • A Vonage webhook token that carries a payload hash now vouches for that body only. Before, a captured token also
    passed with no body at all, so it could stand in for any GET to /vonage/event or /vonage/voice for five minutes.
    An outgoing Vonage call that was answered but never connected its websocket now ends with
    vonage-failed-to-connect-call instead of staying queued.

  • OAuth's redirect_uri has to be on the same origin as PUBLIC_URL (or on localhost). It was a prefix match, so
    https://your-host.evil.example passed.