Skip to content

[Nebula] Fix context filters not prepopulated when viewing chat from history #5710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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
15 changes: 9 additions & 6 deletions apps/dashboard/src/app/nebula-app/(app)/api/session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { NEXT_PUBLIC_NEBULA_URL } from "@/constants/env";
import { fetchWithAuthToken } from "../../../../utils/fetchWithAuthToken";
import type { ContextFilters } from "./chat";
import type { ExecuteConfig, SessionInfo, TruncatedSessionInfo } from "./types";
import type {
DeletedSessionInfo,
ExecuteConfig,
SessionInfo,
TruncatedSessionInfo,
UpdatedSessionInfo,
} from "./types";

// TODO - get the spec for return types on /session POST and PUT

Expand Down Expand Up @@ -71,7 +77,7 @@ export async function updateSession(params: {
}
const data = await res.json();

return data.result as SessionInfo;
return data.result as UpdatedSessionInfo;
}

export async function deleteSession(params: {
Expand All @@ -89,10 +95,7 @@ export async function deleteSession(params: {
}
const data = await res.json();

return data.result as {
id: string;
deleted_at: string;
};
return data.result as DeletedSessionInfo;
}

export async function getSessions(params: {
Expand Down
20 changes: 20 additions & 0 deletions apps/dashboard/src/app/nebula-app/(app)/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,30 @@ export type SessionInfo = {
archived_at: string | null;
title: string | null;
is_public: boolean | null;
context_filter: {
chain_ids: string[];
contract_addresses: string[];
} | null;
// memory
// action: array<object> | null; <-- type of this is not available on https://nebula-api.thirdweb-dev.com/docs#/default/get_session_session__session_id__get
};

export type UpdatedSessionInfo = {
title: string;
modal_name: string;
account_id: string;
execute_config: ExecuteConfig | null;
context_filter: {
chain_ids: string[];
contract_addresses: string[];
} | null;
};

export type DeletedSessionInfo = {
id: string;
deleted_at: string;
};

export type TruncatedSessionInfo = {
created_at: string;
id: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ export function ChatPageContent(props: {
const [_config, setConfig] = useState<ExecuteConfig | null>();
const [contextFilters, setContextFilters] = useState<
ContextFilters | undefined
>(undefined);
>(() => {
const contextFilterRes = props.session?.context_filter;
if (contextFilterRes) {
return {
chainIds: contextFilterRes.chain_ids,
contractAddresses: contextFilterRes.contract_addresses,
};
}
});

const config = _config || {
mode: "client",
Expand Down Expand Up @@ -254,16 +262,12 @@ export function ChatPageContent(props: {
// If no session exists, create a new one
await initSession();
} else {
const newSession = await updateSession({
await updateSession({
authToken: props.authToken,
config: newConfig,
sessionId,
contextFilters,
});

if (newSession) {
setSessionId(newSession.id);
}
}
} catch (error) {
console.error("Failed to update session", error);
Expand Down Expand Up @@ -292,16 +296,12 @@ export function ChatPageContent(props: {
updateContextFilters={async (values) => {
// if session is not yet created, don't need to update sessions - starting a chat will create a session with the context filters
if (sessionId) {
const newSession = await updateSession({
await updateSession({
authToken: props.authToken,
config,
sessionId,
contextFilters: values,
});
// setting new id - but it doesn't actually change if the session was already created ( which is the case here )
if (newSession) {
setSessionId(newSession.id);
}
}
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,24 @@ export default function ContextFiltersButton(props: {
: "Set context filters"}
</Button>
</DialogTrigger>
<ContextFilterDialogContent
contextFilters={props.contextFilters}
isPending={updateMutation.isPending}
updateFilters={async (data) => {
const promise = updateMutation.mutateAsync(data);
toast.promise(promise, {
success: "Context filters updated",
error: "Failed to update context filters",
});
<DialogContent className="p-0">
<ContextFilterDialogContent
contextFilters={props.contextFilters}
isPending={updateMutation.isPending}
updateFilters={async (data) => {
const promise = updateMutation.mutateAsync(data);
toast.promise(promise, {
success: "Context filters updated",
error: "Failed to update context filters",
});

promise.then(() => {
props.setContextFilters(data);
setIsOpen(false);
});
}}
/>
promise.then(() => {
props.setContextFilters(data);
setIsOpen(false);
});
}}
/>
</DialogContent>
</Dialog>
);
}
Expand Down Expand Up @@ -137,76 +139,74 @@ function ContextFilterDialogContent(props: {
}

return (
<DialogContent className="p-0">
<Form {...form}>
<DialogHeader className="px-6 pt-6 pb-1">
<DialogTitle className="font-semibold text-xl">
Context Filters
</DialogTitle>
<DialogDescription className="text-muted-foreground">
Provide context information to Nebula for your prompts
</DialogDescription>
</DialogHeader>
<Form {...form}>
<DialogHeader className="px-6 pt-6 pb-1">
<DialogTitle className="font-semibold text-xl">
Context Filters
</DialogTitle>
<DialogDescription className="text-muted-foreground">
Provide context information to Nebula for your prompts
</DialogDescription>
</DialogHeader>

<form onSubmit={form.handleSubmit(onSubmit)}>
<div className="flex flex-col gap-5 px-6">
<FormField
control={form.control}
name="chainIds"
render={() => (
<FormItem>
<FormLabel>Chain IDs</FormLabel>
<FormControl>
<MultiNetworkSelector
selectedChainIds={form
.watch()
.chainIds.split(",")
.filter(Boolean)
.map(Number)}
onChange={(values) => {
console.log("values", values);
form.setValue("chainIds", values.join(","));
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<form onSubmit={form.handleSubmit(onSubmit)}>
<div className="flex flex-col gap-5 px-6">
<FormField
control={form.control}
name="chainIds"
render={() => (
<FormItem>
<FormLabel>Chain IDs</FormLabel>
<FormControl>
<MultiNetworkSelector
selectedChainIds={form
.watch()
.chainIds.split(",")
.filter(Boolean)
.map(Number)}
onChange={(values) => {
console.log("values", values);
form.setValue("chainIds", values.join(","));
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name="contractAddresses"
render={({ field }) => (
<FormItem>
<FormLabel>Contract Addresses</FormLabel>
<FormControl>
<AutoResizeTextarea
{...field}
placeholder="0x123..., 0x456..."
className="min-h-[32px] resize-none"
/>
</FormControl>
<FormDescription>
Comma separated list of contract addresses
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="contractAddresses"
render={({ field }) => (
<FormItem>
<FormLabel>Contract Addresses</FormLabel>
<FormControl>
<AutoResizeTextarea
{...field}
placeholder="0x123..., 0x456..."
className="min-h-[32px] resize-none"
/>
</FormControl>
<FormDescription>
Comma separated list of contract addresses
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>

<div className="mt-10 flex justify-end gap-3 border-t bg-muted/50 p-6">
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button className="min-w-28 gap-2" type="submit">
{props.isPending && <Spinner className="size-4" />}
Update
</Button>
</div>
</form>
</Form>
</DialogContent>
<div className="mt-10 flex justify-end gap-3 border-t bg-muted/50 p-6">
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button className="min-w-28 gap-2" type="submit">
{props.isPending && <Spinner className="size-4" />}
Update
</Button>
</div>
</form>
</Form>
);
}
Loading