This commit is contained in:
1 parent
63e15b6023
commit
b1643b635d
2 files changed
+38
-1
No files matched your search
@@ -758,6 +758,17 @@ async def handle_job(ctx: JobContext) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
await ctx.connect()
|
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)
|
logger.info("Agent connected to room %s", ctx.room.name)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -31,6 +31,7 @@ const MODE_KEY = "hope_conversation_mode";
|
|||||||
// ── State ───────────────────────────────────────────────────────────────────
|
// ── State ───────────────────────────────────────────────────────────────────
|
||||||
let room = null;
|
let room = null;
|
||||||
let agentParticipant = null;
|
let agentParticipant = null;
|
||||||
|
let agentReady = false;
|
||||||
let uiState = "idle"; // idle | connecting | listening | thinking | speaking
|
let uiState = "idle"; // idle | connecting | listening | thinking | speaking
|
||||||
let micLevel = 0; // 0..1, smoothed
|
let micLevel = 0; // 0..1, smoothed
|
||||||
let agentAudioLevel = 0; // 0..1, smoothed
|
let agentAudioLevel = 0; // 0..1, smoothed
|
||||||
@@ -518,7 +519,9 @@ function registerTranscriptionStream(rm) {
|
|||||||
function handleDataPacket(payload, participant, topic) {
|
function handleDataPacket(payload, participant, topic) {
|
||||||
try {
|
try {
|
||||||
const msg = JSON.parse(new TextDecoder().decode(payload));
|
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);
|
addMessage(msg.role || "agent", msg.text);
|
||||||
if (conversationMode === "text" && (msg.role || "agent") === "agent") {
|
if (conversationMode === "text" && (msg.role || "agent") === "agent") {
|
||||||
setState("listening");
|
setState("listening");
|
||||||
@@ -721,6 +724,7 @@ function createRoom(token) {
|
|||||||
startBtn.disabled = false;
|
startBtn.disabled = false;
|
||||||
stopBtn.disabled = true;
|
stopBtn.disabled = true;
|
||||||
agentParticipant = null;
|
agentParticipant = null;
|
||||||
|
agentReady = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return newRoom.connect(LIVEKIT_URL, token, {
|
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) {
|
function waitForAgent(timeoutMs) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (findAgent(room)) return resolve(true);
|
if (findAgent(room)) return resolve(true);
|
||||||
@@ -773,6 +793,7 @@ async function connectConversation() {
|
|||||||
const stale = room;
|
const stale = room;
|
||||||
room = null;
|
room = null;
|
||||||
agentParticipant = null;
|
agentParticipant = null;
|
||||||
|
agentReady = false;
|
||||||
await stale.disconnect();
|
await stale.disconnect();
|
||||||
const freshToken = await fetchToken(ROOM_NAME);
|
const freshToken = await fetchToken(ROOM_NAME);
|
||||||
room = await createRoom(freshToken);
|
room = await createRoom(freshToken);
|
||||||
@@ -780,6 +801,10 @@ async function connectConversation() {
|
|||||||
throw new Error("Assistant did not join — reload the page and try again");
|
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);
|
sendModeMessage(conversationMode);
|
||||||
if (conversationMode === "voice") {
|
if (conversationMode === "voice") {
|
||||||
@@ -870,6 +895,7 @@ stopBtn.addEventListener("click", () => {
|
|||||||
room.disconnect();
|
room.disconnect();
|
||||||
room = null;
|
room = null;
|
||||||
agentParticipant = null;
|
agentParticipant = null;
|
||||||
|
agentReady = false;
|
||||||
}
|
}
|
||||||
teardownAudio();
|
teardownAudio();
|
||||||
stopVisualLoop();
|
stopVisualLoop();
|
||||||
|
|||||||
Reference in new issue
Block a user