Skip to content

Commit b0ce410

Browse files
committed
[NEB-241] Dashboard: /chat endpoint schema update related changes
1 parent 1e924e0 commit b0ce410

File tree

10 files changed

+237
-73
lines changed

10 files changed

+237
-73
lines changed

apps/dashboard/src/app/nebula-app/(app)/api/chat.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NEXT_PUBLIC_NEBULA_URL } from "@/constants/env";
22
// TODO - copy the source of this library to dashboard
33
import { stream } from "fetch-event-stream";
44
import type { NebulaTxData } from "../components/Chats";
5+
import type { NebulaUserMessage } from "./types";
56

67
export type NebulaContext = {
78
chainIds: string[] | null;
@@ -42,15 +43,15 @@ export type NebulaSwapData = {
4243
};
4344

4445
export async function promptNebula(params: {
45-
message: string;
46+
message: NebulaUserMessage;
4647
sessionId: string;
4748
authToken: string;
4849
handleStream: (res: ChatStreamedResponse) => void;
4950
abortController: AbortController;
5051
context: undefined | NebulaContext;
5152
}) {
5253
const body: Record<string, string | boolean | object> = {
53-
message: params.message,
54+
messages: [params.message],
5455
stream: true,
5556
session_id: params.sessionId,
5657
};

apps/dashboard/src/app/nebula-app/(app)/api/types.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,36 @@ type SessionContextFilter = {
33
wallet_address: string | null;
44
};
55

6-
export type NebulaSessionHistoryMessage = {
7-
role: "user" | "assistant" | "action" | "image";
8-
content: string;
9-
timestamp: number;
6+
type NebulaUserMessageContentItem =
7+
| {
8+
type: "image";
9+
image_url: string;
10+
}
11+
| {
12+
type: "text";
13+
text: string;
14+
}
15+
| {
16+
type: "transaction";
17+
transaction_hash: string;
18+
chain_id: number;
19+
};
20+
21+
export type NebulaUserMessageContent = NebulaUserMessageContentItem[];
22+
23+
export type NebulaUserMessage = {
24+
role: "user";
25+
content: NebulaUserMessageContent;
1026
};
1127

28+
export type NebulaSessionHistoryMessage =
29+
| {
30+
role: "assistant" | "action" | "image";
31+
content: string;
32+
timestamp: number;
33+
}
34+
| NebulaUserMessage;
35+
1236
export type SessionInfo = {
1337
id: string;
1438
account_id: string;

apps/dashboard/src/app/nebula-app/(app)/components/ChatBar.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ import {
3434
import { shortenAddress } from "thirdweb/utils";
3535
import type { Wallet } from "thirdweb/wallets";
3636
import type { NebulaContext } from "../api/chat";
37+
import type { NebulaUserMessage } from "../api/types";
3738

3839
export type WalletMeta = {
3940
walletId: Wallet["id"];
4041
address: string;
4142
};
4243

4344
export function ChatBar(props: {
44-
sendMessage: (message: string) => void;
45+
sendMessage: (message: NebulaUserMessage) => void;
4546
isChatStreaming: boolean;
4647
abortChatStream: () => void;
4748
prefillMessage: string | undefined;
@@ -53,11 +54,22 @@ export function ChatBar(props: {
5354
connectedWallets: WalletMeta[];
5455
setActiveWallet: (wallet: WalletMeta) => void;
5556
isConnectingWallet: boolean;
57+
// TODO - add this option later
58+
// showImageUploader: boolean;
5659
}) {
5760
const [message, setMessage] = useState(props.prefillMessage || "");
5861
const selectedChainIds = props.context?.chainIds?.map((x) => Number(x)) || [];
5962
const firstChainId = selectedChainIds[0];
6063

64+
function handleSubmit(message: string) {
65+
setMessage("");
66+
props.sendMessage({
67+
role: "user",
68+
// TODO - add image here later
69+
content: [{ type: "text", text: message }],
70+
});
71+
}
72+
6173
return (
6274
<div
6375
className={cn(
@@ -77,8 +89,7 @@ export function ChatBar(props: {
7789
}
7890
if (e.key === "Enter" && !props.isChatStreaming) {
7991
e.preventDefault();
80-
setMessage("");
81-
props.sendMessage(message);
92+
handleSubmit(message);
8293
}
8394
}}
8495
className="min-h-[60px] resize-none border-none bg-transparent pt-2 leading-relaxed focus-visible:ring-0 focus-visible:ring-offset-0"
@@ -194,8 +205,7 @@ export function ChatBar(props: {
194205
variant="pink"
195206
onClick={() => {
196207
if (message.trim() === "") return;
197-
setMessage("");
198-
props.sendMessage(message);
208+
handleSubmit(message);
199209
}}
200210
>
201211
<ArrowUpIcon className="size-4" />

apps/dashboard/src/app/nebula-app/(app)/components/ChatPageContent.tsx

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import {
2020
} from "thirdweb/react";
2121
import { type NebulaContext, promptNebula } from "../api/chat";
2222
import { createSession, updateSession } from "../api/session";
23-
import type { NebulaSessionHistoryMessage, SessionInfo } from "../api/types";
23+
import type {
24+
NebulaSessionHistoryMessage,
25+
NebulaUserMessage,
26+
SessionInfo,
27+
} from "../api/types";
2428
import { examplePrompts } from "../data/examplePrompts";
2529
import { newSessionsStore } from "../stores";
2630
import { ChatBar, type WalletMeta } from "./ChatBar";
@@ -135,20 +139,25 @@ export function ChatPageContent(props: {
135139
}, [contextFilters, props.authToken]);
136140

137141
const handleSendMessage = useCallback(
138-
async (message: string) => {
142+
async (message: NebulaUserMessage) => {
139143
setUserHasSubmittedMessage(true);
140144
setMessages((prev) => [
141145
...prev,
142-
{ text: message, type: "user" },
143-
// instant loading indicator feedback to user
146+
{
147+
type: "user",
148+
content: message.content,
149+
},
144150
{
145151
type: "presence",
146152
texts: [],
147153
},
148154
]);
149155

150156
// handle hardcoded replies first
151-
const lowerCaseMessage = message.toLowerCase();
157+
const lowerCaseMessage = message.content
158+
.find((x) => x.type === "text")
159+
?.text.toLowerCase();
160+
152161
const interceptedReply = examplePrompts.find(
153162
(prompt) => prompt.message.toLowerCase() === lowerCaseMessage,
154163
)?.interceptedReply;
@@ -175,13 +184,18 @@ export function ChatPageContent(props: {
175184
currentSessionId = session.id;
176185
}
177186

187+
const firstTextMessage =
188+
message.role === "user"
189+
? message.content.find((x) => x.type === "text")?.text || ""
190+
: "";
191+
178192
// add this session on sidebar
179-
if (messages.length === 0) {
193+
if (messages.length === 0 && firstTextMessage) {
180194
const prevValue = newSessionsStore.getValue();
181195
newSessionsStore.setValue([
182196
{
183197
id: currentSessionId,
184-
title: message,
198+
title: firstTextMessage,
185199
created_at: new Date().toISOString(),
186200
updated_at: new Date().toISOString(),
187201
},
@@ -193,7 +207,7 @@ export function ChatPageContent(props: {
193207

194208
await handleNebulaPrompt({
195209
abortController,
196-
message,
210+
message: message,
197211
sessionId: currentSessionId,
198212
authToken: props.authToken,
199213
setMessages,
@@ -234,7 +248,15 @@ export function ChatPageContent(props: {
234248
!hasDoneAutoPrompt.current
235249
) {
236250
hasDoneAutoPrompt.current = true;
237-
handleSendMessage(props.initialParams.q);
251+
handleSendMessage({
252+
role: "user",
253+
content: [
254+
{
255+
type: "text",
256+
text: props.initialParams.q,
257+
},
258+
],
259+
});
238260
}
239261
}, [props.initialParams?.q, messages.length, handleSendMessage]);
240262

@@ -402,7 +424,7 @@ function getLastUsedChainIds(): string[] | null {
402424

403425
export async function handleNebulaPrompt(params: {
404426
abortController: AbortController;
405-
message: string;
427+
message: NebulaUserMessage;
406428
sessionId: string;
407429
authToken: string;
408430
setMessages: React.Dispatch<React.SetStateAction<ChatMessage[]>>;
@@ -654,7 +676,7 @@ function parseHistoryToMessages(history: NebulaSessionHistoryMessage[]) {
654676

655677
case "user": {
656678
messages.push({
657-
text: message.content,
679+
content: message.content,
658680
type: message.role,
659681
});
660682
break;

apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ export const UserPresenceError: Story = {
3333
args: {
3434
messages: [
3535
{
36-
text: randomLorem(10),
36+
content: [
37+
{
38+
type: "text",
39+
text: randomLorem(10),
40+
},
41+
],
3742
type: "user",
3843
},
3944
{
@@ -205,8 +210,13 @@ export const Markdown: Story = {
205210
request_id: undefined,
206211
},
207212
{
208-
text: responseWithCodeMarkdown,
209213
type: "user",
214+
content: [
215+
{
216+
type: "text",
217+
text: responseWithCodeMarkdown,
218+
},
219+
],
210220
},
211221
],
212222
},

0 commit comments

Comments
 (0)