Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ Documentation on the framework and how to use it can be found [here](https://doc
- entrypoint: The starting point for an interactive session, similar to a request handler in a web server.
- Worker: The main process that coordinates job scheduling and launches agents for user sessions.

**Backchannel Handling**: The voice agent backchannel logic has been refactored into a dedicated handler to improve clarity and maintain behavior.

- **What changed**: Backchannel detection and state are now implemented in `livekit.agents.voice.backchannel.BackchannelHandler`.
- **Why**: Extracting the logic isolates short-utterance detection (e.g., "okay", "yeah") so these affirmations don't trigger full turn commits or LLM replies and so resume/interrupt timers are easier to reason about.
- **Exit commands**: Built-in support for exit command detection (e.g., "exit", "quit", "goodbye", "bye", "stop", "end") within the backchannel handler for easier identification of session-termination intents.
- **Behavior notes**: The refactor preserves existing behavior: fast detection of backchannels, a small false-interruption timer to avoid spurious interrupts, and skipping backchannel transcripts from the session transcript buffer.


## Usage

### Simple voice agent
Expand Down
15 changes: 11 additions & 4 deletions livekit-agents/livekit/agents/ipc/supervised_proc.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,18 @@ def _mask_ctrl_c() -> Generator[None, None, None]:
finally:
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGINT])
else:
old = signal.signal(signal.SIGINT, signal.SIG_IGN)
try:
# On Windows, signal.signal() only works in the main thread
# Check if we're in the main thread before trying to modify signals
import threading
if threading.current_thread() is threading.main_thread():
old = signal.signal(signal.SIGINT, signal.SIG_IGN)
try:
yield
finally:
signal.signal(signal.SIGINT, old)
else:
# Not in main thread - just yield without signal masking
yield
finally:
signal.signal(signal.SIGINT, old)


@dataclass
Expand Down
14 changes: 12 additions & 2 deletions livekit-agents/livekit/agents/telemetry/traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk._logs import (
LogData,
LoggerProvider,
LoggingHandler,
LogRecord,
LogRecordProcessor,
ReadableLogRecord,
)
# Compatibility aliases for older API names
LogRecord = ReadableLogRecord
try:
from opentelemetry.sdk._logs import LogData
except ImportError:
# LogData removed in newer versions - create a simple wrapper
from dataclasses import dataclass
@dataclass
class LogData:
log_record: ReadableLogRecord
instrumentation_scope: object = None
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import SpanProcessor, TracerProvider
Expand Down
Loading