Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ A reference implementation of a chatbot interface built with React, TypeScript,

## 🚀 Quick Start

**Prerequisites**: Ensure the [lightspeed-stack](https://github.com/lightspeed-core/lightspeed-stack) is running to provide the backend API services.

If you need help getting `lightspeed-stack` running follow this [guide](https://github.com/lightspeed-core/lightspeed-stack/blob/main/docs/getting_started.md).

```bash
git clone https://github.com/your-org/lightspeed-reference-ui
cd lightspeed-reference-ui
Expand Down Expand Up @@ -166,6 +170,7 @@ Body: {
Response: Server-Sent Events stream with events:
- start: { conversation_id: string }
- token: { id: number, role: string, token: string }
- tool_call: { id: number, role: string, token: string | Record<string, any> }
- end: { referenced_documents: any[], truncated: any, input_tokens: number, output_tokens: number }
```

Expand Down Expand Up @@ -245,6 +250,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
## 🆘 Support

If you encounter any issues or have questions:
- Check the [Issues](https://github.com/your-org/lightspeed-reference-ui/issues) page
- Check the [Issues](https://github.com/lightspeed-core/lightspeed-reference-ui/issues) page
- Review the component documentation in `src/app/LightspeedChatbot/README.md`
- Refer to the [PatternFly documentation](https://www.patternfly.org/get-started/develop) for UI components
39 changes: 27 additions & 12 deletions src/app/LightspeedChatbot/hooks/useChatbot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MessageProps } from '@patternfly/chatbot/dist/dynamic/Message';
import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
import { DropEvent, DropdownItem, DropdownList } from '@patternfly/react-core';

import { Model, QueryRequest, StreamTokenData, StreamEndData, ConversationResponse } from '../types';
import { Model, QueryRequest, StreamTokenData, StreamEndData, ConversationResponse, StreamToolCallData } from '../types';
import { INITIAL_MESSAGES, INITIAL_CONVERSATIONS, USER_AVATAR, BOT_AVATAR, DEFAULT_SYSTEM_PROMPT } from '../constants';
import { fetchModels, sendStreamingQuery, fetchConversation, deleteConversation } from '../services/api';
import { generateId, findMatchingItems, copyToClipboard } from '../utils/helpers';
Expand Down Expand Up @@ -41,7 +41,7 @@ export const useChatbot = () => {
// Set first LLM model as default
const defaultModel = models.find((model) => model.api_model_type === 'llm');
if (defaultModel) {
setSelectedModel(defaultModel.identifier);
setSelectedModel(defaultModel.provider_resource_id);
setSelectedProvider(defaultModel.provider_id);
}
};
Expand Down Expand Up @@ -148,7 +148,12 @@ export const useChatbot = () => {

// Selection handlers
const onSelectModel = (_event?: React.MouseEvent, value?: string | number) => {
setSelectedModel(value as string);
const selectedIdentifier = value as string;
const selectedModelData = availableModels.find(model => model.identifier === selectedIdentifier);
if (selectedModelData) {
setSelectedModel(selectedModelData.provider_resource_id);
setSelectedProvider(selectedModelData.provider_id);
}
};

const onSelectDisplayMode = (_event?: React.MouseEvent, value?: string | number) => {
Expand Down Expand Up @@ -328,6 +333,7 @@ export const useChatbot = () => {
conversation_id: currentConversationId || undefined,
model: selectedModel || undefined,
provider: selectedProvider || undefined,
no_tools: false,
system_prompt: DEFAULT_SYSTEM_PROMPT,
attachments:
attachedFiles.length > 0 && fileContents.length > 0
Expand All @@ -347,15 +353,7 @@ export const useChatbot = () => {
queryRequest,
// onToken callback
(token: string, tokenData?: StreamTokenData) => {
if (tokenData && tokenData.role === 'tool_execution') {
currentToolExecutions.push(token);
setToolExecutions((prev) => ({
...prev,
[botMessageId]: [...currentToolExecutions],
}));
} else {
streamingContent += token;
}
streamingContent += token;

setMessages((prevMessages) => {
const updatedMessages = [...prevMessages];
Expand Down Expand Up @@ -407,6 +405,23 @@ export const useChatbot = () => {
});
setAnnouncement(`Message from Lightspeed AI: ${streamingContent}`);
},
// onToolCall callback
(toolCallData: StreamToolCallData) => {
console.log('toolCallData', toolCallData);
if (
typeof toolCallData.token === 'object' &&
toolCallData.token !== null &&
typeof toolCallData.token.tool_name === 'string' &&
typeof toolCallData.token.arguments === 'object'
) {
const { tool_name, arguments: toolArgs } = toolCallData.token;
currentToolExecutions.push(`${tool_name}(${JSON.stringify(toolArgs)})`);
}
setToolExecutions((prev) => ({
...prev,
[botMessageId]: [...currentToolExecutions],
}));
},
);
} catch (error) {
console.error('Error sending streaming query:', error);
Expand Down
6 changes: 6 additions & 0 deletions src/app/LightspeedChatbot/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
StreamEvent,
StreamStartData,
StreamTokenData,
StreamToolCallData,
StreamEndData,
ConversationResponse,
} from '../types';
Expand Down Expand Up @@ -79,6 +80,7 @@ export const sendStreamingQuery = async (
onToken: (token: string, tokenData?: StreamTokenData) => void,
onStart: (conversationId: string) => void,
onEnd: (endData: StreamEndData) => void,
onToolCall: (toolCallData: StreamToolCallData) => void,
): Promise<void> => {
try {
const response = await fetch(`${API_BASE_URL}/v1/streaming_query`, {
Expand Down Expand Up @@ -117,6 +119,10 @@ export const sendStreamingQuery = async (
const startData = eventData.data as StreamStartData;
onStart(startData.conversation_id);
break;
case 'tool_call':
const toolCallData = eventData.data as StreamToolCallData;
onToolCall(toolCallData);
break;
case 'token':
const tokenData = eventData.data as StreamTokenData;
onToken(tokenData.token, tokenData);
Expand Down
9 changes: 8 additions & 1 deletion src/app/LightspeedChatbot/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface QueryRequest {
conversation_id?: string;
provider?: string;
model?: string;
no_tools?: boolean;
system_prompt?: string;
attachments?: Array<{
attachment_type: string;
Expand Down Expand Up @@ -42,7 +43,7 @@ export interface ConversationResponse {

// Streaming types
export interface StreamEvent {
event: 'start' | 'token' | 'end';
event: 'start' | 'token' | 'tool_call' | 'end';
data: any;
}

Expand All @@ -56,6 +57,12 @@ export interface StreamTokenData {
token: string;
}

export interface StreamToolCallData {
id: number;
role: string;
token: string | Record<string, any>;
}

export interface StreamEndData {
referenced_documents: Array<{
doc_url: string;
Expand Down