Skip to content

fix(core): flip text content fields#2013

Open
rosetta-livekit-bot[bot] wants to merge 3 commits into
mainfrom
compos-howdah-reckoned
Open

fix(core): flip text content fields#2013
rosetta-livekit-bot[bot] wants to merge 3 commits into
mainfrom
compos-howdah-reckoned

Conversation

@rosetta-livekit-bot

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

Copy link
Copy Markdown
Contributor

Summary

Ports livekit/agents#6353 to agents-js: assistant textContent strips only LiveKit <expr/> markup, while provider/runtime paths use rawTextContent so model-facing expressive markup is preserved. The follow-up repair also strips unmatched opening and closing <expr> delimiters independently, matching Python's current _split_expr behavior for malformed model output.

Source diff coverage

Coverage classification
  • livekit-agents/livekit/agents/llm/_provider_format/anthropic.py - ported to plugins/anthropic/src/llm.ts; Anthropic context building uses rawTextContent.
  • livekit-agents/livekit/agents/llm/_provider_format/aws.py - not applicable; agents-js has no AWS provider-format counterpart.
  • livekit-agents/livekit/agents/llm/_provider_format/google.py - ported to agents/src/llm/provider_format/google.ts; system messages use rawTextContent.
  • livekit-agents/livekit/agents/llm/_provider_format/utils.py - ported to agents/src/llm/provider_format/utils.ts; mid-conversation instructions preserve raw instruction text.
  • livekit-agents/livekit/agents/llm/chat_context.py - adapted to agents/src/llm/chat_context.ts and agents/src/tts/provider_format.ts; added rawTextContent, made assistant textContent strip only <expr/>, added stripMarkup JSON handling, and ported expr-only stripping without pulling in Python's full provider-format parser.
  • livekit-agents/livekit/agents/llm/utils.py - adapted to agents/src/llm/utils.ts; changed same-ID raw message text is represented as remove/create because agents-js has no Python-style to_update operation.
  • livekit-agents/livekit/agents/telemetry/traces.py - adapted/no code change; agents-js telemetry already iterates raw message content.
  • livekit-agents/livekit/agents/tts/_provider_format.py - adapted to agents/src/tts/provider_format.ts; paired, self-closing, and independent unmatched expr delimiters are removed while provider-native markup remains untouched.
  • livekit-agents/livekit/agents/voice/agent_activity.py - ported to agents/src/voice/agent_activity.ts; realtime reply input, preemptive transcript comparison, and user-input tracing use rawTextContent.
  • livekit-agents/livekit/agents/voice/agent_session.py - not applicable; the exact Python debug logging path does not exist in agents-js.
  • livekit-agents/livekit/agents/voice/remote_session.py - adapted/no code change; agents-js remote session serialization already transports raw message content.
  • Python-only AWS, LangChain, Ultravox, and xAI override paths have no direct agents-js counterparts. Keyterm/STT context paths intentionally use sanitized textContent, matching Python's new behavior.
  • tests/test_expr_markup.py - ported to agents/src/llm/chat_context.test.ts; tests cover expr-only stripping, assistant/non-assistant accessors, undefined text, JSON stripping, malformed delimiters, and stream-assembled markers. agents/src/llm/utils.test.ts covers same-ID rawTextContent changes.

Release decision

Keep the existing core minor changeset: this intentionally changes the documented public meaning of ChatMessage.textContent and adds rawTextContent. Anthropic and Phonic only adapt internal provider call sites, so their entries remain patch.

Verification

Exact head: 87819ed41c1842adcd70b4d615c36a948b58c2e9.

  • pnpm test agents/src/llm/chat_context.test.ts agents/src/llm/utils.test.ts - passed: 2 files, 122 tests.
  • Strict RED/GREEN reproduced unmatched opening and closing marker leakage before the two-regex parity repair; both regressions pass afterward.
  • pnpm build:agents - passed.
  • pnpm build - passed.
  • pnpm typecheck - passed.
  • pnpm lint - passed.
  • pnpm format:check - passed.
  • git diff --check - passed.

Known unrelated local blockers:

  • Repo-wide pnpm api:check reaches unrelated plugins/liveavatar, whose package defines api:check without an api-extractor.json. Scoped core extraction is separately blocked by API Extractor 7.43.7 rejecting generated TypeScript 5.9 export * as declarations.
  • Unfiltered pnpm test runs credentialed provider suites in this environment: 1627 tests passed, while external/provider cases failed (including Baseten model 404 responses and unsupported Baseten STT recognize). The focused core suites above pass.

Cue voice E2E

  • Session: sid_9e17ea494cd9.
  • Exact head: 87819ed41c1842adcd70b4d615c36a948b58c2e9.
  • Mode/agent: fresh voice-mode session with a temporary dispatchable deterministic agent, removed after verification.
  • Changed-path input: Alpha <expr type="break" label="1s"/> bravo.
  • Predicate: debug_message(.payload.kind="expr_text_clean",.payload.text="Alpha bravo").
  • Result: resolved after completed playout (waitForPlayout()), exit code 0. Persisted events contained no literal <expr> markup.
  • Session WAV: stereo PCM s16le, 48 kHz, 2.443979 s, 469288 bytes, SHA-256 c99f191e569f8be77534970dd741eb77764139c0ea6e801db0b790c3fb8f89a4.
  • Command WAV: stereo PCM s16le, 48 kHz, 2.233438 s, 428864 bytes, SHA-256 82d5bf3e6ccfb39b9824428fe61147fa89377c0d1c466f567085d1352c4de4bb.
  • Independent transcription of both WAVs: Alpha Bravo. No markup was spoken.
  • Provider setup: real LiveKit Cloud transport and LiveKit Inference cartesia/sonic-3 TTS; Whisper was used only to inspect the persisted WAVs.
  • Limitations: the deterministic harness did not use STT or an LLM. Remote-session conversation_item_added intentionally carries raw content in both Python and JS, so the clean-text assertion used a path-specific debug event derived from ChatMessage.textContent; chat insertion was disabled to avoid conflating raw transport with user-facing cleaned text. Artifacts are persisted locally under ~/.cue-cli/sessions/sid_9e17ea494cd9/ and are identified above by cryptographic hash.

Ported from livekit/agents#6353

Original PR description

Before:

  • text_content raw content, with expressive tags and bracket tags;
  • plain_text_content clean content, without any tags;

Now:

  • text_content clean content, without any expressive-only tags expr
  • raw_text_content raw content with expr tags

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 9, 2026 19:19
@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 87819ed

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

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

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 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: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

toubatbrian and others added 2 commits July 15, 2026 10:45
Remove unmatched expressive delimiters so malformed model output cannot leak into user-facing text, and lock in raw-content diff behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant