Skip to content

Support AssemblyAI inference context carryover - #2057

Open
rosetta-livekit-bot[bot] wants to merge 10 commits into
mainfrom
interim-prevue-pate
Open

Support AssemblyAI inference context carryover#2057
rosetta-livekit-bot[bot] wants to merge 10 commits into
mainfrom
interim-prevue-pate

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Port AssemblyAI inference STT agent_context carryover for supported U3 Pro family models.
  • Add the linked-source carryover controls, assistant-only 1,750-character tail truncation, and provider option typing.
  • Guard unsupported/disabled fallback children and synchronize forwarding across dynamic model transitions.
  • Add focused wire-payload, lifecycle, fallback, cleanup, and patch-release coverage.
Source diff coverage
Source file Classification Target coverage
livekit-agents/livekit/agents/inference/stt.py Ported agents/src/inference/stt.ts ports the linked PR's U3 Pro carryover model gate, option shape, capability wiring, and assistant-message forwarding. JS-specific safeguards prevent unsupported/disabled fallback children from being mutated and synchronize capability listeners across model changes.
tests/test_inference_stt_context.py Ported and expanded agents/src/inference/stt.test.ts covers capability gating, assistant-only forwarding, 1,750-character tail truncation, ignored items, active session.update wire payloads, supported/unsupported/supported/disabled transitions, and listener cleanup.

This PR is intentionally the lower stack. PR #2058 supersedes its temporary carryover-control surface with the current session-level Python architecture.

Validation

  • Exact head: efb7c37e0f6a630f8761f6abe4a274391e42ab09.
  • Focused STT/session/fallback tests passed: 129 passed, 1 skipped.
  • Package and full builds passed.
  • Isolated package lint passed with no errors and existing warnings; the normal linked-worktree command encountered duplicate ESLint plugin discovery.
  • Focused Prettier check passed.
  • Independent spec-compliance review approved.
  • Independent code-quality review approved.
  • Exact-head CI passed: Build, Test, Formatting, REUSE, Devin Review, and CLA.

Cue voice E2E

  • Session: sid_e3340fa16681.
  • Exact head: efb7c37e0f6a630f8761f6abe4a274391e42ab09.
  • Mode: Cue voice with real LiveKit room transport, voice injection/recording, and Cartesia sonic-3 through LiveKit inference TTS.
  • Controlled boundary: a protocol-compatible LiveKit inference WebSocket boundary captured exact STT session.create/session.update payloads and supplied deterministic transcripts; the LLM was deterministic.
  • Path-specific results: capability snapshots followed supported/unsupported/supported/disabled as true/false/true/false; only the supported transition forwarded. Unsupported, disabled, and user items never appeared in agent_context.
  • Request shaping: a 2,250-character assistant item produced exactly the final 1,750 B characters, SHA-256 a35f084996bba9fddefe6fb9be79b29763dc6ecc810fada308db8601777abf58.
  • Cleanup: conversation/capability listener counts changed from 1/1 while active to 0/0 after close.
  • Continuity: a second voice turn in the same session committed CONTINUITY-2057 and real TTS audio.
  • Artifacts: ~/.cue-cli/sessions/sid_e3340fa16681/events.jsonl, two command result.json files, session recording.wav, and both command WAVs. All were flushed and inspected directly.
  • Limitation: this captures production request shaping at a protocol-compatible boundary; it does not claim a production AssemblyAI network call.

Ported from livekit/agents#6466

Original PR description

already introduced in the assembly ai plugin

Post-rebase

  • Rebased/merged origin/main to clear conflicts in fallback_adapter.test.ts imports and agent_session.test.ts describe blocks.
  • Focused tests after merge: 101 passed, 1 skipped.
  • New exact head: efb7c37e0f6a630f8761f6abe4a274391e42ab09.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 18, 2026 00:55
@changeset-bot

changeset-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e2feaad

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

devin-ai-integration[bot]

This comment was marked as resolved.

toubatbrian and others added 2 commits July 20, 2026 13:55
Guard provider updates by live capabilities and propagate model capability changes so sessions and fallback adapters forward context only while supported.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover the emitted session.update payload and the runtime previous_context_n_turns opt-out required by the Rosetta stack contract.

Co-authored-by: Cursor <cursoragent@cursor.com>
rosetta-livekit-bot Bot and others added 2 commits July 22, 2026 12:23
Co-authored-by: rosetta-livekit-bot[bot] <282703043+rosetta-livekit-bot[bot]@users.noreply.github.com>
Co-authored-by: Toubat <brian.yin@livekit.io>
Resolve conflicts by keeping both STT context-option and user-input
transcription tests, and by combining fallback-adapter test imports.

Co-authored-by: Cursor <cursoragent@cursor.com>
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines 497 to 502
cloudHostname,
roomId,
jobId,
metadata: options.metadata,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Cloud log records are missing the agent identity labels that traces get

The agent name and cloud agent/deployment identifiers are collected but not handed to the log uploader (initPinoCloudExporter({ metadata: options.metadata }) at agents/src/telemetry/traces.ts:497-502), so uploaded logs cannot be attributed to the agent even though the code comment states they carry it.
Impact: Log records shipped to LiveKit Cloud lack the agent name and deployment labels, so agent-level log filtering/insights show nothing for them while traces do.

Why the identity attributes never reach the log pipeline

setupCloudTracer builds baseMetadata with lk.agent_name, lk.cloud_agent_id and lk.deployment_id (agents/src/telemetry/traces.ts:400-421) and merges it with the caller metadata into sessionMetadata (agents/src/telemetry/traces.ts:423). sessionMetadata is used for the trace resource and for the MetadataSpanProcessor on both provider paths, but the logging path forwards only options.metadata (the job's simulation/redaction flags) to initPinoCloudExporter, whose transport stamps room_id/job_id plus whatever config.metadata contains (agents/src/telemetry/pino_otel_transport.ts:134-137, :201-208). The inline comment at agents/src/telemetry/traces.ts:404-408 explicitly claims the agent name is "Included in both the resource (traces) and the session metadata (spans + logs)", which does not hold.

Suggested change
cloudHostname,
roomId,
jobId,
metadata: options.metadata,
});
initPinoCloudExporter({
cloudHostname,
roomId,
jobId,
metadata: sessionMetadata,
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

tinalenguyen added a commit that referenced this pull request Jul 31, 2026
Single commit on top of latest origin/main (db3263b). Squashes the PR stack
(#2058 STT context options + #2057 AssemblyAI carryover) and the Devin-review fixes.

- inference STT: chatContext capability + agent_context carryover for the U3 Pro
  family, 1750-char tail truncation, assistant-only forwarding; drop stale
  agent_context when switching to a model that can't accept it (Devin review).
- session: sttContextOptions.forwardChatContext (default true), keytermsOptions
  deprecated/mapped; forwarding synced on capabilities_changed + model swap.
- fallback_adapter: re-aggregate all dynamic child capabilities on
  capabilities_changed (alignedTranscript/keyterms/chatContext), not just chatContext.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tinalenguyen
tinalenguyen force-pushed the interim-prevue-pate branch from 18e0d25 to 10f3002 Compare July 31, 2026 19:38
devin-ai-integration[bot]

This comment was marked as resolved.

Integrate latest main (incl. #2152) into the verified AssemblyAI context-carryover
port. Conflicts resolved in agents/src/inference/stt.ts and stt.test.ts by keeping
both the port's chat-context carryover and main's word-alignment capability
(alignedTranscriptForModel). No behavioral changes beyond the merge.
After merging main, inference STT recomputes alignedTranscript/keyterms/chatContext
on updateOptions({ model }) and emits capabilities_changed, but FallbackAdapter's
forwarder only re-read chatContext — so a child switching to a model without word
timings left the adapter advertising alignedTranscript it no longer had. Re-aggregate
every runtime-dynamic capability, mirroring the constructor. (Devin review)
…odel

updateOptions merges modelOptions and never removes keys, and connectWs serializes the
whole baseline as settings.extra, so after switching away from a U3 Pro model the stale
agent_context would still be sent to a model that rejects it. Drop it on the transition
and propagate the removal to live streams. (Devin review)

Note: this diverges from Python livekit-agents, which retains agent_context across the
transition.
@tinalenguyen
tinalenguyen force-pushed the interim-prevue-pate branch from 10f3002 to cbaa1fe Compare July 31, 2026 19:48
…lds on model switch

The plugin STT computed chatContext + U3-Pro-only param validation only in the
constructor, but updateOptions() accepts a new speechModel. With carryover defaulting
on for the U3 Pro family, agentContext is auto-populated by _pushConversationItem; a
later switch to a non-U3 model left the stale agentContext serialized into #connectWS /
UpdateConfiguration and kept capabilities.chatContext advertising support, so the session
kept forwarding assistant replies.

updateOptions now, when speechModel changes: recomputes chatContext via
updateCapabilities(), rejects U3-Pro-only fields passed alongside a non-U3 model
(mirroring the constructor), and drops any stale U3-Pro-only fields (agentContext,
previousContextNTurns, prompt, voiceFocus, voiceFocusThreshold, mode) the new model
cannot accept, propagating the clearing to live streams. _pushConversationItem now guards
on capabilities.chatContext. Mirrors agents/src/inference/stt.ts updateOptions.
@tinalenguyen
tinalenguyen force-pushed the interim-prevue-pate branch from cbaa1fe to 1507bb4 Compare July 31, 2026 20:04

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

chatContext: supportsChatContext(this.opts.model),
alignedTranscript: alignmentModels.every(alignedTranscriptForModel) ? 'word' : false,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Switching speech models leaves provider-specific tuning fields behind, which the new model rejects

Only the carried-over reply text is removed when the speech model changes (delete cleared.agent_context at agents/src/inference/stt.ts:621), leaving the other model-specific settings in place, so the next connection sends settings the new model does not accept and can fail to start.
Impact: Users who switch models mid-session can end up with a speech-to-text connection that the provider rejects, breaking transcription.

Only `agent_context` is dropped, while the other U3-Pro-only extras persist

AssemblyAIOptions documents five fields as "Only supported with u3-rt-pro": agent_context, previous_context_n_turns, voice_focus, voice_focus_threshold and mode (agents/src/inference/stt.ts:136-146). updateOptions merges modelOptions and never removes keys, and connectWs serializes the whole baseline as settings.extra (agents/src/inference/stt.ts:669-675). The new clearing block only removes agent_context, so after e.g. updateOptions({ model: 'assemblyai/universal-streaming' }) a previously set voice_focus/mode/previous_context_n_turns is still shipped to a model that rejects U3-Pro-only parameters — the exact failure the block was added to prevent.

The AssemblyAI plugin does this correctly: it clears every entry of U3_PRO_ONLY_PARAMS when the model changes (plugins/assemblyai/src/stt.ts:274-287), so the inference path is inconsistent with it.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…_context

The inference-STT clearing block added for agent_context only removed that one key, but
AssemblyAIOptions documents five U3-Pro-only fields (agent_context,
previous_context_n_turns, voice_focus, voice_focus_threshold, mode). connectWs serializes
the whole modelOptions baseline as settings.extra, so a stale voice_focus/mode/
previous_context_n_turns would still be shipped to a non-U3 model and rejected. Clear all
of them via ASSEMBLYAI_U3_PRO_ONLY_EXTRAS, matching U3_PRO_ONLY_PARAMS in
plugins/assemblyai/src/stt.ts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants