Skip to content
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

fixes #153: Add user messages to chat window for quick actions #185

Open
wants to merge 1 commit into
base: staging
Choose a base branch
from
Open
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
13 changes: 8 additions & 5 deletions src/components/artifacts/ArtifactRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useGraphContext } from "@/contexts/GraphContext";
import { getArtifactContent } from "@/contexts/utils";
import { convertToOpenAIFormat } from "@/lib/convert_messages";
import { cn } from "@/lib/utils";
import {
Expand All @@ -7,19 +9,17 @@ import {
} from "@/types";
import { EditorView } from "@codemirror/view";
import { HumanMessage } from "@langchain/core/messages";
import { Forward, LoaderCircle, CircleCheck } from "lucide-react";
import { CircleCheck, Forward, LoaderCircle } from "lucide-react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { ReflectionsDialog } from "../reflections-dialog/ReflectionsDialog";
import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button";
import { ActionsToolbar, CodeToolBar } from "./actions_toolbar";
import { CodeRenderer } from "./CodeRenderer";
import { TextRenderer } from "./TextRenderer";
import { CustomQuickActions } from "./actions_toolbar/custom";
import { getArtifactContent } from "@/contexts/utils";
import { ArtifactLoading } from "./ArtifactLoading";
import { CodeRenderer } from "./CodeRenderer";
import { AskOpenCanvas } from "./components/AskOpenCanvas";
import { useGraphContext } from "@/contexts/GraphContext";
import { TextRenderer } from "./TextRenderer";

export interface ArtifactRendererProps {
isEditing: boolean;
Expand Down Expand Up @@ -412,19 +412,22 @@ function ArtifactRendererComponent(props: ArtifactRendererProps) {
)}
</div>
<CustomQuickActions
setMessages={setMessages}
streamMessage={streamMessage}
assistantId={assistantId}
user={user}
isTextSelected={isSelectionActive || selectedBlocks !== undefined}
/>
{currentArtifactContent.type === "text" ? (
<ActionsToolbar
setMessages={setMessages}
streamMessage={streamMessage}
isTextSelected={isSelectionActive || selectedBlocks !== undefined}
/>
) : null}
{currentArtifactContent.type === "code" ? (
<CodeToolBar
setMessages={setMessages}
streamMessage={streamMessage}
isTextSelected={isSelectionActive || selectedBlocks !== undefined}
language={
Expand Down
11 changes: 9 additions & 2 deletions src/components/artifacts/actions_toolbar/code/PortToLanguage.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { ProgrammingLanguageOptions } from "@/types";
import { useToast } from "@/hooks/use-toast";
import { ProgrammingLanguageList } from "@/components/ui/programming-lang-dropdown";
import { GraphInput } from "@/contexts/GraphContext";
import { useToast } from "@/hooks/use-toast";
import { ProgrammingLanguageOptions } from "@/types";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";

export interface PortToLanguageOptionsProps {
streamMessage: (params: GraphInput) => Promise<void>;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;

handleClose: () => void;
language: ProgrammingLanguageOptions;
}
Expand Down Expand Up @@ -48,6 +51,10 @@ export function PortToLanguageOptions(props: PortToLanguageOptionsProps) {
}

props.handleClose();
props.setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(`Port the code to ${prettifyLanguage(portLanguage)}`),
]);
await streamMessage({
portLanguage,
});
Expand Down
31 changes: 25 additions & 6 deletions src/components/artifacts/actions_toolbar/code/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useEffect, useRef, useState } from "react";
import { MessageCircleCode, Code, ScrollText, Bug, BookA } from "lucide-react";
import { cn } from "@/lib/utils";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { PortToLanguageOptions } from "./PortToLanguage";
import { ProgrammingLanguageOptions } from "@/types";
import { GraphInput } from "@/contexts/GraphContext";
import { cn } from "@/lib/utils";
import { ProgrammingLanguageOptions } from "@/types";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
import { BookA, Bug, Code, MessageCircleCode, ScrollText } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { PortToLanguageOptions } from "./PortToLanguage";

type SharedComponentProps = {
handleClose: () => void;
streamMessage: (params: GraphInput) => Promise<void>;
language: ProgrammingLanguageOptions;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
};

type ToolbarOption = {
Expand All @@ -23,6 +25,7 @@ export interface CodeToolbarProps {
streamMessage: (params: GraphInput) => Promise<void>;
isTextSelected: boolean;
language: ProgrammingLanguageOptions;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
}

const toolbarOptions: ToolbarOption[] = [
Expand Down Expand Up @@ -55,7 +58,7 @@ const toolbarOptions: ToolbarOption[] = [
];

export function CodeToolBar(props: CodeToolbarProps) {
const { streamMessage } = props;
const { streamMessage, setMessages } = props;
const [isExpanded, setIsExpanded] = useState(false);
const [activeOption, setActiveOption] = useState<string | null>(null);
const toolbarRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -97,6 +100,22 @@ export function CodeToolBar(props: CodeToolbarProps) {

setIsExpanded(false);
setActiveOption(null);

const actionMessages = {
addComments: "Add descriptive inline comments to my code",
addLogs: "Insert log statements into my code",
fixBugs: "Fix any potential bugs in my code",
};

if (actionMessages[optionId as keyof typeof actionMessages]) {
setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(
actionMessages[optionId as keyof typeof actionMessages]
),
]);
}

if (optionId === "addComments") {
await streamMessage({
addComments: true,
Expand Down
43 changes: 29 additions & 14 deletions src/components/artifacts/actions_toolbar/custom/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import {
CirclePlus,
WandSparkles,
Trash2,
LoaderCircle,
Pencil,
} from "lucide-react";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import {
DropdownMenu,
Expand All @@ -14,21 +7,30 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { CustomQuickAction } from "@/types";
import { NewCustomQuickActionDialog } from "./NewCustomQuickActionDialog";
import { useEffect, useState } from "react";
import { useStore } from "@/hooks/useStore";
import { cn } from "@/lib/utils";
import { useToast } from "@/hooks/use-toast";
import { TighterText } from "@/components/ui/header";
import { GraphInput } from "@/contexts/GraphContext";
import { useToast } from "@/hooks/use-toast";
import { useStore } from "@/hooks/useStore";
import { cn } from "@/lib/utils";
import { CustomQuickAction } from "@/types";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
import { User } from "@supabase/supabase-js";
import {
CirclePlus,
LoaderCircle,
Pencil,
Trash2,
WandSparkles,
} from "lucide-react";
import { useEffect, useState } from "react";
import { NewCustomQuickActionDialog } from "./NewCustomQuickActionDialog";

export interface CustomQuickActionsProps {
isTextSelected: boolean;
assistantId: string | undefined;
user: User | undefined;
streamMessage: (params: GraphInput) => Promise<void>;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
}

const DropdownMenuItemWithDelete = ({
Expand Down Expand Up @@ -82,7 +84,7 @@ const DropdownMenuItemWithDelete = ({
};

export function CustomQuickActions(props: CustomQuickActionsProps) {
const { user, assistantId, streamMessage } = props;
const { user, assistantId, streamMessage, setMessages } = props;
const {
getCustomQuickActions,
deleteCustomQuickAction,
Expand Down Expand Up @@ -121,6 +123,19 @@ export function CustomQuickActions(props: CustomQuickActionsProps) {
};

const handleQuickActionClick = async (id: string): Promise<void> => {
const selectedAction = customQuickActions?.find(
(action) => action.id === id
);

if (selectedAction) {
setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(
`Please use my custom quick action "${selectedAction.title}" to update my artifact`
),
]);
}

setOpen(false);
setIsEditing(false);
setIsEditingId(undefined);
Expand Down
20 changes: 16 additions & 4 deletions src/components/artifacts/actions_toolbar/text/LengthOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { cn } from "@/lib/utils";
import { useState } from "react";
import { ArtifactLengthOptions } from "@/types";
import { Slider } from "@/components/ui/slider";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Slider } from "@/components/ui/slider";
import { GraphInput } from "@/contexts/GraphContext";
import { cn } from "@/lib/utils";
import { ArtifactLengthOptions } from "@/types";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
import { useState } from "react";

export interface LengthOptionsProps {
streamMessage: (params: GraphInput) => Promise<void>;
handleClose: () => void;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
}

const lengthOptions = [
Expand All @@ -30,6 +32,16 @@ export function LengthOptions(props: LengthOptionsProps) {

const handleSubmit = async (artifactLength: ArtifactLengthOptions) => {
props.handleClose();
const lengthMap = {
shortest: "much shorter",
short: "shorter",
long: "longer",
longest: "much longer",
};
props.setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(`Update my artifact to be ${lengthMap[artifactLength]}`),
]);
await streamMessage({
artifactLength,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { GraphInput } from "@/contexts/GraphContext";
import { ReadingLevelOptions as ReadingLevelOptionsType } from "@/types";
import { HumanMessage } from "@langchain/core/messages";
import {
Baby,
GraduationCap,
PersonStanding,
School,
Swords,
} from "lucide-react";
import { ReadingLevelOptions as ReadingLevelOptionsType } from "@/types";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { GraphInput } from "@/contexts/GraphContext";

export interface ReadingLevelOptionsProps {
streamMessage: (params: GraphInput) => Promise<void>;
handleClose: () => void;
setMessages: React.Dispatch<React.SetStateAction<HumanMessage[]>>;
}

export function ReadingLevelOptions(props: ReadingLevelOptionsProps) {
const { streamMessage } = props;

const handleSubmit = async (readingLevel: ReadingLevelOptionsType) => {
props.handleClose();
const levelMap = {
phd: "PhD level",
college: "college level",
teenager: "teenager level",
child: "child level",
pirate: "pirate speak",
};
props.setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(
`Rewrite my artifact to be at a ${levelMap[readingLevel]}`
),
]);
await streamMessage({
readingLevel,
});
Expand Down
17 changes: 15 additions & 2 deletions src/components/artifacts/actions_toolbar/text/TranslateOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import {
UsaFlag,
ChinaFlag,
FrenchFlag,
IndiaFlag,
SpanishFlag,
FrenchFlag,
UsaFlag,
} from "@/components/icons/flags";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { GraphInput } from "@/contexts/GraphContext";
import { LanguageOptions } from "@/types";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";

export interface TranslateOptionsProps {
streamMessage: (params: GraphInput) => Promise<void>;
handleClose: () => void;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
}

export function TranslateOptions(props: TranslateOptionsProps) {
const { streamMessage } = props;

const handleSubmit = async (language: LanguageOptions) => {
props.handleClose();
const languageMap = {
english: "English",
mandarin: "Mandarin",
hindi: "Hindi",
spanish: "Spanish",
french: "French",
};
props.setMessages((prevMessages) => [
...prevMessages,
new HumanMessage(`Translate my artifact to ${languageMap[language]}`),
]);
await streamMessage({
language,
});
Expand Down
21 changes: 14 additions & 7 deletions src/components/artifacts/actions_toolbar/text/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { useEffect, useRef, useState } from "react";
import { Languages, BookOpen, SlidersVertical, SmilePlus } from "lucide-react";
import { MagicPencilSVG } from "@/components/icons/magic_pencil";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { GraphInput } from "@/contexts/GraphContext";
import { cn } from "@/lib/utils";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
import { BookOpen, Languages, SlidersVertical, SmilePlus } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { LengthOptions } from "./LengthOptions";
import { ReadingLevelOptions } from "./ReadingLevelOptions";
import { TranslateOptions } from "./TranslateOptions";
import { LengthOptions } from "./LengthOptions";
import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button";
import { MagicPencilSVG } from "@/components/icons/magic_pencil";
import { GraphInput } from "@/contexts/GraphContext";

type SharedComponentProps = {
streamMessage: (params: GraphInput) => Promise<void>;
handleClose: () => void;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
};

type ToolbarOption = {
Expand All @@ -22,6 +24,7 @@ type ToolbarOption = {

export interface ActionsToolbarProps {
streamMessage: (params: GraphInput) => Promise<void>;
setMessages: React.Dispatch<React.SetStateAction<BaseMessage[]>>;
isTextSelected: boolean;
}

Expand Down Expand Up @@ -55,7 +58,7 @@ const toolbarOptions: ToolbarOption[] = [
];

export function ActionsToolbar(props: ActionsToolbarProps) {
const { streamMessage } = props;
const { streamMessage, setMessages } = props;
const [isExpanded, setIsExpanded] = useState(false);
const [activeOption, setActiveOption] = useState<string | null>(null);
const toolbarRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -90,6 +93,10 @@ export function ActionsToolbar(props: ActionsToolbarProps) {
) => {
event.stopPropagation();
if (optionId === "addEmojis") {
setMessages((prevMessages) => [
...prevMessages,
new HumanMessage("Add emojis to my artifact"),
]);
setIsExpanded(false);
setActiveOption(null);
await streamMessage({
Expand Down