tall-ability-51442
03/22/2026, 2:35 PMtall-airline-16756
03/22/2026, 2:35 PMtall-airline-16756
03/22/2026, 2:35 PMlk.chat stream but no handler/callback is registered to process it. The log indicates a missing callback for that topic, so incoming text is observed but not acted on.
Likely causes and quick checks
• If you relied on a default built-in text handler in previous versions, it’s possible the way text callbacks are registered changed in 1.5 and a callback now must be explicitly provided.
• Check how you initialize the agent/room options: do you pass a text input callback (or any custom text handler) when creating the agent or joining the room?
• Verify your agent code that previously handled text wasn’t removed or overwritten during the upgrade (for example, if you replaced defaults with custom options that omit text handlers).
What I recommend you try next
1. Confirm how you create the agent/room:
◦ Share the snippet where you construct room/agent options (the part that could register input callbacks). If you can paste that, I can point out what to change.
1. Explicitly register a text callback for lk.chat and see if the log goes away. The agents system supports providing a text input callback in the room options — adding one will ensure incoming lk.chat messages are delivered to your logic.
2. If you use default behavior (no custom callback) and expect built-in handling, tell me whether that worked before the upgrade and include the previous version number. That helps confirm whether default registration changed between versions.
If you want, paste:
• The code that creates/initializes the agent or joins the room (especially the options object), and
• The exact upgrade steps (what you changed from the previous version)
I’ll look at your snippet and give precise code changes to register the text callback so your lk.chat messages are processed again.
Sources: Text and transcriptions | LiveKit Documentation, with interactive elementstall-ability-51442
03/22/2026, 2:39 PMBVCTelephony instead for best results
noise_cancellation=noise_cancellation.BVC(),
),
room_output_options=RoomOutputOptions(audio_enabled=not text_only_mode),
)tall-airline-16756
03/22/2026, 2:40 PMlk.chat topic but reports there is no custom callback registered for that topic. This log is informational; default text handling is still present and should process lk.chat messages automatically for standard chat use.
What to verify next (quick checks)
1. Confirm the incoming messages are actually using topic lk.chat (not a variant or typo).
2. Ensure the participant sending text is connected to the same room referenced by ctx.room.
3. Check whether text input is enabled for the session — by default it is, and your shown code (with no explicit text callback) is normally sufficient for default processing.
4. Confirm there is no custom agent logic elsewhere that explicitly unregisters or blocks text callbacks before the default handler runs.
If the agent is receiving but ignoring messages, please tell me:
• Are there any other logs (errors or warnings) around the same time as the "no callback attached" message?
• Do you observe the agent responding at all (text or TTS) when you send a chat message, or is nothing produced?
• The exact livekit-agents version you upgraded from and the full version string you upgraded to (1.5.x) — that helps confirm whether logging behavior changed versus actual behavior.
If everything above looks normal, next diagnostic step
• Paste the code where you construct the Assistant class (or any custom hooks you add to the session/agent) and any place you might override room/agent defaults. I’ll scan those for anything that could suppress the default text handler.
Optional immediate workaround
• You can attach an explicit simple text callback to confirm delivery and processing. If you want, I can show the minimal Python snippet to register a lk.chat handler that forwards incoming text into the agent pipeline — this will both silence the log and ensure messages are processed if something in your environment is preventing the default from running.
Which would you like me to do next?
• I can provide the explicit callback snippet now, or
• You can paste the additional logs and the Assistant / session initialization code and I’ll look for what’s suppressing the default handler. Sources: Text and transcriptions | LiveKit Documentation, with interactive elementstall-ability-51442
03/22/2026, 3:08 PMtall-airline-16756
03/22/2026, 3:09 PMsession.input.set_text_enabled(True) (or the equivalent) to ensure text input is on.
1. Confirm you’re passing the callback in the right place
◦ The callback must be provided in the RoomOptions/TextInputOptions that the session actually uses. If you construct a different options object (or pass room_input_options vs room_options) the callback could be attached to the wrong object.
1. Ensure session has fully started before messages arrive
◦ If messages are sent before the session/agent finishes initialization, the callback might not yet be registered and the stream will be ignored. Check logs for session start/connected events and try sending a message after those events.
1. Verify callback function signature and import path
◦ Use the minimal signature the docs show (e.g., def custom_text_handler(session, event): ...) and avoid using methods with bound-self vs standalone functions until it’s working.
1. Check for code that may unregister or disable callbacks
◦ Search your codebase for any calls that set text_input=False, call session.input.set_text_enabled(False), or otherwise modify RoomOptions after start.
Minimal diagnostic callback you can add right now
• Add a tiny callback that only logs receipt and calls a simple reply. This confirms whether the callback registration path is being used:
def debug_text_handler(session, event):
# quick log to stdout so we can see it immediately
print("DEBUG: received text event:", event.text)
# interrupt any current activity, then generate a simple reply
session.interrupt()
session.generate_reply(user_input=event.text)
await session.start(
room=ctx.room,
agent=Assistant(...),
room_input_options=RoomInputOptions(
noise_cancellation=noise_cancellation.BVC(),
text_input=RoomInputOptions.TextInputOptions(
text_input_cb=debug_text_handler
),
),
room_output_options=RoomOutputOptions(audio_enabled=not text_only_mode),
)
Notes about the snippet above:
• I used room_input_options.text_input.text_input_cb as the nested option location because some SDK variants nest TextInputOptions under room input options. If your SDK variant uses room_options=RoomOptions(text_input=TextInputOptions(...)) use that shape instead — the key is to attach to the exact options object that session.start consumes.
• If your current attempt followed the docs exactly and still didn’t run, try placing the callback function in module scope (not as a bound method) as a test — just to rule out serialization/closure issues.
If that still doesn’t hit
• Paste the exact code you tried when registering the callback (the RoomOptions/TextInputOptions object you passed). I’ll review it for placement/signature mistakes.
• Also paste the immediate logs around session start (connected/ready) and the "ignored text stream..." entry — timestamps and a few lines before/after are useful.
Why this likely isn’t an LLM/processing bug
• The log specifically reports an unhandled text stream. That points to the callback registration/enablement path or timing, rather than the downstream LLM/TTS pipeline. So we should focus on where/when the callback is attached and whether text input is enabled for the active session.
Next step
• If you want, paste the exact RoomInputOptions/TextInputOptions code you used and a short snippet showing session start logs. I’ll point out exactly where to change it (or provide a tailored minimal example that will definitely be invoked in your environment). Sources: Text and transcriptions | LiveKit Documentation, with interactive elementstall-ability-51442
03/22/2026, 3:13 PMBVCTelephony instead for best results
noise_cancellation=noise_cancellation.BVC(),
),
audio_output=not text_only_mode,
),
)
session.input.set_text_enabled(True)tall-airline-16756
03/22/2026, 3:13 PMcustom_text_input_handler(...) and the room_options=room_io.RoomOptions(text_input=room_io.TextInputOptions(...)) snippet, plus the fact you still see "ignored text stream..." and the print never runs.
Immediate observations
• The runtime log indicates the session isn’t recognizing any callback attached for the lk.chat stream. That usually means either (A) the options object with the callback isn’t the one used by the active session, (B) text input is disabled at the time messages arrive, or (C) the callback registration happens too late (timing/lifecycle issue).
• Your callback signature looks correct and your handler code is fine as a diagnostic (simple print + interrupt + generate_reply).
Concrete checks & quick fixes to try now
1. Ensure the options object you pass is actually used by session.start
◦ You used room_options=room_io.RoomOptions(...) in your snippet. Confirm the session.start you call accepts room_options= (not room_input_options= or room_io.RoomOptions vs RoomInputOptions mismatch). Some SDK variants use room_input_options / room_output_options names. Use the exact parameter name the version of the SDK expects.
1. Move callback registration earlier (before start) and enable text explicitly
◦ Call session.input.set_text_enabled(True) before or immediately after session.start, but preferably before any clients send messages.
1. Use a module-level (not bound method) function for the callback
◦ For debugging, keep custom_text_input_handler as a top-level function (not a method on a class instance) to avoid issues with serialization/closure or bound-self mismatch.
1. Add logs around session lifecycle
◦ Print/log immediately after session.start and in any session connected/ready event handlers. Make sure messages are sent only after you see connected/ready.
1. Try the minimal diagnostic example below — copy-paste this and run it to rule out config shape/timing issues.
Minimal diagnostic example (guarantees callback placement)
# module-level handler
def debug_text_handler(session, event):
print("🔥 DEBUG: text handler invoked, event:", event.text)
session.interrupt()
session.generate_reply(user_input=event.text)
# Start session with explicit room_options shape that attaches the text callback
await session.start(
room=ctx.room,
agent=Assistant(...),
room_options=room_io.RoomOptions(
text_input=room_io.TextInputOptions(
text_input_cb=debug_text_handler
),
audio_input=room_io.AudioInputOptions(
noise_cancellation=noise_cancellation.BVC(),
),
audio_output=not text_only_mode,
),
)
# Ensure text input is explicitly enabled once the session has started
session.input.set_text_enabled(True)
print("Session started and text input explicitly enabled")
If your SDK variant instead expects room_input_options replace room_options= with room_input_options= and attach the same nested text_input there — the key is to attach to the exact options parameter that session.start reads.
If that still doesn’t hit, please paste two small things
• The exact signature of session.start in your installed package (e.g., quick print of help(session.start) or the import path/version) — this confirms which parameter name to use.
• The session startup logs (a few lines before and after session.start and the "ignored text stream..." message) so I can check ordering/timing.
Why I suspect a mismatch
• You’re seeing the ignored-text log which means the runtime observes the incoming lk.chat stream but didn’t find a callback on the active session. That’s most often caused by passing the callback in the wrong options object / parameter or registering it after the session is already connected and messages arrive.
Next step I’ll take with you
• Once you paste the small items above (or confirm whether your SDK uses room_options vs room_input_options), I’ll give the exact corrected snippet that matches your SDK and a small test you can run to prove the handler is invoked. If needed, I’ll also show how to subscribe to conversation_item_added as an alternate way to observe incoming text events while we debug callback registration., with interactive elementstall-ability-51442
03/22/2026, 3:22 PMtall-airline-16756
03/22/2026, 3:22 PMroom_input_options parameter that the runtime warns is deprecated, and your explicit callback never fires while the runtime logs “ignored text stream with topic 'lk.chat', no callback attached.” Let’s solve this step-by-step.
What I’m responding to
• Your last snippet that uses room_input_options=RoomInputOptions(text_input_cb=...) and the runtime warning to use RoomOptions instead. You also confirmed the callback print is never hit and the ignored-text log continues.
Why this likely isn’t your handler code
• Your handler signature and body look fine for diagnosing (simple print then interrupt + generate).
• The runtime message strongly suggests the session never saw a registered callback for the active RoomOptions that the session is actually using. The deprecation warning points to a parameter/shape mismatch as the most likely root cause.
Concrete next steps — try this exact flow 1) Use RoomOptions (not RoomInputOptions/RoomOutputOptions) and attach TextInputOptions there
• Copy this minimal, module-level example exactly and run it. Make sure the function is defined at module scope (not as a bound method).
# module-level handler
def custom_text_input_handler(session, event):
print("🔥 Custom text input handler invoked:", event.text)
session.interrupt()
session.generate_reply(user_input=event.text)
# start the session using RoomOptions (replace ... with your existing args)
await session.start(
room=ctx.room,
agent=Assistant(
student_data=student_data,
is_demo=is_demo,
memory_context=memory_context,
tutor_instructions=tutor_instructions,
conversation_history=conversation_history,
target_session_minutes=target_session_minutes,
),
room_options=room_io.RoomOptions(
text_input=room_io.TextInputOptions(
text_input_cb=custom_text_input_handler
),
audio_input=room_io.AudioInputOptions(
noise_cancellation=noise_cancellation.BVC(),
),
audio_output=not text_only_mode,
),
)
# explicitly enable text input after start to be safe
session.input.set_text_enabled(True)
print("Session started; text input explicitly enabled")
2) Ensure messages arrive after the session is ready
• Wait for the session start logs / connected-ready messages before sending a test message. If you send messages before the session finishes initializing, the stream may be ignored.
3) Confirm the frontend sends to the lk.chat topic
• Send text using the client sendText(..., topic='lk.chat'). The runtime ignores other topics by default.
4) If the handler still does not run, capture these items and paste them here:
• The exact livekit-agents package version (the full version string for 1.5.x you installed).
• The console logs for session start: show a few lines before and after await session.start(...) and the exact "ignored text stream..." log lines (timestamps help).
• A copy of the import names you use (e.g., from livekit.agents import room_io vs other import paths) so I can confirm the correct option class names.
Why I asked for these items
• The runtime warning about deprecation suggests your session may be reading a different options shape. If room_input_options is being ignored by the new session API, the callback will never attach and the runtime will log ignored streams even though your handler exists in code.
• Logs + version let me confirm whether this is a migration issue introduced in 1.5 or a timing/usage mismatch.
Optional alternate diagnostic
• If you want a quick alternative while testing, subscribe to conversation_item_added events (those trigger when text is committed to history). That will at least let you observe incoming messages server-side while we get the direct callback path fixed.
Let me know which you prefer:
• I can review the exact logs + version you paste and point to the precise fix, or
• If you want, I can provide a second minimal example that uses conversation_item_added to confirm messages reach the session while we debug the direct callback registration. Sources: Agent session | LiveKit Documentation | Text and transcriptions | LiveKit Documentation, with interactive elementstall-ability-51442
03/22/2026, 3:29 PMconversation_item_added isn't getting hit. should i try scubscribing to lk.chat directly?tall-airline-16756
03/22/2026, 3:29 PMconversation_item_added, and none of them fire. That strongly narrows the problem to one of a few places: text input is disabled for the active session, messages are not being sent to the lk.chat topic the server expects, or the session/options object the agent actually uses doesn’t have the callback attached.
Short answer to your question: yes — subscribing directly to the lk.chat text stream is a good diagnostic step. It will tell you whether the server is receiving those text frames at all, independent of the agent callback machinery.
Concrete troubleshooting steps (in order) 1) Confirm text input is enabled for the active session
• Explicitly enable text input before sending messages:
◦ Call session.input.set_text_enabled(True) right after you start the session (or before sending test messages).
◦ If your SDK offers a text_input flag in RoomOptions, set it explicitly to true.
2) Verify the client is sending to topic 'lk.chat'
• On the client, ensure sendText (or equivalent) is called with topic='lk.chat'.
• If you have control of the client, send a test message after you see the session print “Session started; text input explicitly enabled”.
3) Subscribe directly to the lk.chat stream as a diagnostic
• Add a low-level subscription to see raw incoming text frames. This bypasses the agent callback layer so you can confirm delivery. How you do this will depend on your environment, but conceptually:
◦ Add a handler that listens for incoming text streams/messages and logs them immediately.
◦ If you see the messages here, the problem is in how RoomOptions/callbacks are attached or in agent lifecycle timing.
◦ If you do not see them, the messages are not arriving to the server (client/topic mismatch or transport problem).
4) Re-run with a minimal end-to-end test
• Use the minimal module-level callback + RoomOptions example I gave earlier.
• Start the session, explicitly enable text, wait for the "started/ready" log, then send a single test message from the client to lk.chat.
What to capture and paste if this still fails
• The livekit-agents package version (exact string for 1.5.x).
• The exact session start logs (a few lines before and after await session.start(...)) including the deprecation warning you saw.
• The log lines when you send a test message (timestamped) showing "ignored text stream..." or not.
• The client call used to send text (the sendText invocation or equivalent), showing the topic parameter.
Quick example: subscribe to lk.chat (conceptual — adapt to your stack)
• If your SDK exposes a lower-level event bus, add a handler that logs every incoming text frame on any topic, and filter for lk.chat.
• If you can’t do a low-level subscription, use conversation_item_added as a fallback — but you already said that didn’t fire, which makes the direct subscription even more useful.
Why this approach
• If direct subscription shows messages arriving, we’ll know callbacks are not being attached correctly (timing/options mismatch) and can focus on exactly where to pass RoomOptions.
• If direct subscription shows nothing, the client is likely sending to the wrong topic or text input is disabled upstream.
If you want, I can:
• Provide a minimal direct-subscribe example tailored to the exact import names you use (e.g., from livekit.agents import room_io) — paste your imports and I’ll tailor it.
• Review the logs and version you paste and give an exact correction to the session.start call that will attach the callback correctly.
Which would you like to do next — try the direct subscription now, or paste the logs + version and I’ll analyze them?
, with interactive elementstall-ability-51442
03/22/2026, 3:49 PMtall-airline-16756
03/22/2026, 3:50 PMlk.chat stream had no callback attached.
• You confirmed the documented RoomOptions/TextInputOptions callbacks and conversation_item_added didn’t fire.
• Manually registering a low-level text-stream handler for the chat topic (what you posted) fixed it — messages are now seen and processed.
Why this explains the behavior you saw
• The runtime is reporting that no handler was attached for the lk.chat stream on the active session. The deprecation warning you saw about RoomInputOptions / RoomOutputOptions means the SDK’s session options shape and callback-registration surface changed; if callbacks are passed to the wrong options object or if the client is sending on a different topic, the SDK won’t wire up a handler for those incoming frames.
• In addition, some UI libraries (you mentioned useChat / components-react) send text on a different topic constant (your TOPIC_CHAT), not necessarily lk.chat. If the frontend is sending on a non-lk.chat topic, the agent’s high-level text callback (which listens for lk.chat) won’t be invoked. Your manual subscription listens to that topic directly and therefore bypasses the higher-level callback wiring — that’s why it worked.
Is this a bug?
• I can’t declare internal intent or promises about releases, but from the symptoms:
◦ This looks like a behavior change in how text streams are routed/registered (and/or a migration requirement caused by the options deprecation).
◦ If you were previously relying on an implicit handler accepting any chat-like topic, and now the SDK requires callbacks be attached to lk.chat (or requires RoomOptions in the new shape), that is a breaking change in behavior even if intentional.
• Whether it’s a bug or an intentional breaking change depends on release notes / maintainers’ decision. The important part now is reliable fix paths you can use immediately.
Practical options to fix and avoid fragility You have three clear choices — pick the one that fits your setup best:
1) Make the frontend send text on the expected topic (lk.chat)
• If you can change the client, send messages with topic='lk.chat' so the agent’s high-level text path (RoomOptions/TextInputOptions) will see them automatically.
• This is the cleanest fix if you control both client and server.
2) Attach the high-level callback correctly using the new RoomOptions shape
• Ensure you pass the callback in the room_options=RoomOptions(text_input=TextInputOptions(text_input_cb=...)) parameter that the active SDK expects (not deprecated room_input_options / room_output_options).
• Keep the callback a module-level function during testing to avoid binding/serialization issues and make sure text is enabled (session.input.set_text_enabled(True)) before sending test messages.
3) Keep your low-level subscription (what you implemented) as a deliberate compatibility shim
• Your _register_lk_chat_text_handler approach is valid and reliable: it bypasses the agent callback registration and consumes text frames directly, so it works even if frontends use different topics or the high-level callback path is not wired.
• This is the right choice when you don’t control the client topic or want to be tolerant of different client libraries.
Recommended next steps I can help with
• If you prefer to convert the client to lk.chat, I can show the exact client-side change needed.
• If you prefer to use the high-level RoomOptions callback, paste the exact session.start call and imports you use; I’ll give the exact minimal snippet matching your package so it attaches correctly.
• If you keep the low-level handler (which is fine), I can suggest a couple of small hardening changes (filtering out local participant reliably, adding metrics/logging, and safe exception handling).
If you want, I can also:
• Draft a concise issue/feedback text you can raise against the livekit-agents release notes or repo describing this break (so maintainers can clarify if it’s intended), or
• Provide a minimal end-to-end example (client + server) that uses the new RoomOptions text_input callback and shows the full flow working.
Which path would you like to take — fix the client to send lk.chat, make the RoomOptions callback work, or harden your low-level subscription?
, with interactive elementsrhythmic-helmet-52095
03/23/2026, 12:14 AMtall-airline-16756
03/23/2026, 12:15 AMRoomOptions shape and stricter wiring of text callbacks, and older/deprecated paths or implicit handling you relied on no longer get automatically attached.
• Because your frontend was (or may have been) sending text on a topic that the new high-level callbacks weren’t wired to, the agent runtime logged the ignored lk.chat stream and none of the high-level callbacks fired — which forced you to add the low-level lk.chat subscription as a pragmatic fix.
Why your manual subscription made it work
• Your handler listens directly to the room text stream and consumes frames regardless of the higher-level callback registration. That bypasses the changed callback registration path and restores message delivery to your agent logic.
Is this a bug or intended?
• From your symptom set and the PR link, this behaves like a breaking change (intentional or accidental) in how text streams are registered/handled. Whether it’s classified as a bug depends on the maintainers’ intent and the release notes for that PR. Practically speaking, it is a breaking change in behavior relative to older versions and understandably disruptive.
Recommended production paths (pick one)
• If you control the client: make the client send messages explicitly to lk.chat and use the new RoomOptions(text_input=TextInputOptions(...)) callback shape. This is the clean, forward-compatible solution.
• If you don’t control the client or want robustness: keep the low-level room.register_text_stream_handler(TOPIC_CHAT, ...) shim (your current fix). It’s reliable and tolerant of differing client topics.
• If you want the high-level API: migrate all server-side startup to use room_options=RoomOptions(...) with text_input=TextInputOptions(text_input_cb=...) and ensure session.input.set_text_enabled(True) happens before messages arrive. Use a module-level callback function for testing.
I can help with any of these:
• Give the exact minimal server snippet that uses the new RoomOptions shape matching your imports.
• Provide the exact client-side change to send with topic='lk.chat'.
• Draft a concise issue/PR comment you can paste into the linked GitHub PR describing your regression and environment (version, logs, and the workaround you used) so maintainers can prioritize a fix or clarify intended behavior.
Which would you like next — a migration snippet for your server, the client-change snippet, or help drafting a clear issue comment for the PR?
, with interactive elementsrhythmic-helmet-52095
03/23/2026, 12:18 AMtall-airline-16756
03/23/2026, 12:18 AMlk.chat) as an acceptable compatibility fix until the SDK behavior is clarified or fixed.
Recommended next steps (pick one)
• If you control the client: change the client to send text on topic='lk.chat' and attach your callback via room_options=RoomOptions(text_input=TextInputOptions(text_input_cb=...)). That’s the clean, forward-compatible approach.
• If you don’t control the client or prefer resilience: keep your low-level subscription as a deliberate compatibility shim (your current code). I can help harden it (logging, dedup, error handling).
• If you want the SDK-level fix: I can help you draft a concise comment/issue summary for the PR/issue that explains the regression with your version, logs, and the minimal repro you used (that helps maintainers prioritize a fix or document the breaking change).
Optional help I can provide now
• A minimal server-side snippet using the new RoomOptions shape that you can drop into your app to test.
• A minimal client example to send to lk.chat.
• A short issue comment you can paste into the linked PR/issue describing your environment, logs, and the workaround you used.
Which would you like me to do next — provide the migration snippet, client change, hardening suggestions for your shim, or help draft an issue comment for the PR?
, with interactive elements