e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
import { useAuiState } from "@assistant-ui/react";
|
|
import {
|
|
updateXuluxPendingUserMessage,
|
|
updateXuluxThreadStatus,
|
|
} from "./xulux-local-storage";
|
|
|
|
export function XuluxThreadStatusObserver() {
|
|
const remoteId = useAuiState((state) => state.threadListItem.remoteId);
|
|
const isRunning = useAuiState((state) => state.thread.isRunning);
|
|
const messages = useAuiState((state) => state.thread.messages);
|
|
const previous = useRef<{
|
|
remoteId: string | undefined;
|
|
isRunning: boolean;
|
|
}>({ remoteId: undefined, isRunning: false });
|
|
|
|
useEffect(() => {
|
|
if (!remoteId || !isRunning) return;
|
|
|
|
const latestUserText = getLatestUserText(messages);
|
|
if (latestUserText) {
|
|
updateXuluxPendingUserMessage(remoteId, latestUserText);
|
|
}
|
|
}, [isRunning, messages, remoteId]);
|
|
|
|
useEffect(() => {
|
|
const prior = previous.current;
|
|
previous.current = { remoteId, isRunning };
|
|
|
|
if (!remoteId) return;
|
|
if (prior.remoteId !== remoteId) return;
|
|
|
|
if (isRunning && !prior.isRunning) {
|
|
updateXuluxThreadStatus(remoteId, "running");
|
|
return;
|
|
}
|
|
|
|
if (!isRunning && prior.isRunning) {
|
|
updateXuluxThreadStatus(remoteId, "idle");
|
|
updateXuluxPendingUserMessage(remoteId, null);
|
|
}
|
|
}, [remoteId, isRunning]);
|
|
|
|
return null;
|
|
}
|
|
|
|
function getLatestUserText(
|
|
messages: readonly {
|
|
role: string;
|
|
content: readonly unknown[];
|
|
}[],
|
|
): string | null {
|
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
const message = messages[index];
|
|
if (message?.role !== "user") continue;
|
|
|
|
const text = message.content
|
|
.flatMap((part) => {
|
|
if (!part || typeof part !== "object") return [];
|
|
const typedPart = part as Record<string, unknown>;
|
|
return typedPart.type === "text" && typeof typedPart.text === "string"
|
|
? [typedPart.text]
|
|
: [];
|
|
})
|
|
.join("\n")
|
|
.trim();
|
|
|
|
if (text) return text;
|
|
}
|
|
|
|
return null;
|
|
}
|