Skip to content

Commit 75e635a

Browse files
iamfaranraheeliftikhar5
authored andcommitted
[Feat]: make chat component flexible
1 parent 4585d15 commit 75e635a

File tree

9 files changed

+437
-31
lines changed

9 files changed

+437
-31
lines changed

client/packages/lowcoder/src/comps/comps/chatComp/chatCompTypes.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,31 @@ import { AutoHeightControl } from "@lowcoder-ee/comps/controls/autoHeightControl
1111
const ModelTypeOptions = [
1212
{ label: "Direct LLM", value: "direct-llm" },
1313
{ label: "n8n Workflow", value: "n8n" },
14+
{ label: "Query", value: "query" },
1415
] as const;
1516

1617
export const chatChildrenMap = {
1718
text: withDefault(StringControl, "Chat Component Placeholder"),
1819
chatQuery: QuerySelectControl,
1920
currentMessage: stringExposingStateControl("currentMessage", ""),
20-
modelType: dropdownControl(ModelTypeOptions, "direct-llm"),
21+
modelType: dropdownControl(ModelTypeOptions, "query"),
2122
modelHost: withDefault(StringControl, ""),
2223
streaming: BoolControl.DEFAULT_TRUE,
2324
systemPrompt: withDefault(StringControl, "You are a helpful assistant."),
2425
agent: BoolControl,
2526
maxInteractions: withDefault(NumberControl, 10),
26-
autoHeight: AutoHeightControl,
27-
tableName: withDefault(StringControl, ""),
27+
tableName: withDefault(StringControl, "default"),
2828
};
2929

3030
export type ChatCompProps = {
3131
text: string;
3232
chatQuery: string;
3333
currentMessage: string;
3434
modelType: string;
35+
modelHost: string;
3536
streaming: boolean;
3637
systemPrompt: string;
3738
agent: boolean;
3839
maxInteractions: number;
40+
tableName: string;
3941
};
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// client/packages/lowcoder/src/comps/comps/chatComp/chatView.tsx
2-
import React from "react";
2+
import React, { useMemo } from "react";
33
import { ChatCompProps } from "./chatCompTypes";
44
import { CompAction } from "lowcoder-core";
55
import { ChatApp } from "./components/ChatApp";
6+
import { createChatStorage } from './utils/chatStorageFactory';
67

78
import "@assistant-ui/styles/index.css";
89
import "@assistant-ui/styles/markdown.css";
@@ -13,8 +14,33 @@ interface ChatViewProps extends ChatCompProps {
1314
}
1415

1516
export const ChatView = React.memo((props: ChatViewProps) => {
16-
const { chatQuery, currentMessage, dispatch } = props;
17-
return <ChatApp chatQuery={chatQuery} currentMessage={currentMessage} dispatch={dispatch} />;
17+
const {
18+
chatQuery,
19+
currentMessage,
20+
dispatch,
21+
modelType,
22+
modelHost,
23+
systemPrompt,
24+
streaming,
25+
tableName
26+
} = props;
27+
28+
// Create storage instance based on tableName
29+
const storage = useMemo(() => createChatStorage(tableName || "default"), [tableName]);
30+
31+
return (
32+
<ChatApp
33+
chatQuery={chatQuery}
34+
currentMessage={currentMessage}
35+
dispatch={dispatch}
36+
modelType={modelType}
37+
modelHost={modelHost}
38+
systemPrompt={systemPrompt}
39+
streaming={streaming}
40+
tableName={tableName}
41+
storage={storage}
42+
/>
43+
);
1844
});
1945

2046
ChatView.displayName = 'ChatView';
Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,43 @@
11
import { ChatProvider } from "./context/ChatContext";
22
import { ChatMain } from "./ChatMain";
33
import { CompAction } from "lowcoder-core";
4+
import { createChatStorage } from "../utils/chatStorageFactory";
45

56
interface ChatAppProps {
67
chatQuery: string;
78
currentMessage: string;
89
dispatch?: (action: CompAction<any>) => void;
10+
modelType: string;
11+
modelHost?: string;
12+
systemPrompt?: string;
13+
streaming?: boolean;
14+
tableName: string;
15+
storage: ReturnType<typeof createChatStorage>;
916
}
1017

11-
export function ChatApp({ chatQuery, currentMessage, dispatch }: ChatAppProps) {
18+
export function ChatApp({
19+
chatQuery,
20+
currentMessage,
21+
dispatch,
22+
modelType,
23+
modelHost,
24+
systemPrompt,
25+
streaming,
26+
tableName,
27+
storage
28+
}: ChatAppProps) {
1229
return (
13-
<ChatProvider>
14-
<ChatMain chatQuery={chatQuery} currentMessage={currentMessage} dispatch={dispatch} />
30+
<ChatProvider storage={storage}>
31+
<ChatMain
32+
chatQuery={chatQuery}
33+
currentMessage={currentMessage}
34+
dispatch={dispatch}
35+
modelType={modelType}
36+
modelHost={modelHost}
37+
systemPrompt={systemPrompt}
38+
streaming={streaming}
39+
tableName={tableName}
40+
/>
1541
</ChatProvider>
1642
);
17-
}
43+
}

client/packages/lowcoder/src/comps/comps/chatComp/components/ChatMain.tsx

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import {
1818
import styled from "styled-components";
1919
import { routeByNameAction, executeQueryAction, CompAction, changeChildAction } from "lowcoder-core";
2020
import { getPromiseAfterDispatch } from "util/promiseUtils";
21+
// ADD THIS IMPORT:
22+
import { createResponseHandler } from '../utils/responseFactory';
23+
import { useMemo } from 'react'; // if not already imported
2124

2225
const ChatContainer = styled.div<{ $autoHeight?: boolean }>`
2326
display: flex;
@@ -95,13 +98,28 @@ const callQuery = async (
9598
}
9699
};
97100

101+
// AFTER:
98102
interface ChatMainProps {
99103
chatQuery: string;
100104
currentMessage: string;
101105
dispatch?: (action: CompAction<any>) => void;
106+
// Add new props for response handling
107+
modelType: string;
108+
modelHost?: string;
109+
systemPrompt?: string;
110+
streaming?: boolean;
111+
tableName: string;
102112
}
103113

104-
export function ChatMain({ chatQuery, currentMessage, dispatch }: ChatMainProps) {
114+
export function ChatMain({
115+
chatQuery,
116+
currentMessage,
117+
dispatch,
118+
modelType,
119+
modelHost,
120+
systemPrompt,
121+
streaming,
122+
tableName }: ChatMainProps) {
105123
const { state, actions } = useChatContext();
106124
const [isRunning, setIsRunning] = useState(false);
107125
const editorState = useContext(EditorContext);
@@ -113,6 +131,21 @@ export function ChatMain({ chatQuery, currentMessage, dispatch }: ChatMainProps)
113131
editorStateRef.current = editorState;
114132
}, [editorState]);
115133

134+
// Create response handler based on model type
135+
const responseHandler = useMemo(() => {
136+
const responseType = modelType === "n8n" ? "direct-api" : "query";
137+
138+
return createResponseHandler(responseType, {
139+
// Query handler config
140+
chatQuery,
141+
dispatch,
142+
// Direct API handler config
143+
modelHost,
144+
systemPrompt,
145+
streaming
146+
});
147+
}, [modelType, chatQuery, dispatch, modelHost, systemPrompt, streaming]);
148+
116149
console.log("STATE", state);
117150

118151
// Get messages for current thread
@@ -205,7 +238,7 @@ export function ChatMain({ chatQuery, currentMessage, dispatch }: ChatMainProps)
205238

206239
try {
207240
// Call selected query / fallback to mock
208-
const response = await callQuery(chatQuery, userMessage.text, dispatch);
241+
const response = await responseHandler.sendMessage(userMessage.text);
209242

210243
const assistantMessage: MyMessage = {
211244
id: generateId(),
@@ -263,7 +296,7 @@ export function ChatMain({ chatQuery, currentMessage, dispatch }: ChatMainProps)
263296
setIsRunning(true);
264297

265298
try {
266-
const response = await callQuery(chatQuery, editedMessage.text, dispatch);
299+
const response = await responseHandler.sendMessage(editedMessage.text);
267300

268301
const assistantMessage: MyMessage = {
269302
id: generateId(),

client/packages/lowcoder/src/comps/comps/chatComp/components/context/ChatContext.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { createContext, useContext, useReducer, useEffect, ReactNode } from "react";
2-
import { chatStorage, ThreadData as StoredThreadData } from "../../utils/chatStorage";
3-
2+
import { ThreadData as StoredThreadData } from "../../utils/chatStorageFactory";
43
// Define thread-specific message type
54
export interface MyMessage {
65
id: string;
@@ -176,18 +175,19 @@ interface ChatContextType {
176175
const ChatContext = createContext<ChatContextType | null>(null);
177176

178177
// Chat provider component
179-
export function ChatProvider({ children }: { children: ReactNode }) {
178+
export function ChatProvider({ children, storage }: { children: ReactNode, storage: ReturnType<typeof import("../../utils/chatStorageFactory").createChatStorage>;
179+
}) {
180180
const [state, dispatch] = useReducer(chatReducer, initialState);
181181

182182
// Initialize data from storage
183183
const initialize = async () => {
184184
dispatch({ type: "INITIALIZE_START" });
185185

186186
try {
187-
await chatStorage.initialize();
187+
await storage.initialize();
188188

189189
// Load all threads from storage
190-
const storedThreads = await chatStorage.getAllThreads();
190+
const storedThreads = await storage.getAllThreads();
191191

192192
if (storedThreads.length > 0) {
193193
// Convert stored threads to UI format
@@ -200,7 +200,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
200200
// Load messages for each thread
201201
const threadMessages = new Map<string, MyMessage[]>();
202202
for (const thread of storedThreads) {
203-
const messages = await chatStorage.getMessages(thread.threadId);
203+
const messages = await storage.getMessages(thread.threadId);
204204
threadMessages.set(thread.threadId, messages);
205205
}
206206

@@ -228,7 +228,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
228228
createdAt: Date.now(),
229229
updatedAt: Date.now(),
230230
};
231-
await chatStorage.saveThread(defaultThread);
231+
await storage.saveThread(defaultThread);
232232

233233
dispatch({
234234
type: "INITIALIZE_SUCCESS",
@@ -268,7 +268,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
268268
createdAt: Date.now(),
269269
updatedAt: Date.now(),
270270
};
271-
await chatStorage.saveThread(storedThread);
271+
await storage.saveThread(storedThread);
272272
dispatch({ type: "MARK_SAVED" });
273273
} catch (error) {
274274
console.error("Failed to save new thread:", error);
@@ -283,14 +283,14 @@ export function ChatProvider({ children }: { children: ReactNode }) {
283283

284284
// Save to storage
285285
try {
286-
const existingThread = await chatStorage.getThread(threadId);
286+
const existingThread = await storage.getThread(threadId);
287287
if (existingThread) {
288288
const updatedThread: StoredThreadData = {
289289
...existingThread,
290290
...updates,
291291
updatedAt: Date.now(),
292292
};
293-
await chatStorage.saveThread(updatedThread);
293+
await storage.saveThread(updatedThread);
294294
dispatch({ type: "MARK_SAVED" });
295295
}
296296
} catch (error) {
@@ -304,7 +304,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
304304

305305
// Delete from storage
306306
try {
307-
await chatStorage.deleteThread(threadId);
307+
await storage.deleteThread(threadId);
308308
dispatch({ type: "MARK_SAVED" });
309309
} catch (error) {
310310
console.error("Failed to delete thread:", error);
@@ -318,7 +318,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
318318

319319
// Save to storage
320320
try {
321-
await chatStorage.saveMessage(message, threadId);
321+
await storage.saveMessage(message, threadId);
322322
dispatch({ type: "MARK_SAVED" });
323323
} catch (error) {
324324
console.error("Failed to save message:", error);
@@ -331,7 +331,7 @@ export function ChatProvider({ children }: { children: ReactNode }) {
331331

332332
// Save to storage
333333
try {
334-
await chatStorage.saveMessages(messages, threadId);
334+
await storage.saveMessages(messages, threadId);
335335
dispatch({ type: "MARK_SAVED" });
336336
} catch (error) {
337337
console.error("Failed to save messages:", error);

0 commit comments

Comments
 (0)