From 906577759a1fbd90ce66f67fbc3e2f6c9083498c Mon Sep 17 00:00:00 2001 From: Prasanna721 Date: Sat, 10 Jan 2026 08:40:34 -0800 Subject: [PATCH] update readme and agents.md --- packages/pipecat-sdk-python/Agents.md | 250 ++++---------------------- packages/pipecat-sdk-python/README.md | 15 -- 2 files changed, 38 insertions(+), 227 deletions(-) diff --git a/packages/pipecat-sdk-python/Agents.md b/packages/pipecat-sdk-python/Agents.md index e6d4244d..b43c3bb0 100644 --- a/packages/pipecat-sdk-python/Agents.md +++ b/packages/pipecat-sdk-python/Agents.md @@ -1,147 +1,34 @@ -# agents.md +# AGENTS.md -Agent knowledge file for Supermemory Pipecat SDK. This describes how Supermemory integrates with Pipecat for memory-enhanced voice AI. +## Overview -## What This Package Does +This package adds persistent memory to Pipecat voice AI pipelines using Supermemory. -Supermemory Pipecat SDK provides a `FrameProcessor` that intercepts conversation frames, retrieves relevant memories from Supermemory, injects them into the LLM context, and stores new messages. +**Tech Stack:** Python 3.10+, Pipecat, Supermemory SDK -## Package Structure +## Commands -``` -packages/pipecat-sdk-python/ -├── src/supermemory_pipecat/ -│ ├── __init__.py # Exports: SupermemoryPipecatService -│ ├── service.py # Main FrameProcessor class -│ ├── exceptions.py # Error hierarchy -│ └── utils.py # Helpers: get_last_user_message, deduplicate_memories -├── pyproject.toml # Package: supermemory-pipecat -└── README.md +```bash +pip install supermemory-pipecat ``` -## Core Class: SupermemoryPipecatService +## Integration Pattern -Extends `pipecat.processors.frame_processor.FrameProcessor`. - -### Constructor Parameters - -| Parameter | Type | Required | Default | -|-----------|------|----------|---------| -| `user_id` | str | Yes | - | -| `session_id` | str | No | None | -| `api_key` | str | No | `SUPERMEMORY_API_KEY` env | -| `params` | InputParams | No | defaults | -| `base_url` | str | No | `https://api.supermemory.ai` | - -### InputParams Configuration - -```python -InputParams( - search_limit=10, # Max memories to retrieve - search_threshold=0.1, # Similarity threshold (0.0-1.0) - mode="full", # "profile" | "query" | "full" - add_memory="always", # "always" | "never" - add_as_system_message=True, - system_prompt="Based on previous conversations, I recall:\n\n", - position=1, -) -``` - -### Key Mappings - -- `user_id` → `container_tag` (direct, no transformation) -- `session_id` → `custom_id` (in Supermemory API) - -## How It Works - -### Pipeline Position - -``` -[Transport] → [STT] → [UserContext] → [SupermemoryPipecatService] → [LLM] → [TTS] → [Output] -``` - -### Frame Processing Flow - -1. **Intercept**: Catches `LLMContextFrame`, `OpenAILLMContextFrame`, `LLMMessagesFrame` -2. **Extract**: Gets last user message from context -3. **Track**: Stores message in `_conversation_history` (clean, no injections) -4. **Retrieve**: Calls `client.profile()` via Supermemory SDK -5. **Inject**: Adds formatted memories to context as system message -6. **Store**: Sends last user message to Supermemory (background, non-blocking) -7. **Push**: Forwards enhanced frame downstream - -### Supermemory SDK Integration - -**Retrieval** - via `supermemory.AsyncSupermemory.profile()`: -```python -response = await client.profile( - container_tag="user-123", - q="What's the weather?", - threshold=0.1, - extra_body={"limit": 10}, -) -# response.profile.static: List[str] -# response.profile.dynamic: List[str] -# response.search_results.results: List[object] -``` - -**Storage** - via `supermemory.AsyncSupermemory.memories.add()`: -```python -await client.memories.add( - content="User: What's the weather?", - container_tags=["user-123"], - custom_id="session-456", - metadata={"platform": "pipecat"}, -) -``` - -## Memory Modes - -| Mode | Static Profile | Dynamic Profile | Search Results | -|------|----------------|-----------------|----------------| -| `profile` | Yes | Yes | No | -| `query` | No | No | Yes | -| `full` | Yes | Yes | Yes | - -## Instance State - -```python -self.user_id: str # User identifier -self.container_tag: str # Same as user_id -self.session_id: Optional[str] # Session grouping -self._conversation_history: List[Dict] # Clean message history -self._last_query: Optional[str] # Dedup tracking -self._supermemory_client # Supermemory SDK client -``` - -## Error Handling - -- Memory retrieval failures: Log warning, continue without memories -- Memory storage failures: Log error, don't crash pipeline -- Frame processing errors: Log error, pass original frame through - -## Sample Usage +Place `SupermemoryPipecatService` between context aggregator and LLM in the pipeline: ```python from supermemory_pipecat import SupermemoryPipecatService -# Create service memory = SupermemoryPipecatService( - api_key=os.getenv("SUPERMEMORY_API_KEY"), - user_id="user-123", - session_id="conv-456", - params=SupermemoryPipecatService.InputParams( - mode="full", - add_memory="always", - ), + user_id="user-123", # Required: identifies the user + session_id="session-456", # Optional: groups conversations ) -# Add to pipeline pipeline = Pipeline([ transport.input(), stt, context_aggregator.user(), - memory, # ← Intercepts here, retrieves/injects/stores + memory, # <- Memory service here llm, tts, transport.output(), @@ -149,98 +36,37 @@ pipeline = Pipeline([ ]) ``` -## Full Working Example +## Configuration ```python -"""Pipecat + Supermemory Voice Bot""" - -import os -from fastapi import FastAPI, WebSocket -from pipecat.pipeline.pipeline import Pipeline -from pipecat.pipeline.runner import PipelineRunner -from pipecat.pipeline.task import PipelineParams, PipelineTask -from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext -from pipecat.services.openai.llm import OpenAILLMService -from pipecat.services.openai.tts import OpenAITTSService -from pipecat.services.openai.stt import OpenAISTTService -from pipecat.transports.websocket.fastapi import ( - FastAPIWebsocketParams, - FastAPIWebsocketTransport, +memory = SupermemoryPipecatService( + api_key="...", # Or use SUPERMEMORY_API_KEY env var + user_id="user-123", + session_id="session-456", + params=SupermemoryPipecatService.InputParams( + search_limit=10, # Max memories to retrieve + search_threshold=0.1, # Similarity threshold 0.0-1.0 + mode="full", # "profile" | "query" | "full" + system_prompt="Based on previous conversations:\n\n", + ), ) -from pipecat.audio.vad.silero import SileroVADAnalyzer -from pipecat.serializers.protobuf import ProtobufFrameSerializer - -from supermemory_pipecat import SupermemoryPipecatService - -app = FastAPI() - -SYSTEM_PROMPT = """You are a helpful voice assistant with memory. -Keep responses brief. Your output will be converted to audio.""" - -@app.websocket("/ws") -async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - - transport = FastAPIWebsocketTransport( - websocket=websocket, - params=FastAPIWebsocketParams( - audio_in_enabled=True, - audio_out_enabled=True, - vad_enabled=True, - vad_analyzer=SileroVADAnalyzer(), - vad_audio_passthrough=True, - serializer=ProtobufFrameSerializer(), - ), - ) - - stt = OpenAISTTService(api_key=os.getenv("OPENAI_API_KEY")) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o-mini") - tts = OpenAITTSService(api_key=os.getenv("OPENAI_API_KEY"), voice="alloy") - - # Supermemory integration - memory = SupermemoryPipecatService( - user_id="test-user", - session_id="voice-session", - ) - - context = OpenAILLMContext([{"role": "system", "content": SYSTEM_PROMPT}]) - context_aggregator = llm.create_context_aggregator(context) - - pipeline = Pipeline([ - transport.input(), - stt, - context_aggregator.user(), - memory, - llm, - tts, - transport.output(), - context_aggregator.assistant(), - ]) - - task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True)) - runner = PipelineRunner(handle_sigint=False) - await runner.run(task) - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8001) ``` -## Key Files Reference +## Memory Modes -- `service.py:46` - `SupermemoryPipecatService` class definition -- `service.py:96` - `__init__()` constructor -- `service.py:157` - `_retrieve_memories()` API call -- `service.py:218` - `_store_message()` storage logic -- `service.py:264` - `_enhance_context_with_memories()` injection -- `service.py:328` - `process_frame()` main entry point +| Mode | Retrieves | Use When | +|------|-----------|----------| +| `"profile"` | User profile only | Personalization without search | +| `"query"` | Search results only | Finding relevant past context | +| `"full"` | Profile + search | Complete memory (default) | -## Differences from Mem0 +## Environment Variables -| Aspect | Mem0 | Supermemory | -|--------|------|-------------| -| Identity | `user_id`, `agent_id`, `run_id` | `user_id` only (= container_tag) | -| Retrieval | `memory.search()` | `client.profile()` (static + dynamic + search) | -| Storage | Full conversation | Last user message only | -| Metadata | `{"platform": "pipecat"}` | `{"platform": "pipecat"}` | -| Session | N/A | `session_id` → `custom_id` | +- `SUPERMEMORY_API_KEY` - Supermemory API key +- `OPENAI_API_KEY` - For OpenAI services (STT/LLM/TTS) + +## Boundaries + +- Always place memory service after `context_aggregator.user()` and before `llm` +- Always provide `user_id` - it's required +- Never hardcode API keys in code - use environment variables diff --git a/packages/pipecat-sdk-python/README.md b/packages/pipecat-sdk-python/README.md index 7f2b8d70..5f6e8478 100644 --- a/packages/pipecat-sdk-python/README.md +++ b/packages/pipecat-sdk-python/README.md @@ -58,8 +58,6 @@ memory = SupermemoryPipecatService( search_limit=10, # Max memories to retrieve search_threshold=0.1, # Similarity threshold mode="full", # "profile", "query", or "full" - add_memory="always", # "always" or "never" - add_as_system_message=True, system_prompt="Based on previous conversations, I recall:\n\n", ), ) @@ -156,19 +154,6 @@ async def websocket_endpoint(websocket: WebSocket): await runner.run(task) ``` -## Conversation History - -Access the tracked conversation (without injected memories): - -```python -# Get conversation history -history = memory.get_conversation_history() -# [{"role": "user", "content": "Hello"}, {"role": "user", "content": "What's my name?"}] - -# Clear history -memory.clear_conversation_history() -``` - ## License MIT