199 lines
5.8 KiB
TypeScript
199 lines
5.8 KiB
TypeScript
"use client";
|
|
|
|
import { ServerEvent, SessionStatus, AgentConfig } from "@/app/components/Realtime/types";
|
|
import { useTranscript } from "@/app/components/Realtime/contexts/TranscriptContext";
|
|
import { useEvent } from "@/app/components/Realtime/contexts/EventContext";
|
|
import { useRef } from "react";
|
|
|
|
export interface UseHandleServerEventParams {
|
|
setSessionStatus: (status: SessionStatus) => void;
|
|
selectedAgentName: string;
|
|
selectedAgentConfigSet: AgentConfig[] | null;
|
|
sendClientEvent: (eventObj: any, eventNameSuffix?: string) => void;
|
|
setSelectedAgentName: (name: string) => void;
|
|
shouldForceResponse?: boolean;
|
|
}
|
|
|
|
export function useHandleServerEvent({
|
|
setSessionStatus,
|
|
selectedAgentName,
|
|
selectedAgentConfigSet,
|
|
sendClientEvent,
|
|
setSelectedAgentName,
|
|
}: UseHandleServerEventParams) {
|
|
const {
|
|
transcriptItems,
|
|
addTranscriptBreadcrumb,
|
|
addTranscriptMessage,
|
|
updateTranscriptMessage,
|
|
updateTranscriptItemStatus,
|
|
} = useTranscript();
|
|
|
|
const { logServerEvent } = useEvent();
|
|
|
|
const handleFunctionCall = async (functionCallParams: {
|
|
name: string;
|
|
call_id?: string;
|
|
arguments: string;
|
|
}) => {
|
|
const args = JSON.parse(functionCallParams.arguments);
|
|
const currentAgent = selectedAgentConfigSet?.find(
|
|
(a) => a.name === selectedAgentName
|
|
);
|
|
|
|
addTranscriptBreadcrumb(`function call: ${functionCallParams.name}`, args);
|
|
|
|
if (currentAgent?.toolLogic?.[functionCallParams.name]) {
|
|
const fn = currentAgent.toolLogic[functionCallParams.name];
|
|
const fnResult = await fn(args, transcriptItems);
|
|
addTranscriptBreadcrumb(
|
|
`function call result: ${functionCallParams.name}`,
|
|
fnResult
|
|
);
|
|
|
|
sendClientEvent({
|
|
type: "conversation.item.create",
|
|
item: {
|
|
type: "function_call_output",
|
|
call_id: functionCallParams.call_id,
|
|
output: JSON.stringify(fnResult),
|
|
},
|
|
});
|
|
sendClientEvent({ type: "response.create" });
|
|
} else if (functionCallParams.name === "transferAgents") {
|
|
const destinationAgent = args.destination_agent;
|
|
const newAgentConfig =
|
|
selectedAgentConfigSet?.find((a) => a.name === destinationAgent) || null;
|
|
if (newAgentConfig) {
|
|
setSelectedAgentName(destinationAgent);
|
|
}
|
|
const functionCallOutput = {
|
|
destination_agent: destinationAgent,
|
|
did_transfer: !!newAgentConfig,
|
|
};
|
|
sendClientEvent({
|
|
type: "conversation.item.create",
|
|
item: {
|
|
type: "function_call_output",
|
|
call_id: functionCallParams.call_id,
|
|
output: JSON.stringify(functionCallOutput),
|
|
},
|
|
});
|
|
addTranscriptBreadcrumb(
|
|
`function call: ${functionCallParams.name} response`,
|
|
functionCallOutput
|
|
);
|
|
} else {
|
|
const simulatedResult = { result: true };
|
|
addTranscriptBreadcrumb(
|
|
`function call fallback: ${functionCallParams.name}`,
|
|
simulatedResult
|
|
);
|
|
|
|
sendClientEvent({
|
|
type: "conversation.item.create",
|
|
item: {
|
|
type: "function_call_output",
|
|
call_id: functionCallParams.call_id,
|
|
output: JSON.stringify(simulatedResult),
|
|
},
|
|
});
|
|
sendClientEvent({ type: "response.create" });
|
|
}
|
|
};
|
|
|
|
const handleServerEvent = (serverEvent: ServerEvent) => {
|
|
logServerEvent(serverEvent);
|
|
|
|
switch (serverEvent.type) {
|
|
case "session.created": {
|
|
if (serverEvent.session?.id) {
|
|
setSessionStatus("CONNECTED");
|
|
addTranscriptBreadcrumb(
|
|
`session.id: ${
|
|
serverEvent.session.id
|
|
}\nStarted at: ${new Date().toLocaleString()}`
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "conversation.item.created": {
|
|
let text =
|
|
serverEvent.item?.content?.[0]?.text ||
|
|
serverEvent.item?.content?.[0]?.transcript ||
|
|
"";
|
|
const role = serverEvent.item?.role as "user" | "assistant";
|
|
const itemId = serverEvent.item?.id;
|
|
|
|
if (itemId && transcriptItems.some((item) => item.itemId === itemId)) {
|
|
break;
|
|
}
|
|
|
|
if (itemId && role) {
|
|
if (role === "user" && !text) {
|
|
text = "[Transcribing...]";
|
|
}
|
|
addTranscriptMessage(itemId, role, text);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "conversation.item.input_audio_transcription.completed": {
|
|
const itemId = serverEvent.item_id;
|
|
const finalTranscript =
|
|
!serverEvent.transcript || serverEvent.transcript === "\n"
|
|
? "[inaudible]"
|
|
: serverEvent.transcript;
|
|
if (itemId) {
|
|
updateTranscriptMessage(itemId, finalTranscript, false);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "response.audio_transcript.delta": {
|
|
const itemId = serverEvent.item_id;
|
|
const deltaText = serverEvent.delta || "";
|
|
if (itemId) {
|
|
updateTranscriptMessage(itemId, deltaText, true);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "response.done": {
|
|
if (serverEvent.response?.output) {
|
|
serverEvent.response.output.forEach((outputItem) => {
|
|
if (
|
|
outputItem.type === "function_call" &&
|
|
outputItem.name &&
|
|
outputItem.arguments
|
|
) {
|
|
handleFunctionCall({
|
|
name: outputItem.name,
|
|
call_id: outputItem.call_id,
|
|
arguments: outputItem.arguments,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
|
|
case "response.output_item.done": {
|
|
const itemId = serverEvent.item?.id;
|
|
if (itemId) {
|
|
updateTranscriptItemStatus(itemId, "DONE");
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
|
|
const handleServerEventRef = useRef(handleServerEvent);
|
|
handleServerEventRef.current = handleServerEvent;
|
|
|
|
return handleServerEventRef;
|
|
}
|