tibet-voice-cache
Conversation memory for streaming voice AI. Give your voice model persistent context without role confusion.
pip install tibet-voice-cache
What it does
Streaming voice models (Gemini Live, OpenAI Realtime) lose context between sessions. When you inject raw conversation history as user/model turns, the model replays old responses, talks to itself, or confuses who said what.
tibet-voice-cache stores user and AI utterances separately and builds clean context summaries for your system instruction — no fake turns, no role confusion.
It is provider- and transport-agnostic: it works on plain transcripts (add_user / add_ai), so any audio source plugs in through a small adapter. A Gemini Live adapter ships today; OpenAI Realtime, a SIP/WebRTC bridge, or stored-audio transcripts all follow the same adapters/base pattern.
client / device ──audio──► your proxy ──audio──► streaming voice model
│ │
input_transcript output_transcript
│ │
▼ ▼
user_said[] ai_said[]
│ │
└──── system instruction injection ────┘
│
"Earlier discussed:
User asked about X
You answered Y"
Quick start
from tibet_voice_cache import VoiceCache
# Create a cache (in-memory or persistent)
cache = VoiceCache(actor="user_123", storage_dir="./cache")
# During your voice session, record what's said
cache.add_user("What's the weather like?")
cache.add_ai("It's sunny and 22 degrees!")
cache.complete_turn()
# Next session: inject context into system instruction
system_prompt = cache.inject_into_system_instruction(
"You are a helpful voice assistant."
)
# Result:
# "You are a helpful voice assistant.
#
# === PRIOR CONTEXT ===
# The user previously said:
# - What's the weather like?
# You previously responded:
# - It's sunny and 22 degrees!
# === END CONTEXT ===
# Do NOT respond to the above context unless the user refers to it."
Gemini Flash Live adapter
Drop-in integration for Google's Gemini Live API:
from tibet_voice_cache import VoiceCache
from tibet_voice_cache.adapters.gemini_live import GeminiLiveAdapter
from google import genai
cache = VoiceCache(actor="user_123", storage_dir="./cache")
adapter = GeminiLiveAdapter(cache)
# Build config with context already injected
config = adapter.build_config(
base_instruction="You are OomLlama, a friendly Dutch AI assistant.",
voice="Kore",
)
client = genai.Client(api_key=API_KEY)
async with client.aio.live.connect(model="gemini-3.1-flash-live-preview", config=config) as session:
# In your relay loop, hook into transcription events:
async for msg in session.receive():
if msg.server_content:
if msg.server_content.input_transcription:
adapter.on_input_transcript(msg.server_content.input_transcription.text)
if msg.server_content.output_transcription:
adapter.on_output_transcript(msg.server_content.output_transcription.text)
if msg.server_content.turn_complete:
adapter.on_turn_complete()
# Session ends — persist cache for next time
adapter.on_session_end()
Summary styles
Choose how context is formatted for your model:
from tibet_voice_cache import VoiceCache, SummaryStyle
# Labeled (default) — clear sections
cache = VoiceCache(actor="user", summary_style=SummaryStyle.LABELED)
# Compact — minimal tokens
cache = VoiceCache(actor="user", summary_style=SummaryStyle.COMPACT)
# → [Context] User: weather question. You: sunny, 22 degrees.
# Narrative — natural language
cache = VoiceCache(actor="user", summary_style=SummaryStyle.NARRATIVE)
# → Earlier in the conversation:
# - The user said: "What's the weather like?"
# - You replied: "It's sunny and 22 degrees!"
# Chronological — ordered pairs
cache = VoiceCache(actor="user", summary_style=SummaryStyle.CHRONOLOGICAL)
# → Previously discussed:
# 1. User: What's the weather? -> You: Sunny, 22 degrees
Multi-language labels
Built-in English and Dutch, or bring your own:
# Dutch labels
cache = VoiceCache(actor="user", summary_style=SummaryStyle.LABELED)
cache.summary_builder.labels = SummaryBuilder.LABELS["nl"]
# Custom labels
cache.summary_builder.labels = {
"header": "--- KONTEXT ---",
"footer": "--- ENDE ---",
"user_label": "Benutzer sagte:",
"ai_label": "Du antwortetest:",
"no_replay": "Reagiere nicht auf obigen Kontext.",
...
}
Bulk session import
Save all transcripts at once when a session ends:
cache.add_session_transcripts(
user_texts=["Hello", "How are you?", "Tell me a joke"],
ai_texts=["Hi there!", "I'm great!", "Why did the chicken..."],
)
Migrate from mixed history
Coming from a [{"role": "user", "content": "..."}, {"role": "assistant", ...}] format?
legacy_history = [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi!"},
]
cache = VoiceCache.from_mixed_history(legacy_history, actor="migrated")
Persistence
Cache is stored as JSON per actor. Works with any filesystem:
# Local storage
cache = VoiceCache(actor="user_123", storage_dir="./cache")
# Shared storage (NFS, S3 mount, etc.)
cache = VoiceCache(actor="user_123", storage_dir="/mnt/shared/voice-cache")
# In-memory only (no persistence)
cache = VoiceCache(actor="user_123")
File format:
{
"actor": "user_123",
"user_said": [
{"text": "Hello", "timestamp": 1712234567.89, "turn_id": 0}
],
"ai_said": [
{"text": "Hi there!", "timestamp": 1712234568.12, "turn_id": 0}
],
"turn_counter": 1,
"updated": "2026-04-04T10:30:00+00:00"
}
Why not Google's Context Cache API?
Google's context caching is designed for REST API calls — cache large documents, save tokens. For the Live API (streaming audio), their approach is send_client_content with raw turns — which causes the exact role confusion this package solves.
Google's own docs recommend: "For longer contexts, provide a single message summary." That's exactly what tibet-voice-cache does, automatically.
Part of the TIBET ecosystem
tibet-voice-cache is part of TIBET — Traceable Intent-Based Event Tokens. Built by the HumoticaOS family.
| Package | Description |
|---|---|
tibet-voice-cache |
This package — voice conversation memory |
tibet-voice-cache-mcp |
MCP server wrapper (coming soon) |
Roadmap
The memory layer — separated user/AI utterances, clean context injection — is what ships today, and
it runs in production. Next, all on the same adapters/base pattern (the cache stays
provider-agnostic):
- SIP / WebRTC bridge — feed live telephony or browser-voice transcripts straight into the cache, role-confusion-free.
- OpenAI Realtime adapter — a sibling to the Gemini Live one.
- Voice-driven actions — let an utterance trigger a governed action, not just remembered context, enforced through the TIBET/JIS layer so the action carries its intent and audit trail.
These are deliberate next steps, not shipped. The cache is honest about what it does today.
License
MIT — use it, fork it, give your voice AI a memory.
Credits
Designed by Jasper van de Meent. Built by Jasper and Root AI as part of HumoticaOS.
Stack-positie: Groep specialized · Eigen tijdlijn — niet onderdeel van de ainternet/evidence-spine · ← tibet-phantom · tibet-voice-cache-mcp → · See STACK.md · See demo/golden-path/ for the spine end-to-end.
Enterprise
For private hub hosting, SLA support, custom integrations, or compliance guidance:
| Enterprise | enterprise@humotica.com |
| Support | support@humotica.com |
| Security | security@humotica.com |
See ENTERPRISE.md for details.
Metadata
Release files for tibet-voice-cache 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tibet_voice_cache-0.1.1.tar.gz | 13.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tibet_voice_cache-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.4 kB
Release files / tibet_voice_cache-0.1.1.tar.gz
| Download URL | tibet_voice_cache-0.1.1.tar.gz |
|---|---|
| Size | 13.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
26b2037d17bab579994225ae4f2121a37e887dc8113f999a0b08759ef50a8f32
|
|
BLAKE2b-256 checksum How to use checksums |
06260dd63ff68eb347f02b3cbedbd4ca9aa796c4e8fd02231b702fb260d72d0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / tibet_voice_cache-0.1.1-py3-none-any.whl
| Download URL | tibet_voice_cache-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
04b9f562c848d073602f973c21f1e1eb6b3f15788332c89adcbc38fe11afadc8
|
|
BLAKE2b-256 checksum How to use checksums |
cadc634d07e1ec775f5e12eeb1034fce2c8058cf6129a07c0a730ba91b61b5e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|