Skip to content

feat: Add pipecat integration#543

Draft
Abhijeet Prasad (AbhiPrasad) wants to merge 1 commit into
mainfrom
abhi-pipecat-integration
Draft

feat: Add pipecat integration#543
Abhijeet Prasad (AbhiPrasad) wants to merge 1 commit into
mainfrom
abhi-pipecat-integration

Conversation

@AbhiPrasad

@AbhiPrasad Abhijeet Prasad (AbhiPrasad) commented Jul 3, 2026

Copy link
Copy Markdown
Member

resolves https://linear.app/braintrustdata/issue/SDK-7/braintrust-pipecat-integration

AI Summary

Adds observer-based Pipecat instrumentation that injects a
BraintrustPipecatObserver into PipelineWorker construction via setup_pipecat()
and auto_instrument(). The observer turns real Pipecat pipeline/provider events
into Braintrust task and llm spans, with VCR-backed OpenAI/Pipecat coverage for
both latest and 1.3.0.

The integration also supports setup_pipecat(capture_audio=True) for capturing
Pipecat audio attachments in traces. When enabled, user/input audio and TTS audio
chunks are accumulated from real Pipecat frames, wrapped as WAV/PCM Braintrust
Attachments, and logged with audio metadata like sample rate, channel count,
frame count, and byte size.

Try it in an app:

import braintrust
from pipecat.frames.frames import EndFrame, LLMContextFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.worker import PipelineParams, PipelineWorker
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.workers.runner import WorkerRunner

braintrust.init_logger(project="pipecat-demo")
braintrust.auto_instrument()  # installs the Pipecat PipelineWorker observer

llm = OpenAILLMService(
    api_key="...",
    settings=OpenAILLMService.Settings(
        model="gpt-4o-mini",
        temperature=0.0,
        max_completion_tokens=64,
    ),
)
worker = PipelineWorker(
    Pipeline([llm]),
    params=PipelineParams(enable_metrics=True, enable_usage_metrics=True),
)
context = LLMContext(messages=[{"role": "user", "content": "Say hello"}])

@worker.event_handler("on_pipeline_started")
async def on_pipeline_started(_worker, _frame):
    await worker.queue_frames([LLMContextFrame(context), EndFrame()])

runner = WorkerRunner(handle_sigint=False)
await runner.add_workers(worker)
await runner.run()

To enable audio attachments explicitly:

from braintrust.integrations.pipecat import setup_pipecat

setup_pipecat(capture_audio=True)

To validate locally from this repo:

cd py
nox -s "test_pipecat(latest)"
nox -s "test_pipecat(1.3.0)"
OPENAI_API_KEY=sk-test-dummy-api-key-for-vcr-tests \
  nox -s "test_pipecat(latest)" -- -k test_setup_pipecat_traces_real_pipeline_frames

Expected trace shape:

pipecat_pipeline                         task
├── user_speaking                        task  input.audio: Attachment
├── tts_response                         task  output.audio: Attachment
└── pipecat_llm_response                 llm
    ├── input:  [{role: developer}, {role: user, ...}]
    ├── output: [{index: 0, finish_reason: stop, message: {...}}]
    ├── metadata: {provider: openai, model: gpt-4o-mini}
    └── metrics: {prompt_tokens, completion_tokens, tokens, time_to_first_token}

@AbhiPrasad Abhijeet Prasad (AbhiPrasad) force-pushed the abhi-pipecat-integration branch 4 times, most recently from 107ad5c to 0646781 Compare July 7, 2026 22:58
Adds observer-based Pipecat instrumentation that injects a
BraintrustPipecatObserver into PipelineWorker construction via setup_pipecat()
and auto_instrument(). The observer turns real Pipecat pipeline/provider events
into Braintrust task and llm spans, with VCR-backed OpenAI/Pipecat coverage for
both latest and 1.3.0.

The integration also supports setup_pipecat(capture_audio=True) for capturing
Pipecat audio attachments in traces. When enabled, user/input audio and TTS audio
chunks are accumulated from real Pipecat frames, wrapped as WAV/PCM Braintrust
Attachments, and logged with audio metadata like sample rate, channel count,
frame count, and byte size.

Try it in an app:

```python
import braintrust
from pipecat.frames.frames import EndFrame, LLMContextFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.worker import PipelineParams, PipelineWorker
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.workers.runner import WorkerRunner

braintrust.init_logger(project="pipecat-demo")
braintrust.auto_instrument()  # installs the Pipecat PipelineWorker observer

llm = OpenAILLMService(
    api_key="...",
    settings=OpenAILLMService.Settings(
        model="gpt-4o-mini",
        temperature=0.0,
        max_completion_tokens=64,
    ),
)
worker = PipelineWorker(
    Pipeline([llm]),
    params=PipelineParams(enable_metrics=True, enable_usage_metrics=True),
)
context = LLMContext(messages=[{"role": "user", "content": "Say hello"}])

@worker.event_handler("on_pipeline_started")
async def on_pipeline_started(_worker, _frame):
    await worker.queue_frames([LLMContextFrame(context), EndFrame()])

runner = WorkerRunner(handle_sigint=False)
await runner.add_workers(worker)
await runner.run()
```

To enable audio attachments explicitly:

```python
from braintrust.integrations.pipecat import setup_pipecat

setup_pipecat(capture_audio=True)
```

To validate locally from this repo:

```bash
cd py
nox -s "test_pipecat(latest)"
nox -s "test_pipecat(1.3.0)"
OPENAI_API_KEY=sk-test-dummy-api-key-for-vcr-tests \
  nox -s "test_pipecat(latest)" -- -k test_setup_pipecat_traces_real_pipeline_frames
```

Expected trace shape:

```text
pipecat_pipeline                         task
├── user_speaking                        task  input.audio: Attachment
├── tts_response                         task  output.audio: Attachment
└── pipecat_llm_response                 llm
    ├── input:  [{role: developer}, {role: user, ...}]
    ├── output: [{index: 0, finish_reason: stop, message: {...}}]
    ├── metadata: {provider: openai, model: gpt-4o-mini}
    └── metrics: {prompt_tokens, completion_tokens, tokens, time_to_first_token}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant