refactor pilot chat api contract and typed ai-sdk flow
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
MeQueryDocument,
|
||||
} from "~~/graphql/generated";
|
||||
import { Chat as AiChat } from "@ai-sdk/vue";
|
||||
import { DefaultChatTransport, isTextUIPart, type UIMessage } from "ai";
|
||||
import { DefaultChatTransport, isTextUIPart, type DataUIPart, type UIMessage } from "ai";
|
||||
import { isVoiceCaptureSupported, transcribeAudioBlob } from "~/composables/useVoiceTranscription";
|
||||
|
||||
import type { Contact } from "~/composables/useContacts";
|
||||
@@ -90,8 +90,31 @@ export type ChatConversation = {
|
||||
lastMessageText?: string | null;
|
||||
};
|
||||
|
||||
type PilotDataTypes = {
|
||||
"agent-log": {
|
||||
requestId: string;
|
||||
at: string;
|
||||
text: string;
|
||||
};
|
||||
};
|
||||
|
||||
type PilotUiMessage = UIMessage<unknown, PilotDataTypes>;
|
||||
|
||||
function safeTrim(value: unknown) { return String(value ?? "").trim(); }
|
||||
|
||||
function parsePilotAgentLog(part: DataUIPart<PilotDataTypes>) {
|
||||
if (part.type !== "data-agent-log") return null;
|
||||
|
||||
const data = part.data as Partial<PilotDataTypes["agent-log"]> | null | undefined;
|
||||
const text = safeTrim(data?.text);
|
||||
if (!text) return null;
|
||||
|
||||
return {
|
||||
text,
|
||||
at: safeTrim(data?.at) || new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function usePilotChat(opts: {
|
||||
apolloAuthReady: ComputedRef<boolean>;
|
||||
authMe: Ref<any>;
|
||||
@@ -191,24 +214,24 @@ export function usePilotChat(opts: {
|
||||
// ---------------------------------------------------------------------------
|
||||
// AI SDK chat instance
|
||||
// ---------------------------------------------------------------------------
|
||||
const pilotChat = new AiChat<UIMessage>({
|
||||
const pilotChat = new AiChat<PilotUiMessage>({
|
||||
transport: new DefaultChatTransport({
|
||||
api: "/api/pilot-chat",
|
||||
}),
|
||||
onData: (part: any) => {
|
||||
if (part?.type !== "data-agent-log") return;
|
||||
const text = String(part?.data?.text ?? "").trim();
|
||||
if (!text) return;
|
||||
const at = String(part?.data?.at ?? new Date().toISOString());
|
||||
pilotLiveLogs.value = [...pilotLiveLogs.value, { id: `${Date.now()}-${Math.random()}`, text, at }];
|
||||
onData: (part) => {
|
||||
const log = parsePilotAgentLog(part);
|
||||
if (!log) return;
|
||||
pilotLiveLogs.value = [...pilotLiveLogs.value, { id: `${Date.now()}-${Math.random()}`, text: log.text, at: log.at }];
|
||||
},
|
||||
onFinish: async () => {
|
||||
pilotSending.value = false;
|
||||
livePilotUserText.value = "";
|
||||
livePilotAssistantText.value = "";
|
||||
pilotLiveLogs.value = [];
|
||||
await Promise.all([refetchChatMessages(), refetchChatConversations(), opts.refetchAllCrmQueries()]);
|
||||
},
|
||||
onError: () => {
|
||||
pilotSending.value = false;
|
||||
if (livePilotUserText.value) {
|
||||
pilotInput.value = livePilotUserText.value;
|
||||
}
|
||||
@@ -285,7 +308,7 @@ export function usePilotChat(opts: {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Pilot ↔ UIMessage bridge
|
||||
// ---------------------------------------------------------------------------
|
||||
function pilotToUiMessage(message: PilotMessage): UIMessage {
|
||||
function pilotToUiMessage(message: PilotMessage): PilotUiMessage {
|
||||
return {
|
||||
id: message.id,
|
||||
role: message.role,
|
||||
@@ -377,20 +400,8 @@ export function usePilotChat(opts: {
|
||||
);
|
||||
} catch {
|
||||
pilotInput.value = text;
|
||||
} finally {
|
||||
const latestAssistant = [...pilotChat.messages]
|
||||
.reverse()
|
||||
.find((message) => message.role === "assistant");
|
||||
|
||||
if (latestAssistant) {
|
||||
const textPart = latestAssistant.parts.find(isTextUIPart);
|
||||
livePilotAssistantText.value = textPart?.text ?? "";
|
||||
}
|
||||
|
||||
livePilotUserText.value = "";
|
||||
livePilotAssistantText.value = "";
|
||||
pilotSending.value = false;
|
||||
await Promise.all([refetchChatMessages(), refetchChatConversations(), opts.refetchAllCrmQueries()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user