import React, { useState, useEffect } from 'react';
const ConversationEvents = ({ eventsUrl, token }) => {
const [events, setEvents] = useState([]);
useEffect(() => {
const eventSource = new EventSource(eventsUrl + '?token=' + token);
eventSource.onmessage = (event) => {
const rawEvent = JSON.parse(event.data);
setEvents(current => chatEventsAccumulator(current, rawEvent));
};
eventSource.onerror = (error) => {
console.error('EventSource failed:', error);
};
return () => {
eventSource.close();
};
}, [eventsUrl, token]);
return (
<div>
<h3>Conversation Events</h3>
{events.map((event) => (
<div key={`${event.id}-${event.type}`}>
{event.type === 'user.message' && (
<div>
<strong>User:</strong> {event.payload.text}
</div>
)}
{event.type === 'agent.message' && (
<div>
<strong>Agent:</strong> {event.payload.text}
{!event.payload.is_complete && <span> ...</span>}
</div>
)}
{event.type === 'agent.tool.call' && (
<div>
<strong>Tool Call:</strong> {event.payload.name}({event.payload.arguments})
{event.payload.result && <div>Result: {event.payload.result}</div>}
{event.payload.error && <div>Error: {event.payload.error}</div>}
</div>
)}
{event.type === 'conversation.started' && (
<div><em>Conversation started</em></div>
)}
{event.type === 'conversation.ended' && (
<div><em>Conversation ended</em></div>
)}
{event.type === 'server.error' && (
<div><strong>Error:</strong> {event.payload.error}</div>
)}
</div>
))}
</div>
);
};
// Event accumulator function to handle streaming events
const chatEventsAccumulator = (current = [], rawEvent) => {
const currentEvents = current || [];
const { id, created_at, payload } = rawEvent;
if (payload.type === "agent.message.delta") {
const existingIndex = currentEvents.findIndex(
(event) => event.type === "agent.message" && event.payload.generation_id === payload.generation_id
);
const simplifiedEvent = {
id: existingIndex >= 0 ? currentEvents[existingIndex].id : id,
created_at,
type: "agent.message",
payload: {
generation_id: payload.generation_id,
text: existingIndex >= 0
? (currentEvents[existingIndex].payload.text || "") + payload.text_delta
: payload.text_delta || "",
is_complete: false,
},
};
if (existingIndex >= 0) {
const newEvents = [...currentEvents];
newEvents[existingIndex] = simplifiedEvent;
return newEvents;
} else {
return [...currentEvents, simplifiedEvent];
}
}
if (payload.type === "agent.message.completed") {
const existingIndex = currentEvents.findIndex(
(event) => event.type === "agent.message" && event.payload.generation_id === payload.generation_id
);
const simplifiedEvent = {
id: existingIndex >= 0 ? currentEvents[existingIndex].id : id,
created_at,
type: "agent.message",
payload: {
generation_id: payload.generation_id,
text: payload.text,
is_complete: true,
},
};
if (existingIndex >= 0) {
const newEvents = [...currentEvents];
newEvents[existingIndex] = simplifiedEvent;
return newEvents;
} else {
return [...currentEvents, simplifiedEvent];
}
}
if (payload.type === "agent.tool_call.created") {
const simplifiedEvent = {
id,
created_at,
type: "agent.tool.call",
payload: {
call_id: payload.call_id,
name: payload.name,
arguments: payload.arguments,
is_complete: false,
},
};
return [...currentEvents, simplifiedEvent];
}
if (payload.type === "agent.tool_call.returned") {
const existingIndex = currentEvents.findIndex(
(event) => event.type === "agent.tool.call" && event.payload.call_id === payload.call_id
);
const simplifiedEvent = {
id: existingIndex >= 0 ? currentEvents[existingIndex].id : id,
created_at,
type: "agent.tool.call",
payload: {
call_id: payload.call_id,
name: payload.name,
arguments: payload.arguments,
result: payload.result,
error: payload.error,
is_complete: true,
},
};
if (existingIndex >= 0) {
const newEvents = [...currentEvents];
newEvents[existingIndex] = simplifiedEvent;
return newEvents;
} else {
return [...currentEvents, simplifiedEvent];
}
}
if (payload.type === "user.message.received") {
const simplifiedEvent = {
id,
created_at,
type: "user.message",
payload: {
text: payload.text,
is_complete: true,
},
};
return [...currentEvents, simplifiedEvent];
}
if (payload.type === "conversation.started") {
const simplifiedEvent = {
id,
created_at,
type: "conversation.started",
payload: { is_complete: true },
};
return [...currentEvents, simplifiedEvent];
}
if (payload.type === "conversation.ended") {
const simplifiedEvent = {
id,
created_at,
type: "conversation.ended",
payload: { is_complete: true },
};
return [...currentEvents, simplifiedEvent];
}
if (payload.type === "server.error") {
const simplifiedEvent = {
id,
created_at,
type: "server.error",
payload: {
error: payload.error,
is_complete: true,
},
};
return [...currentEvents, simplifiedEvent];
}
return currentEvents;
};
export default ConversationEvents;