Skip to content

Commit aec9485

Browse files
committed
add query / new hook from assisstant ui
1 parent 11c98fd commit aec9485

File tree

4 files changed

+126
-21
lines changed

4 files changed

+126
-21
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ChatPropertyView } from "./chatPropertyView";
88
// Build the component
99
const ChatTmpComp = new UICompBuilder(
1010
chatChildrenMap,
11-
(props) => <ChatView {...props} />
11+
(props) => <ChatView {...props} chatQuery={props.chatQuery.value} />
1212
)
1313
.setPropertyViewFn((children) => <ChatPropertyView children={children} />)
1414
.build();

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { StringControl, NumberControl } from "comps/controls/codeControl";
33
import { withDefault } from "comps/generators";
44
import { BoolControl } from "comps/controls/boolControl";
55
import { dropdownControl } from "comps/controls/dropdownControl";
6+
import QuerySelectControl from "comps/controls/querySelectControl";
67

78
// Model type dropdown options
89
const ModelTypeOptions = [
@@ -12,7 +13,7 @@ const ModelTypeOptions = [
1213

1314
export const chatChildrenMap = {
1415
text: withDefault(StringControl, "Chat Component Placeholder"),
15-
modelHost: withDefault(StringControl, "http://localhost:11434"),
16+
chatQuery: QuerySelectControl,
1617
modelType: dropdownControl(ModelTypeOptions, "direct-llm"),
1718
streaming: BoolControl.DEFAULT_TRUE,
1819
systemPrompt: withDefault(StringControl, "You are a helpful assistant."),
@@ -22,8 +23,8 @@ export const chatChildrenMap = {
2223

2324
export type ChatCompProps = {
2425
text: string;
25-
modelHost: string;
26-
modelType: "direct-llm" | "n8n";
26+
chatQuery: string;
27+
modelType: string;
2728
streaming: boolean;
2829
systemPrompt: string;
2930
agent: boolean;

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ export const ChatPropertyView = React.memo((props: any) => {
88
return (
99
<Section name={sectionNames.basic}>
1010
{children.text.propertyView({ label: "Text" })}
11-
{children.modelHost.propertyView({ label: "Model Host URL" })}
11+
{children.chatQuery.propertyView({ label: "Chat Query" })}
1212
{children.modelType.propertyView({ label: "Model Type" })}
13-
{children.streaming.propertyView({ label: "Streaming Responses" })}
14-
{children.systemPrompt.propertyView({ label: "System Prompt" })}
15-
{children.agent.propertyView({ label: "Agent Mode" })}
16-
{children.maxInteractions.propertyView({ label: "Max Interactions" })}
13+
{children.streaming.propertyView({ label: "Enable Streaming" })}
14+
{children.systemPrompt.propertyView({
15+
label: "System Prompt",
16+
placeholder: "Enter system prompt...",
17+
enableSpellCheck: false,
18+
})}
19+
{children.agent.propertyView({ label: "Enable Agent Mode" })}
20+
{children.maxInteractions.propertyView({
21+
label: "Max Interactions",
22+
placeholder: "10",
23+
})}
1724
</Section>
1825
);
1926
});

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

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,123 @@
11
// client/packages/lowcoder/src/comps/comps/chatComp/chatView.tsx
2-
import React from "react";
2+
import React, { useState, useContext } from "react";
33
import { ChatCompProps } from "./chatCompTypes";
44
import { Thread } from "./components/assistant-ui/thread";
55

6-
// Import assistant-ui components and proper runtime
6+
// Import assistant-ui components for external store runtime
77
import {
88
AssistantRuntimeProvider,
9+
useExternalStoreRuntime,
10+
ThreadMessageLike,
11+
AppendMessage
912
} from "@assistant-ui/react";
10-
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
1113
import "@assistant-ui/styles/index.css";
1214
import "@assistant-ui/styles/markdown.css";
1315

16+
// Import Lowcoder query execution
17+
import { EditorContext } from "comps/editorState";
18+
import { executeQueryAction, routeByNameAction } from "lowcoder-core";
19+
20+
const convertMessage = (message: ThreadMessageLike) => {
21+
return message;
22+
};
23+
1424
export const ChatView = React.memo((props: ChatCompProps) => {
15-
// Create proper runtime using useChatRuntime
16-
const runtime = useChatRuntime({
17-
api: props.modelHost,
18-
stream: props.streaming,
19-
modelType: props.modelType as any,
20-
systemPrompt: props.systemPrompt,
21-
agent: props.agent,
22-
maxTurns: props.maxInteractions,
23-
} as any);
25+
const [messages, setMessages] = useState<readonly ThreadMessageLike[]>([]);
26+
const editorState = useContext(EditorContext);
27+
28+
const onNew = async (message: AppendMessage) => {
29+
if (message.content.length !== 1 || message.content[0]?.type !== "text") {
30+
throw new Error("Only text content is supported");
31+
}
32+
33+
// Add user message immediately
34+
const userMessage: ThreadMessageLike = {
35+
role: "user",
36+
content: [{ type: "text", text: message.content[0].text }],
37+
};
38+
setMessages((currentMessages) => [...currentMessages, userMessage]);
39+
40+
try {
41+
// Execute the selected Lowcoder query
42+
if (props.chatQuery) {
43+
// Prepare query arguments with chat context
44+
const queryArgs = {
45+
message: message.content[0].text,
46+
systemPrompt: props.systemPrompt,
47+
streaming: props.streaming,
48+
agent: props.agent,
49+
maxInteractions: props.maxInteractions,
50+
modelType: props.modelType,
51+
// Pass entire conversation history for context
52+
messages: messages.concat([userMessage]).map(msg => ({
53+
role: msg.role,
54+
content: Array.isArray(msg.content) && msg.content[0] && typeof msg.content[0] === "object" && "text" in msg.content[0]
55+
? msg.content[0].text
56+
: typeof msg.content === "string" ? msg.content : ""
57+
}))
58+
};
59+
60+
// Execute the query through Lowcoder's query system
61+
const result = await new Promise((resolve, reject) => {
62+
const queryComp = editorState?.getQueriesComp()
63+
.getView()
64+
.find(q => q.children.name.getView() === props.chatQuery);
65+
66+
if (!queryComp) {
67+
reject(new Error(`Query "${props.chatQuery}" not found`));
68+
return;
69+
}
70+
71+
queryComp.dispatch(
72+
executeQueryAction({
73+
args: queryArgs,
74+
afterExecFunc: () => {
75+
const queryResult = queryComp.children.data.getView();
76+
resolve(queryResult);
77+
}
78+
})
79+
);
80+
});
81+
82+
// Add assistant response
83+
const assistantMessage: ThreadMessageLike = {
84+
role: "assistant",
85+
content: [{
86+
type: "text",
87+
text: typeof result === "string"
88+
? result
89+
: (result as any)?.message || (result as any)?.response || "No response"
90+
}],
91+
};
92+
setMessages((currentMessages) => [...currentMessages, assistantMessage]);
93+
94+
} else {
95+
// Fallback response when no query is selected
96+
const assistantMessage: ThreadMessageLike = {
97+
role: "assistant",
98+
content: [{ type: "text", text: "Please select a chat query in the component properties." }],
99+
};
100+
setMessages((currentMessages) => [...currentMessages, assistantMessage]);
101+
}
102+
} catch (error) {
103+
// Error handling
104+
const errorMessage: ThreadMessageLike = {
105+
role: "assistant",
106+
content: [{
107+
type: "text",
108+
text: `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`
109+
}],
110+
};
111+
setMessages((currentMessages) => [...currentMessages, errorMessage]);
112+
}
113+
};
114+
115+
const runtime = useExternalStoreRuntime<ThreadMessageLike>({
116+
messages,
117+
setMessages,
118+
onNew,
119+
convertMessage,
120+
});
24121

25122
return (
26123
<AssistantRuntimeProvider runtime={runtime}>

0 commit comments

Comments
 (0)