Metadata-Version: 2.4
Name: tibet-voice-cache
Version: 0.1.1
Summary: Separated user/AI conversation cache for streaming voice models. Gives your voice AI memory without role confusion.
Project-URL: Homepage, https://github.com/jaspertvdm/tibet-voice-cache
Project-URL: Documentation, https://github.com/jaspertvdm/tibet-voice-cache#readme
Project-URL: Repository, https://github.com/jaspertvdm/tibet-voice-cache
Project-URL: Issues, https://github.com/jaspertvdm/tibet-voice-cache/issues
Author-email: Jasper van de Meent <jasper@humotica.nl>, Root AI <root_idd@humotica.nl>
License-Expression: MIT
License-File: LICENSE
Keywords: ai,cache,conversation,gemini,mcp,memory,openai,realtime,streaming,tibet,voice
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: google-genai>=1.0.0; extra == 'all'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
Provides-Extra: mcp
Requires-Dist: tibet-voice-cache-mcp; extra == 'mcp'
Description-Content-Type: text/markdown

# 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

```python
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:

```python
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:

```python
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:

```python
# 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:

```python
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?

```python
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:

```python
# 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:
```json
{
  "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](https://ai.google.dev/gemini-api/docs/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](https://github.com/humoticaOS) — 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](https://github.com/jaspertvdm). Built by Jasper and [Root AI](https://humotica.com) as part of [HumoticaOS](https://humotica.com).

---

**Stack-positie:** Groep `specialized` · Eigen tijdlijn — niet onderdeel van de ainternet/evidence-spine · ← [`tibet-phantom`](https://pypi.org/project/tibet-phantom/) · [`tibet-voice-cache-mcp`](https://pypi.org/project/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](ENTERPRISE.md) for details.
