fix: wait for agent before sending text
Rebuild & Deploy / rebuild (push) Successful in 1m2s

This commit is contained in:
snowspeeder committed 2026-08-29 08:00:42 -04:00
1 parent 63e15b6023
commit b1643b635d
2 files changed
+38 -1

No files matched your search

+11
View File
@@ -758,6 +758,17 @@ async def handle_job(ctx: JobContext) -> None:
)
await ctx.connect()
# The participant can appear in the browser slightly before AgentSession is
# ready to accept lk.chat streams. Explicitly signal readiness so the first
# typed message is never raced against session startup.
try:
await ctx.room.local_participant.publish_data(
json.dumps({"type": "agent_ready"}),
reliable=True,
topic="conversation-control",
)
except Exception as exc: # noqa: BLE001
logger.warning("failed to publish agent readiness: %s", exc)
logger.info("Agent connected to room %s", ctx.room.name)
+27 -1
View File
@@ -31,6 +31,7 @@ const MODE_KEY = "hope_conversation_mode";
// ── State ───────────────────────────────────────────────────────────────────
let room = null;
let agentParticipant = null;
let agentReady = false;
let uiState = "idle"; // idle | connecting | listening | thinking | speaking
let micLevel = 0; // 0..1, smoothed
let agentAudioLevel = 0; // 0..1, smoothed
@@ -518,7 +519,9 @@ function registerTranscriptionStream(rm) {
function handleDataPacket(payload, participant, topic) {
try {
const msg = JSON.parse(new TextDecoder().decode(payload));
if (msg.type === "transcript") {
if (msg.type === "agent_ready") {
agentReady = true;
} else if (msg.type === "transcript") {
addMessage(msg.role || "agent", msg.text);
if (conversationMode === "text" && (msg.role || "agent") === "agent") {
setState("listening");
@@ -721,6 +724,7 @@ function createRoom(token) {
startBtn.disabled = false;
stopBtn.disabled = true;
agentParticipant = null;
agentReady = false;
});
return newRoom.connect(LIVEKIT_URL, token, {
@@ -733,6 +737,22 @@ function createRoom(token) {
});
}
function waitForAgentReady(timeoutMs) {
return new Promise((resolve) => {
if (agentReady) return resolve(true);
const deadline = Date.now() + timeoutMs;
const timer = setInterval(() => {
if (agentReady) {
clearInterval(timer);
resolve(true);
} else if (Date.now() > deadline) {
clearInterval(timer);
resolve(false);
}
}, 100);
});
}
function waitForAgent(timeoutMs) {
return new Promise((resolve) => {
if (findAgent(room)) return resolve(true);
@@ -773,6 +793,7 @@ async function connectConversation() {
const stale = room;
room = null;
agentParticipant = null;
agentReady = false;
await stale.disconnect();
const freshToken = await fetchToken(ROOM_NAME);
room = await createRoom(freshToken);
@@ -780,6 +801,10 @@ async function connectConversation() {
throw new Error("Assistant did not join — reload the page and try again");
}
}
statusEl.textContent = "Hope joined · Finishing setup…";
if (!(await waitForAgentReady(10000))) {
throw new Error("Assistant joined but was not ready — try again");
}
sendModeMessage(conversationMode);
if (conversationMode === "voice") {
@@ -870,6 +895,7 @@ stopBtn.addEventListener("click", () => {
room.disconnect();
room = null;
agentParticipant = null;
agentReady = false;
}
teardownAudio();
stopVisualLoop();