Skip to content

Commit 35aa517

Browse files
iamfaranraheeliftikhar5
authored andcommitted
add system prompt and improve edit UI
1 parent 8045905 commit 35aa517

File tree

5 files changed

+113
-49
lines changed

5 files changed

+113
-49
lines changed

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

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { createChatStorage } from "./utils/storageFactory";
1515
import { QueryHandler, createMessageHandler } from "./handlers/messageHandlers";
1616
import { useMemo, useRef, useEffect } from "react";
1717
import { changeChildAction } from "lowcoder-core";
18+
import { ChatMessage } from "./types/chatTypes";
1819

1920
import "@assistant-ui/styles/index.css";
2021
import "@assistant-ui/styles/markdown.css";
@@ -74,6 +75,30 @@ export const ChatEventHandlerControl = eventHandlerControl(ChatEventOptions);
7475
// SIMPLIFIED CHILDREN MAP - WITH EVENT HANDLERS
7576
// ============================================================================
7677

78+
79+
export function addSystemPromptToHistory(
80+
conversationHistory: ChatMessage[],
81+
systemPrompt: string
82+
): Array<{ role: string; content: string; timestamp: number }> {
83+
// Format conversation history for use in queries
84+
const formattedHistory = conversationHistory.map(msg => ({
85+
role: msg.role,
86+
content: msg.text,
87+
timestamp: msg.timestamp
88+
}));
89+
90+
// Create system message (always exists since we have default)
91+
const systemMessage = [{
92+
role: "system" as const,
93+
content: systemPrompt,
94+
timestamp: Date.now() - 1000000 // Ensure it's always first chronologically
95+
}];
96+
97+
// Return complete history with system prompt prepended
98+
return [...systemMessage, ...formattedHistory];
99+
}
100+
101+
77102
function generateUniqueTableName(): string {
78103
return `chat${Math.floor(1000 + Math.random() * 9000)}`;
79104
}
@@ -117,7 +142,6 @@ const ChatTmpComp = new UICompBuilder(
117142
(props, dispatch) => {
118143

119144
const uniqueTableName = useRef<string>();
120-
121145
// Generate unique table name once (with persistence)
122146
if (!uniqueTableName.current) {
123147
// Use persisted name if exists, otherwise generate new one
@@ -146,7 +170,7 @@ const ChatTmpComp = new UICompBuilder(
146170
return new QueryHandler({
147171
chatQuery: props.chatQuery.value,
148172
dispatch,
149-
streaming: props.streaming
173+
streaming: props.streaming,
150174
});
151175
} else if (handlerType === "n8n") {
152176
return createMessageHandler("n8n", {
@@ -168,7 +192,7 @@ const ChatTmpComp = new UICompBuilder(
168192
props.modelHost,
169193
props.systemPrompt,
170194
props.streaming,
171-
dispatch
195+
dispatch,
172196
]);
173197

174198
// Handle message updates for exposed variable
@@ -179,21 +203,23 @@ const ChatTmpComp = new UICompBuilder(
179203
};
180204

181205
// Handle conversation history updates for exposed variable
182-
const handleConversationUpdate = (conversationHistory: any[]) => {
183-
// Format conversation history for use in queries
184-
const formattedHistory = conversationHistory.map(msg => ({
185-
role: msg.role,
186-
content: msg.text,
187-
timestamp: msg.timestamp
188-
}));
189-
dispatch(changeChildAction("conversationHistory", JSON.stringify(formattedHistory), false));
190-
191-
// Trigger messageReceived event when bot responds
192-
const lastMessage = conversationHistory[conversationHistory.length - 1];
193-
if (lastMessage && lastMessage.role === 'assistant') {
194-
props.onEvent("messageReceived");
195-
}
196-
};
206+
// Handle conversation history updates for exposed variable
207+
const handleConversationUpdate = (conversationHistory: any[]) => {
208+
// Use utility function to create complete history with system prompt
209+
const historyWithSystemPrompt = addSystemPromptToHistory(
210+
conversationHistory,
211+
props.systemPrompt
212+
);
213+
214+
// Expose the complete history (with system prompt) for use in queries
215+
dispatch(changeChildAction("conversationHistory", JSON.stringify(historyWithSystemPrompt), false));
216+
217+
// Trigger messageReceived event when bot responds
218+
const lastMessage = conversationHistory[conversationHistory.length - 1];
219+
if (lastMessage && lastMessage.role === 'assistant') {
220+
props.onEvent("messageReceived");
221+
}
222+
};
197223

198224
// Cleanup on unmount
199225
useEffect(() => {
@@ -226,5 +252,5 @@ const ChatTmpComp = new UICompBuilder(
226252

227253
export const ChatComp = withExposingConfigs(ChatTmpComp, [
228254
new NameConfig("currentMessage", "Current user message"),
229-
new NameConfig("conversationHistory", "Full conversation history as JSON array"),
255+
new NameConfig("conversationHistory", "Full conversation history as JSON array (includes system prompt for API calls)"),
230256
]);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export function ChatCoreMain({
127127
setIsRunning(true);
128128

129129
try {
130+
130131
// Use the message handler (no more complex logic here!)
131132
const response = await messageHandler.sendMessage(userMessage.text);
132133

client/packages/lowcoder/src/comps/comps/chatComp/components/assistant-ui/thread-list.tsx

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import type { FC } from "react";
2+
import { useState } from "react";
23
import {
34
ThreadListItemPrimitive,
45
ThreadListPrimitive,
6+
useThreadListItem,
57
} from "@assistant-ui/react";
68
import { PencilIcon, PlusIcon, Trash2Icon } from "lucide-react";
7-
89
import { TooltipIconButton } from "./tooltip-icon-button";
910
import { useThreadListItemRuntime } from "@assistant-ui/react";
10-
import { Button, Flex } from "antd";
11+
import { Button, Flex, Input } from "antd";
1112

1213
import styled from "styled-components";
13-
import { useChatContext } from "../context/ChatContext";
1414

1515
const StyledPrimaryButton = styled(Button)`
1616
// padding: 20px;
@@ -44,12 +44,23 @@ const ThreadListItems: FC = () => {
4444
};
4545

4646
const ThreadListItem: FC = () => {
47+
const [editing, setEditing] = useState(false);
48+
4749
return (
4850
<ThreadListItemPrimitive.Root className="aui-thread-list-item">
4951
<ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger">
50-
<ThreadListItemTitle />
52+
{editing ? (
53+
<ThreadListItemEditInput
54+
onFinish={() => setEditing(false)}
55+
/>
56+
) : (
57+
<ThreadListItemTitle />
58+
)}
5159
</ThreadListItemPrimitive.Trigger>
52-
<ThreadListItemRename />
60+
<ThreadListItemRename
61+
onStartEdit={() => setEditing(true)}
62+
editing={editing}
63+
/>
5364
<ThreadListItemDelete />
5465
</ThreadListItemPrimitive.Root>
5566
);
@@ -78,37 +89,57 @@ const ThreadListItemDelete: FC = () => {
7889
};
7990

8091

81-
const ThreadListItemRename: FC = () => {
82-
const runtime = useThreadListItemRuntime();
92+
93+
const ThreadListItemEditInput: FC<{ onFinish: () => void }> = ({ onFinish }) => {
94+
const threadItem = useThreadListItem();
95+
const threadRuntime = useThreadListItemRuntime();
8396

84-
const handleClick = async () => {
85-
// runtime doesn't expose a direct `title` prop; read it from its state
86-
let current = "";
87-
try {
88-
// getState is part of the public runtime surface
89-
current = (runtime.getState?.() as any)?.title ?? "";
90-
} catch {
91-
// fallback – generate a title if the runtime provides a helper
92-
if (typeof (runtime as any).generateTitle === "function") {
93-
// generateTitle(threadId) in older builds, generateTitle() in newer ones
94-
current = (runtime as any).generateTitle((runtime as any).threadId ?? undefined);
95-
}
97+
const currentTitle = threadItem?.title || "New Chat";
98+
99+
const handleRename = async (newTitle: string) => {
100+
if (!newTitle.trim() || newTitle === currentTitle){
101+
onFinish();
102+
return;
96103
}
97-
98-
const next = prompt("Rename thread", current)?.trim();
99-
if (next && next !== current) {
100-
await runtime.rename(next);
104+
105+
try {
106+
await threadRuntime.rename(newTitle);
107+
onFinish();
108+
} catch (error) {
109+
console.error("Failed to rename thread:", error);
101110
}
102111
};
103112

113+
return (
114+
<Input
115+
size="small"
116+
defaultValue={currentTitle}
117+
onBlur={(e) => handleRename(e.target.value)}
118+
onPressEnter={(e) => handleRename((e.target as HTMLInputElement).value)}
119+
onKeyDown={(e) => {
120+
if (e.key === 'Escape') onFinish();
121+
}}
122+
autoFocus
123+
style={{ fontSize: '14px', padding: '2px 8px' }}
124+
/>
125+
);
126+
};
127+
128+
129+
const ThreadListItemRename: FC<{ onStartEdit: () => void; editing: boolean }> = ({
130+
onStartEdit,
131+
editing
132+
}) => {
133+
if (editing) return null;
134+
104135
return (
105136
<TooltipIconButton
106-
tooltip="Rename thread"
107137
variant="ghost"
108-
onClick={handleClick}
109-
className="aui-thread-list-item-rename"
138+
tooltip="Rename thread"
139+
onClick={onStartEdit}
110140
>
111141
<PencilIcon />
112142
</TooltipIconButton>
113143
);
114-
};
144+
};
145+

client/packages/lowcoder/src/comps/comps/chatComp/handlers/messageHandlers.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class QueryHandler implements MessageHandler {
5555
constructor(private config: QueryHandlerConfig) {}
5656

5757
async sendMessage(message: string): Promise<MessageResponse> {
58-
const { chatQuery, dispatch } = this.config;
58+
const { chatQuery, dispatch} = this.config;
5959

6060
// If no query selected or dispatch unavailable, return mock response
6161
if (!chatQuery || !dispatch) {
@@ -64,17 +64,22 @@ export class QueryHandler implements MessageHandler {
6464
}
6565

6666
try {
67+
6768
const result: any = await getPromiseAfterDispatch(
6869
dispatch,
6970
routeByNameAction(
7071
chatQuery,
7172
executeQueryAction({
72-
// Send the user prompt as variable named 'prompt' by default
73-
args: { prompt: { value: message } },
73+
// Send both individual prompt and full conversation history
74+
args: {
75+
prompt: { value: message },
76+
},
7477
})
7578
)
7679
);
7780

81+
console.log("QUERY RESULT", result);
82+
7883
return result.message
7984
} catch (e: any) {
8085
throw new Error(e?.message || "Query execution failed");

client/packages/lowcoder/src/comps/comps/chatComp/types/chatTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export interface ChatMessage {
6666
chatQuery: string;
6767
dispatch: any;
6868
streaming?: boolean;
69+
systemPrompt?: string;
6970
}
7071

7172
// ============================================================================

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy