From e1b358b104ab56da7105092f00c1d56718f65cb1 Mon Sep 17 00:00:00 2001 From: Muhammad Ahmad Date: Mon, 4 Nov 2024 09:03:11 +0500 Subject: [PATCH 1/6] feat: add model temperature and max tokens config (#149) --- package.json | 3 + src/agent/open-canvas/nodes/customAction.ts | 6 +- .../open-canvas/nodes/generateArtifact.ts | 16 +- .../open-canvas/nodes/replyToGeneralInput.ts | 6 +- .../open-canvas/nodes/rewriteArtifact.ts | 42 +-- .../open-canvas/nodes/rewriteArtifactTheme.ts | 6 +- .../nodes/rewriteCodeArtifactTheme.ts | 6 +- src/agent/open-canvas/nodes/updateArtifact.ts | 17 +- .../nodes/updateHighlightedText.ts | 12 +- src/agent/utils.ts | 17 +- src/components/canvas/canvas.tsx | 14 +- .../chat-interface/model-selector.tsx | 313 ++++++++++++++---- src/components/chat-interface/thread.tsx | 34 +- src/components/ui/command.tsx | 155 +++++++++ src/components/ui/popover.tsx | 33 ++ src/constants.ts | 81 ++++- src/contexts/GraphContext.tsx | 80 +++-- src/hooks/useThread.tsx | 16 +- src/types.ts | 22 ++ yarn.lock | 212 +++++++++++- 20 files changed, 922 insertions(+), 169 deletions(-) create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/popover.tsx diff --git a/package.json b/package.json index 2188acd7..ccd143ab 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,8 @@ "@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-navigation-menu": "^1.2.1", + "@radix-ui/react-popover": "^1.1.2", "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slider": "^1.2.1", @@ -60,6 +62,7 @@ "@vercel/kv": "^2.0.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "cmdk": "1.0.0", "date-fns": "^4.1.0", "dotenv": "^16.4.5", "eslint-plugin-unused-imports": "^4.1.4", diff --git a/src/agent/open-canvas/nodes/customAction.ts b/src/agent/open-canvas/nodes/customAction.ts index 052961d1..d1fe99ae 100644 --- a/src/agent/open-canvas/nodes/customAction.ts +++ b/src/agent/open-canvas/nodes/customAction.ts @@ -39,11 +39,13 @@ export const customAction = async ( throw new Error("No custom quick action ID found."); } - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = await initChatModel(modelName, { - temperature: 0.5, modelProvider, + // temperature: 0.5, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const store = ensureStoreInConfig(config); diff --git a/src/agent/open-canvas/nodes/generateArtifact.ts b/src/agent/open-canvas/nodes/generateArtifact.ts index bd61bd46..7b832db5 100644 --- a/src/agent/open-canvas/nodes/generateArtifact.ts +++ b/src/agent/open-canvas/nodes/generateArtifact.ts @@ -1,5 +1,6 @@ -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { NEW_ARTIFACT_PROMPT } from "../prompts"; +import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { initChatModel } from "langchain/chat_models/universal"; +import { z } from "zod"; import { ArtifactCodeV3, ArtifactMarkdownV3, @@ -7,14 +8,13 @@ import { PROGRAMMING_LANGUAGES, Reflections, } from "../../../types"; -import { z } from "zod"; import { ensureStoreInConfig, formatReflections, getModelNameAndProviderFromConfig, } from "../../utils"; -import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { initChatModel } from "langchain/chat_models/universal"; +import { NEW_ARTIFACT_PROMPT } from "../prompts"; +import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; /** * Generate a new artifact based on the user's query. @@ -23,11 +23,13 @@ export const generateArtifact = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ): Promise => { - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = await initChatModel(modelName, { - temperature: 0.5, modelProvider, + // temperature: 0.5, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const store = ensureStoreInConfig(config); diff --git a/src/agent/open-canvas/nodes/replyToGeneralInput.ts b/src/agent/open-canvas/nodes/replyToGeneralInput.ts index 5cd71d2f..fbca61a4 100644 --- a/src/agent/open-canvas/nodes/replyToGeneralInput.ts +++ b/src/agent/open-canvas/nodes/replyToGeneralInput.ts @@ -18,11 +18,13 @@ export const replyToGeneralInput = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ): Promise => { - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = await initChatModel(modelName, { - temperature: 0.5, modelProvider, + // temperature: 0.5, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const prompt = `You are an AI assistant tasked with responding to the users question. diff --git a/src/agent/open-canvas/nodes/rewriteArtifact.ts b/src/agent/open-canvas/nodes/rewriteArtifact.ts index 067a522f..628c73ba 100644 --- a/src/agent/open-canvas/nodes/rewriteArtifact.ts +++ b/src/agent/open-canvas/nodes/rewriteArtifact.ts @@ -1,15 +1,11 @@ -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { - GET_TITLE_TYPE_REWRITE_ARTIFACT, - OPTIONALLY_UPDATE_META_PROMPT, - UPDATE_ENTIRE_ARTIFACT_PROMPT, -} from "../prompts"; +import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { initChatModel } from "langchain/chat_models/universal"; +import { z } from "zod"; +import { getArtifactContent } from "../../../contexts/utils"; import { - ensureStoreInConfig, - formatArtifactContent, - formatReflections, - getModelNameAndProviderFromConfig, -} from "../../utils"; + isArtifactCodeContent, + isArtifactMarkdownContent, +} from "../../../lib/artifact_content_types"; import { ArtifactCodeV3, ArtifactMarkdownV3, @@ -17,14 +13,18 @@ import { PROGRAMMING_LANGUAGES, Reflections, } from "../../../types"; -import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { z } from "zod"; -import { getArtifactContent } from "../../../contexts/utils"; import { - isArtifactCodeContent, - isArtifactMarkdownContent, -} from "../../../lib/artifact_content_types"; -import { initChatModel } from "langchain/chat_models/universal"; + ensureStoreInConfig, + formatArtifactContent, + formatReflections, + getModelNameAndProviderFromConfig, +} from "../../utils"; +import { + GET_TITLE_TYPE_REWRITE_ARTIFACT, + OPTIONALLY_UPDATE_META_PROMPT, + UPDATE_ENTIRE_ARTIFACT_PROMPT, +} from "../prompts"; +import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; export const rewriteArtifact = async ( state: typeof OpenCanvasGraphAnnotation.State, @@ -51,12 +51,14 @@ export const rewriteArtifact = async ( "The language of the code artifact. This should be populated with the programming language if the user is requesting code to be written, or 'other', in all other cases." ), }); - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const toolCallingModel = ( await initChatModel(modelName, { - temperature: 0, modelProvider, + temperature: 0, + // temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }) ) .bindTools( diff --git a/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts b/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts index 0d5c73e5..43bdad4b 100644 --- a/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts +++ b/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts @@ -21,11 +21,13 @@ export const rewriteArtifactTheme = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ): Promise => { - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = await initChatModel(modelName, { - temperature: 0.5, modelProvider, + // temperature: 0.5, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const store = ensureStoreInConfig(config); diff --git a/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts b/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts index b1203c82..e098bf63 100644 --- a/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts +++ b/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts @@ -16,11 +16,13 @@ export const rewriteCodeArtifactTheme = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ): Promise => { - const { modelName, modelProvider } = + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = await initChatModel(modelName, { - temperature: 0.5, modelProvider, + // temperature: 0.5, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const currentArtifactContent = state.artifact diff --git a/src/agent/open-canvas/nodes/updateArtifact.ts b/src/agent/open-canvas/nodes/updateArtifact.ts index 74f97b60..65b9f528 100644 --- a/src/agent/open-canvas/nodes/updateArtifact.ts +++ b/src/agent/open-canvas/nodes/updateArtifact.ts @@ -1,11 +1,15 @@ -import { ChatOpenAI } from "@langchain/openai"; -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { UPDATE_HIGHLIGHTED_ARTIFACT_PROMPT } from "../prompts"; -import { ensureStoreInConfig, formatReflections } from "../../utils"; -import { ArtifactCodeV3, ArtifactV3, Reflections } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { ChatOpenAI } from "@langchain/openai"; import { getArtifactContent } from "../../../contexts/utils"; import { isArtifactCodeContent } from "../../../lib/artifact_content_types"; +import { ArtifactCodeV3, ArtifactV3, Reflections } from "../../../types"; +import { + ensureStoreInConfig, + formatReflections, + getModelNameAndProviderFromConfig, +} from "../../utils"; +import { UPDATE_HIGHLIGHTED_ARTIFACT_PROMPT } from "../prompts"; +import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; /** * Update an existing artifact based on the user's query. @@ -14,9 +18,12 @@ export const updateArtifact = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ): Promise => { + const { modelConfig } = getModelNameAndProviderFromConfig(config); const smallModel = new ChatOpenAI({ model: "gpt-4o", temperature: 0, + // temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); const store = ensureStoreInConfig(config); diff --git a/src/agent/open-canvas/nodes/updateHighlightedText.ts b/src/agent/open-canvas/nodes/updateHighlightedText.ts index e37f441c..3a9c133b 100644 --- a/src/agent/open-canvas/nodes/updateHighlightedText.ts +++ b/src/agent/open-canvas/nodes/updateHighlightedText.ts @@ -1,8 +1,10 @@ +import { getModelNameAndProviderFromConfig } from "@/agent/utils"; +import { LangGraphRunnableConfig } from "@langchain/langgraph"; import { ChatOpenAI } from "@langchain/openai"; -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { ArtifactMarkdownV3 } from "../../../types"; import { getArtifactContent } from "../../../contexts/utils"; import { isArtifactMarkdownContent } from "../../../lib/artifact_content_types"; +import { ArtifactMarkdownV3 } from "../../../types"; +import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; const PROMPT = `You are an expert AI writing assistant, tasked with rewriting some text a user has selected. The selected text is nested inside a larger 'block'. You should always respond with ONLY the updated text block in accordance with the user's request. You should always respond with the full markdown text block, as it will simply replace the existing block in the artifact. @@ -27,11 +29,15 @@ Ensure you reply with the FULL text block, including the updated selected text. * Update an existing artifact based on the user's query. */ export const updateHighlightedText = async ( - state: typeof OpenCanvasGraphAnnotation.State + state: typeof OpenCanvasGraphAnnotation.State, + config: LangGraphRunnableConfig ): Promise => { + const { modelConfig } = getModelNameAndProviderFromConfig(config); const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0, + // temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }).withConfig({ runName: "update_highlighted_markdown" }); const currentArtifactContent = state.artifact diff --git a/src/agent/utils.ts b/src/agent/utils.ts index e58c64cc..b0bd6e2f 100644 --- a/src/agent/utils.ts +++ b/src/agent/utils.ts @@ -1,4 +1,5 @@ import { isArtifactCodeContent } from "@/lib/artifact_content_types"; +import { CustomModelConfig } from "@/types"; import { BaseStore, LangGraphRunnableConfig } from "@langchain/langgraph"; import { ArtifactCodeV3, ArtifactMarkdownV3, Reflections } from "../types"; @@ -114,33 +115,47 @@ export const formatArtifactContentWithTemplate = ( export const getModelNameAndProviderFromConfig = ( config: LangGraphRunnableConfig -): { modelName: string; modelProvider: string } => { +): { + modelName: string; + modelProvider: string; + modelConfig: CustomModelConfig; +} => { const customModelName = config.configurable?.customModelName as string; if (!customModelName) { throw new Error("Model name is missing in config."); } + + const modelConfig = config.configurable?.modelConfig as CustomModelConfig; + if (!modelConfig) { + throw new Error("Custom Model config is missing in config."); + } + if (customModelName.includes("gpt-")) { return { modelName: customModelName, modelProvider: "openai", + modelConfig, }; } if (customModelName.includes("claude-")) { return { modelName: customModelName, modelProvider: "anthropic", + modelConfig, }; } if (customModelName.includes("fireworks/")) { return { modelName: customModelName, modelProvider: "fireworks", + modelConfig, }; } if (customModelName.includes("gemini-")) { return { modelName: customModelName, modelProvider: "google-genai", + modelConfig, }; } diff --git a/src/components/canvas/canvas.tsx b/src/components/canvas/canvas.tsx index f8b36967..d0b5c185 100644 --- a/src/components/canvas/canvas.tsx +++ b/src/components/canvas/canvas.tsx @@ -1,8 +1,8 @@ "use client"; import { ArtifactRenderer } from "@/components/artifacts/ArtifactRenderer"; -import { ContentComposerChatInterface } from "./content-composer"; import { ALL_MODEL_NAMES } from "@/constants"; +import { useGraphContext } from "@/contexts/GraphContext"; import { useToast } from "@/hooks/use-toast"; import { getLanguageTemplate } from "@/lib/get_language_template"; import { cn } from "@/lib/utils"; @@ -10,16 +10,17 @@ import { ArtifactCodeV3, ArtifactMarkdownV3, ArtifactV3, + CustomModelConfig, ProgrammingLanguageOptions, } from "@/types"; -import { useEffect, useState } from "react"; -import { useGraphContext } from "@/contexts/GraphContext"; -import React from "react"; +import React, { useEffect, useState } from "react"; +import { ContentComposerChatInterface } from "./content-composer"; export function CanvasComponent() { const { threadData, graphData, userData } = useGraphContext(); const { user } = userData; - const { threadId, clearThreadsWithNoValues, setModelName } = threadData; + const { threadId, clearThreadsWithNoValues, setModelName, setModelConfig } = + threadData; const { setArtifact } = graphData; const { toast } = useToast(); const [chatStarted, setChatStarted] = useState(false); @@ -91,6 +92,9 @@ export function CanvasComponent() { setModelName( thread?.metadata?.customModelName as ALL_MODEL_NAMES ); + setModelConfig( + thread?.metadata?.modelConfig as CustomModelConfig + ); } else { setChatStarted(false); } diff --git a/src/components/chat-interface/model-selector.tsx b/src/components/chat-interface/model-selector.tsx index c5656948..4b2d9bac 100644 --- a/src/components/chat-interface/model-selector.tsx +++ b/src/components/chat-interface/model-selector.tsx @@ -1,28 +1,43 @@ "use client"; -import { motion, AnimatePresence } from "framer-motion"; import LLMIcon from "@/components/icons/svg/LLMIcon.svg"; -import NextImage from "next/image"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; + Command, + CommandGroup, + CommandItem, + CommandList, +} from "@/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; import { ALL_MODEL_NAMES, ANTHROPIC_MODELS, - OPENAI_MODELS, FIREWORKS_MODELS, GEMINI_MODELS, LS_HAS_SEEN_MODEL_DROPDOWN_ALERT, + OPENAI_MODELS, } from "@/constants"; -import { Dispatch, SetStateAction, useEffect, useState } from "react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { ExternalLink, X } from "lucide-react"; -import { TighterText } from "../ui/header"; +import { CustomModelConfig, ModelConfigurationParams } from "@/types"; + +import { cn } from "@/lib/utils"; +import { CaretSortIcon, GearIcon } from "@radix-ui/react-icons"; +import { AnimatePresence, motion } from "framer-motion"; +import { Check, ExternalLink, X } from "lucide-react"; +import NextImage from "next/image"; +import { + Dispatch, + SetStateAction, + useCallback, + useEffect, + useState, +} from "react"; import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button"; +import { TighterText } from "../ui/header"; +import { Slider } from "../ui/slider"; const allModels = [ ...ANTHROPIC_MODELS, @@ -31,17 +46,14 @@ const allModels = [ ...GEMINI_MODELS, ]; +const modelLabelMap = new Map( + allModels.map((model) => [model.name, model.label]) +); + const modelNameToLabel = (modelName: ALL_MODEL_NAMES) => { - const model = allModels.find((m) => m.name === modelName); - return model?.label ?? modelName; + return modelLabelMap.get(modelName) ?? modelName; }; -interface ModelSelectorProps { - modelName: ALL_MODEL_NAMES; - setModelName: Dispatch>; - chatStarted: boolean; -} - const AlertNewModelSelectorFeature = ({ chatStarted, showAlert, @@ -144,19 +156,148 @@ const AlertNewModelSelectorFeature = ({ ); }; -export default function ModelSelector(props: ModelSelectorProps) { - const { modelName, setModelName } = props; - const [showAlert, setShowAlert] = useState(false); +interface ModelSettingsProps { + model: ModelConfigurationParams; + className?: string; + isOpen: boolean; + onOpenChange: (open: boolean) => void; + onClick: (e: any) => any; + modelConfig: CustomModelConfig; + setModelConfig: ( + config: CustomModelConfig | ((prev: CustomModelConfig) => CustomModelConfig) + ) => void; +} + +const ModelSettings = ({ + model, + className, + isOpen, + onOpenChange, + onClick, + modelConfig, + setModelConfig, +}: ModelSettingsProps) => { + const handleTemperatureChange = useCallback( + (value: number[]) => { + setModelConfig((prev) => ({ + ...prev, + temperatureRange: { + ...prev.temperatureRange, + current: value[0], + }, + })); + }, + [setModelConfig] + ); + + const handleMaxTokensChange = useCallback( + (value: number[]) => { + setModelConfig((prev) => ({ + ...prev, + maxTokens: { + ...prev.maxTokens, + current: value[0], + }, + })); + }, + [setModelConfig] + ); + + return ( + + + + + e.stopPropagation()} + > +
+ + +
+
+
+ ); +}; +interface SettingSectionProps { + title: string; + description: string; + value: number; + min: number; + max: number; + step: number; + onChange: (value: number[]) => void; +} + +const SettingSection = ({ + title, + description, + value, + min, + max, + step, + onChange, +}: SettingSectionProps) => ( +
+

{title}

+

{description}

+ +
{value}
+
+); + +interface SelectSelectorProps { + modelName: ALL_MODEL_NAMES; + setModelName: (name: ALL_MODEL_NAMES) => void; + chatStarted: boolean; + open: boolean; + setOpen: (open: boolean) => void; + modelConfig: CustomModelConfig; + setModelConfig: ( + config: CustomModelConfig | ((prev: CustomModelConfig) => CustomModelConfig) + ) => void; +} + +export function SelectSelector(props: SelectSelectorProps) { + const { modelName, setModelName, modelConfig, setModelConfig, setOpen } = + props; + const [activeSettings, setActiveSettings] = useState(null); + + const handleModelChange = useCallback( + async (newModel: ALL_MODEL_NAMES) => { + setModelName(newModel); + setOpen(false); + }, + [setModelName, setOpen] + ); - const handleModelChange = async (newModel: ALL_MODEL_NAMES) => { - // Create a new thread with the new model - setModelName(newModel); - if (showAlert) { - // Ensure the model is closed if the user selects a model - setShowAlert(false); - localStorage.setItem(LS_HAS_SEEN_MODEL_DROPDOWN_ALERT, "true"); - } - }; const allAllowedModels = allModels.filter((model) => { if ( model.name.includes("fireworks/") && @@ -188,30 +329,90 @@ export default function ModelSelector(props: ModelSelectorProps) { }); return ( -
- + {model.label} + { + setActiveSettings(open ? model.name : null); + }} + onClick={(e) => e.stopPropagation()} // Prevent onSelect from being triggered + modelConfig={modelConfig} + setModelConfig={setModelConfig} + /> + + + ))} + + + ); +} + +interface ModelSelectorProps { + modelName: ALL_MODEL_NAMES; + setModelName: (name: ALL_MODEL_NAMES) => void; + chatStarted: boolean; + modelConfig: CustomModelConfig; + setModelConfig: ( + config: CustomModelConfig | ((prev: CustomModelConfig) => CustomModelConfig) + ) => void; +} + +export default function ModelSelector(props: ModelSelectorProps) { + const [showAlert, setShowAlert] = useState(false); + const [open, setOpen] = useState(false); + + console.log("ModelSelector modelConfig: ", props.modelConfig); + + return ( +
+ + +
+ + + {modelNameToLabel(props.modelName)} + + +
+
+ + + +
{ return ( @@ -49,7 +49,14 @@ export const Thread: FC = (props: ThreadProps) => { const { toast } = useToast(); const { userData: { user }, - threadData: { createThread, modelName, setModelName, assistantId }, + threadData: { + createThread, + modelName, + setModelName, + assistantId, + modelConfig, + setModelConfig, + }, graphData: { clearState, runId, feedbackSubmitted, setFeedbackSubmitted }, } = useGraphContext(); @@ -66,9 +73,10 @@ export const Thread: FC = (props: ThreadProps) => { return; } setModelName(modelName); + setModelConfig(modelConfig); clearState(); setChatStarted(false); - const thread = await createThread(modelName, user.id); + const thread = await createThread(modelName, modelConfig, user.id); if (!thread) { toast({ title: "Failed to create a new thread", @@ -91,6 +99,8 @@ export const Thread: FC = (props: ThreadProps) => { chatStarted={false} modelName={modelName} setModelName={setModelName} + modelConfig={modelConfig} + setModelConfig={setModelConfig} /> )}
@@ -140,6 +150,8 @@ export const Thread: FC = (props: ThreadProps) => { chatStarted={true} modelName={modelName} setModelName={setModelName} + modelConfig={modelConfig} + setModelConfig={setModelConfig} />
diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx new file mode 100644 index 00000000..c52980e8 --- /dev/null +++ b/src/components/ui/command.tsx @@ -0,0 +1,155 @@ +"use client" + +import * as React from "react" +import { type DialogProps } from "@radix-ui/react-dialog" +import { MagnifyingGlassIcon } from "@radix-ui/react-icons" +import { Command as CommandPrimitive } from "cmdk" + +import { cn } from "@/lib/utils" +import { Dialog, DialogContent } from "@/components/ui/dialog" + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Command.displayName = CommandPrimitive.displayName + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ) +} + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)) + +CommandInput.displayName = CommandPrimitive.Input.displayName + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandList.displayName = CommandPrimitive.List.displayName + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)) + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandGroup.displayName = CommandPrimitive.Group.displayName + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +CommandSeparator.displayName = CommandPrimitive.Separator.displayName + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandItem.displayName = CommandPrimitive.Item.displayName + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +CommandShortcut.displayName = "CommandShortcut" + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx new file mode 100644 index 00000000..29c7bd2a --- /dev/null +++ b/src/components/ui/popover.tsx @@ -0,0 +1,33 @@ +"use client" + +import * as React from "react" +import * as PopoverPrimitive from "@radix-ui/react-popover" + +import { cn } from "@/lib/utils" + +const Popover = PopoverPrimitive.Root + +const PopoverTrigger = PopoverPrimitive.Trigger + +const PopoverAnchor = PopoverPrimitive.Anchor + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + + + +)) +PopoverContent.displayName = PopoverPrimitive.Content.displayName + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/src/constants.ts b/src/constants.ts index 4f997705..b4ae1d4c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,5 @@ +import { CustomModelConfig, ModelConfigurationParams } from "./types"; + export const LANGGRAPH_API_URL = process.env.LANGGRAPH_API_URL ?? "http://localhost:57318"; // v2 is tied to the 'open-canvas-prod' deployment. @@ -23,36 +25,97 @@ export const DEFAULT_INPUTS = { customQuickActionId: undefined, }; -export const OPENAI_MODELS = [ +export const OPENAI_MODELS: ModelConfigurationParams[] = [ { name: "gpt-4o-mini", label: "GPT-4o mini", + config: { + provider: "openai", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 16384, + default: 16384, + current: 16384, + }, + }, }, ]; -export const ANTHROPIC_MODELS = [ + +export const ANTHROPIC_MODELS: ModelConfigurationParams[] = [ { name: "claude-3-haiku-20240307", label: "Claude 3 Haiku", + config: { + provider: "anthropic", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 4096, + default: 4096, + current: 4096, + }, + }, }, - // { - // name: "claude-3-5-sonnet-20240620", - // label: "Claude 3.5 Sonnet", - // }, ]; -export const FIREWORKS_MODELS = [ + +export const FIREWORKS_MODELS: ModelConfigurationParams[] = [ { name: "accounts/fireworks/models/llama-v3p1-70b-instruct", label: "Fireworks Llama 70B", + config: { + provider: "fireworks", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 16384, + default: 16384, + current: 16384, + }, + }, }, ]; -export const GEMINI_MODELS = [ +export const GEMINI_MODELS: ModelConfigurationParams[] = [ { name: "gemini-1.5-flash", label: "Gemini 1.5 Flash", + config: { + provider: "google-genai", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 8192, + default: 8192, + current: 8192, + }, + }, }, ]; -export const DEFAULT_MODEL_NAME: ALL_MODEL_NAMES = "gpt-4o-mini"; + +export const DEFAULT_MODEL_NAME: ALL_MODEL_NAMES = OPENAI_MODELS[0].name; +export const DEFAULT_MODE_CONFIG: CustomModelConfig = OPENAI_MODELS[0].config; + export type OPENAI_MODEL_NAMES = (typeof OPENAI_MODELS)[number]["name"]; export type ANTHROPIC_MODEL_NAMES = (typeof ANTHROPIC_MODELS)[number]["name"]; export type FIREWORKS_MODEL_NAMES = (typeof FIREWORKS_MODELS)[number]["name"]; diff --git a/src/contexts/GraphContext.tsx b/src/contexts/GraphContext.tsx index a522e800..302f4add 100644 --- a/src/contexts/GraphContext.tsx +++ b/src/contexts/GraphContext.tsx @@ -1,26 +1,25 @@ import { - createContext, - useContext, - ReactNode, - useEffect, - useState, - useRef, - Dispatch, - SetStateAction, -} from "react"; -import { - convertToArtifactV3, - createNewGeneratedArtifactFromTool, - replaceOrInsertMessageChunk, - updateHighlightedCode, - updateHighlightedMarkdown, - updateRewrittenArtifact, - removeCodeBlockFormatting, -} from "./utils"; -import { useUser } from "@/hooks/useUser"; + ALL_MODEL_NAMES, + DEFAULT_INPUTS, + DEFAULT_MODE_CONFIG, + DEFAULT_MODEL_NAME, + THREAD_ID_COOKIE_NAME, +} from "@/constants"; +import { CustomModelConfig } from "@/types"; + +import { useToast } from "@/hooks/use-toast"; +import { useRuns } from "@/hooks/useRuns"; import { useThread } from "@/hooks/useThread"; +import { useUser } from "@/hooks/useUser"; +import { createClient } from "@/hooks/utils"; +import { + isArtifactCodeContent, + isArtifactMarkdownContent, + isDeprecatedArtifactType, +} from "@/lib/artifact_content_types"; +import { setCookie } from "@/lib/cookies"; +import { reverseCleanContent } from "@/lib/normalize_string"; import { addAssistantIdToUser } from "@/lib/supabase/add_assistant_id_to_user"; -import { debounce } from "lodash"; import { ArtifactLengthOptions, ArtifactToolResponse, @@ -34,24 +33,28 @@ import { TextHighlight, } from "@/types"; import { AIMessage, BaseMessage } from "@langchain/core/messages"; -import { useRuns } from "@/hooks/useRuns"; -import { createClient } from "@/hooks/utils"; -import { - ALL_MODEL_NAMES, - DEFAULT_INPUTS, - DEFAULT_MODEL_NAME, - THREAD_ID_COOKIE_NAME, -} from "@/constants"; -import { Thread } from "@langchain/langgraph-sdk"; -import { useToast } from "@/hooks/use-toast"; import { parsePartialJson } from "@langchain/core/output_parsers"; +import { Thread } from "@langchain/langgraph-sdk"; +import { debounce } from "lodash"; import { - isArtifactCodeContent, - isArtifactMarkdownContent, - isDeprecatedArtifactType, -} from "@/lib/artifact_content_types"; -import { reverseCleanContent } from "@/lib/normalize_string"; -import { setCookie } from "@/lib/cookies"; + createContext, + Dispatch, + ReactNode, + SetStateAction, + useContext, + useEffect, + useRef, + useState, +} from "react"; +import { + convertToArtifactV3, + createNewGeneratedArtifactFromTool, + removeCodeBlockFormatting, + replaceOrInsertMessageChunk, + updateHighlightedCode, + updateHighlightedMarkdown, + updateRewrittenArtifact, +} from "./utils"; interface GraphData { runId: string | undefined; @@ -311,6 +314,7 @@ export function GraphProvider({ children }: { children: ReactNode }) { config: { configurable: { customModelName: threadData.modelName, + modelConfig: threadData.modelConfig, }, }, } @@ -880,8 +884,12 @@ export function GraphProvider({ children }: { children: ReactNode }) { threadData.setModelName( thread.metadata.customModelName as ALL_MODEL_NAMES ); + threadData.setModelConfig( + thread.metadata.modelConfig as CustomModelConfig + ); } else { threadData.setModelName(DEFAULT_MODEL_NAME); + threadData.setModelConfig(DEFAULT_MODE_CONFIG); } const castValues: { diff --git a/src/hooks/useThread.tsx b/src/hooks/useThread.tsx index 5760e30b..e78fb859 100644 --- a/src/hooks/useThread.tsx +++ b/src/hooks/useThread.tsx @@ -1,11 +1,13 @@ import { ALL_MODEL_NAMES, ASSISTANT_ID_COOKIE, + DEFAULT_MODE_CONFIG, DEFAULT_MODEL_NAME, HAS_EMPTY_THREADS_CLEARED_COOKIE, THREAD_ID_COOKIE_NAME, } from "@/constants"; import { getCookie, setCookie } from "@/lib/cookies"; +import { CustomModelConfig } from "@/types"; import { Thread } from "@langchain/langgraph-sdk"; import { useState } from "react"; import { createClient } from "./utils"; @@ -17,9 +19,12 @@ export function useThread() { const [isUserThreadsLoading, setIsUserThreadsLoading] = useState(false); const [modelName, setModelName] = useState(DEFAULT_MODEL_NAME); + const [modelConfig, setModelConfig] = + useState(DEFAULT_MODE_CONFIG); const createThread = async ( customModelName: ALL_MODEL_NAMES = DEFAULT_MODEL_NAME, + custModelConfig: CustomModelConfig = modelConfig, userId: string ): Promise => { const client = createClient(); @@ -28,11 +33,13 @@ export function useThread() { metadata: { supabase_user_id: userId, customModelName, + modelConfig: custModelConfig, }, }); setThreadId(thread.thread_id); setCookie(THREAD_ID_COOKIE_NAME, thread.thread_id); setModelName(customModelName); + setModelConfig(custModelConfig); await getUserThreads(userId); return thread; } catch (e) { @@ -86,7 +93,7 @@ export function useThread() { const searchOrCreateThread = async (userId: string) => { const threadIdCookie = getCookie(THREAD_ID_COOKIE_NAME); if (!threadIdCookie) { - await createThread(modelName, userId); + await createThread(modelName, modelConfig, userId); return; } @@ -101,7 +108,7 @@ export function useThread() { return threadIdCookie; } else { // Current thread has activity. Create a new thread. - await createThread(modelName, userId); + await createThread(modelName, modelConfig, userId); return; } }; @@ -176,6 +183,7 @@ export function useThread() { const thread = await client.threads.get(id); if (thread.metadata && thread.metadata.customModelName) { setModelName(thread.metadata.customModelName as ALL_MODEL_NAMES); + setModelConfig(thread.metadata.modelConfig as CustomModelConfig); } return thread; } catch (e) { @@ -199,7 +207,7 @@ export function useThread() { // Create a new thread. Use .then to avoid blocking the UI. // Once completed, `createThread` will re-fetch all user // threads to update UI. - void createThread(modelName, userId); + void createThread(modelName, modelConfig, userId); } const client = createClient(); try { @@ -215,6 +223,7 @@ export function useThread() { userThreads, isUserThreadsLoading, modelName, + modelConfig, createThread, clearThreadsWithNoValues, searchOrCreateThread, @@ -224,5 +233,6 @@ export function useThread() { setThreadId, getOrCreateAssistant, setModelName, + setModelConfig, }; } diff --git a/src/types.ts b/src/types.ts index 22fbd6c5..e75736ec 100644 --- a/src/types.ts +++ b/src/types.ts @@ -265,3 +265,25 @@ export type RewriteArtifactMetaToolResponse = title: string; language: ProgrammingLanguageOptions; }; + +export interface CustomModelConfig { + provider: "openai" | "anthropic" | "fireworks" | "google-genai"; + temperatureRange: { + min: number; + max: number; + default: number; + current: number; + }; + maxTokens: { + min: number; + max: number; + default: number; + current: number; + }; +} + +export interface ModelConfigurationParams { + name: string; + label: string; + config: CustomModelConfig; +} diff --git a/yarn.lock b/yarn.lock index 8536e252..b19d26a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -70,6 +70,13 @@ zod-to-json-schema "^3.23.3" zustand "^4.5.5" +"@babel/runtime@^7.13.10": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.14.6", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.6": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6" @@ -1006,6 +1013,13 @@ resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46" integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ== +"@radix-ui/primitive@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" + integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive@1.1.0", "@radix-ui/primitive@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2" @@ -1062,11 +1076,25 @@ "@radix-ui/react-primitive" "2.0.0" "@radix-ui/react-slot" "1.1.0" +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs@1.1.0", "@radix-ui/react-compose-refs@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74" integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw== +"@radix-ui/react-context@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" + integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8" @@ -1077,6 +1105,27 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a" integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q== +"@radix-ui/react-dialog@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + "@radix-ui/react-dialog@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz#d9345575211d6f2d13e209e84aec9a8584b54d6c" @@ -1102,6 +1151,18 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc" integrity sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg== +"@radix-ui/react-dismissable-layer@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" + integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown" "1.0.3" + "@radix-ui/react-dismissable-layer@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz#2cd0a49a732372513733754e6032d3fb7988834e" @@ -1137,6 +1198,13 @@ "@radix-ui/react-primitive" "2.0.0" "@radix-ui/react-use-controllable-state" "1.1.0" +"@radix-ui/react-focus-guards@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" + integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-focus-guards@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz#8e9abb472a9a394f59a1b45f3dd26cfe3fc6da13" @@ -1147,6 +1215,16 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe" integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg== +"@radix-ui/react-focus-scope@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-focus-scope@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz#ebe2891a298e0a33ad34daab2aad8dea31caf0b2" @@ -1176,6 +1254,14 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.0.tgz#c61af8f323d87682c5ca76b856d60c2312dbcb69" integrity sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw== +"@radix-ui/react-id@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0" + integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-id@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed" @@ -1214,6 +1300,26 @@ aria-hidden "^1.1.1" react-remove-scroll "2.6.0" +"@radix-ui/react-navigation-menu@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.1.tgz#31989e026adecfbb2f7bd1108ee6fffb830b2ec1" + integrity sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q== + dependencies: + "@radix-ui/primitive" "1.1.0" + "@radix-ui/react-collection" "1.1.0" + "@radix-ui/react-compose-refs" "1.1.0" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-dismissable-layer" "1.1.1" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-presence" "1.1.1" + "@radix-ui/react-primitive" "2.0.0" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-use-previous" "1.1.0" + "@radix-ui/react-visually-hidden" "1.1.0" + "@radix-ui/react-popover@^1.0.7", "@radix-ui/react-popover@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.2.tgz#a0cab25f69aa49ad0077d91e9e9dcd323758020c" @@ -1251,6 +1357,14 @@ "@radix-ui/react-use-size" "1.1.0" "@radix-ui/rect" "1.1.0" +"@radix-ui/react-portal@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" + integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-portal@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.1.tgz#1957f1eb2e1aedfb4a5475bd6867d67b50b1d15f" @@ -1267,6 +1381,15 @@ "@radix-ui/react-primitive" "2.0.0" "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-presence@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.0.tgz#227d84d20ca6bfe7da97104b1a8b48a833bfb478" @@ -1283,6 +1406,14 @@ "@radix-ui/react-compose-refs" "1.1.0" "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-primitive@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" + integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-primitive@2.0.0", "@radix-ui/react-primitive@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884" @@ -1384,6 +1515,14 @@ "@radix-ui/react-use-previous" "1.1.0" "@radix-ui/react-use-size" "1.1.0" +"@radix-ui/react-slot@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.0.2", "@radix-ui/react-slot@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84" @@ -1468,11 +1607,26 @@ "@radix-ui/react-use-controllable-state" "1.1.0" "@radix-ui/react-visually-hidden" "1.1.0" +"@radix-ui/react-use-callback-ref@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" + integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref@1.1.0", "@radix-ui/react-use-callback-ref@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1" integrity sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw== +"@radix-ui/react-use-controllable-state@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" + integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz#1321446857bb786917df54c0d4d084877aab04b0" @@ -1480,6 +1634,14 @@ dependencies: "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-use-escape-keydown@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755" + integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown@1.1.0", "@radix-ui/react-use-escape-keydown@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz#31a5b87c3b726504b74e05dac1edce7437b98754" @@ -1487,6 +1649,13 @@ dependencies: "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-use-layout-effect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" + integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27" @@ -2697,6 +2866,14 @@ clsx@^2.1.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== +cmdk@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-1.0.0.tgz#0a095fdafca3dfabed82d1db78a6262fb163ded9" + integrity sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q== + dependencies: + "@radix-ui/react-dialog" "1.0.5" + "@radix-ui/react-primitive" "1.0.3" + codemirror@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29" @@ -6626,7 +6803,7 @@ react-number-format@^5.3.1: resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.4.2.tgz#aec282241f36cee31da13dc5e0f364c0fc6902ab" integrity sha512-cg//jVdS49PYDgmcYoBnMMHl4XNTMuV723ZnHD2aXYtWWWqbVF3hjQ8iB+UZEuXapLbeA8P8H+1o6ZB1lcw3vg== -react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6: +react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c" integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g== @@ -6634,6 +6811,17 @@ react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6: react-style-singleton "^2.2.1" tslib "^2.0.0" +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-remove-scroll@2.5.7: version "2.5.7" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb" @@ -7206,8 +7394,16 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: - name string-width-cjs +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7295,8 +7491,14 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - name strip-ansi-cjs +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From 3907bf2027afb4a5adadfd7aaee599a6c06543dd Mon Sep 17 00:00:00 2001 From: Muhammad Ahmad Date: Mon, 4 Nov 2024 09:18:00 +0500 Subject: [PATCH 2/6] feat: update model selection to set configuration on change --- src/components/chat-interface/model-selector.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/chat-interface/model-selector.tsx b/src/components/chat-interface/model-selector.tsx index 4b2d9bac..4912977c 100644 --- a/src/components/chat-interface/model-selector.tsx +++ b/src/components/chat-interface/model-selector.tsx @@ -293,9 +293,14 @@ export function SelectSelector(props: SelectSelectorProps) { const handleModelChange = useCallback( async (newModel: ALL_MODEL_NAMES) => { setModelName(newModel); + + const selectedModel = allModels.find((model) => model.name === newModel); + if (selectedModel) { + setModelConfig(selectedModel.config); + } setOpen(false); }, - [setModelName, setOpen] + [setModelName, setOpen, setModelConfig] ); const allAllowedModels = allModels.filter((model) => { From dacf24da38ee16b01c0c62f59e423e3b5a8bff83 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 5 Nov 2024 12:41:25 -0800 Subject: [PATCH 3/6] merge staging --- package.json | 5 +- src/agent/open-canvas/index.ts | 4 +- .../nodes/generate-artifact/index.ts | 61 +++ .../nodes/generate-artifact/schemas.ts | 33 ++ .../nodes/generate-artifact/utils.ts | 39 ++ .../open-canvas/nodes/generateArtifact.ts | 133 ------ src/agent/open-canvas/nodes/generatePath.ts | 8 +- .../nodes/rewrite-artifact/index.ts | 68 +++ .../nodes/rewrite-artifact/schemas.ts | 22 + .../nodes/rewrite-artifact/update-meta.ts | 55 +++ .../nodes/rewrite-artifact/utils.ts | 110 +++++ .../open-canvas/nodes/rewriteArtifact.ts | 186 -------- src/agent/utils.ts | 37 ++ src/components/artifacts/ArtifactRenderer.tsx | 6 +- .../custom/NewCustomQuickActionDialog.tsx | 17 +- .../custom/PromptContextTooltip.tsx | 31 -- .../assistant-select/alert-new-feature.tsx | 87 ++++ .../assistant-select/assistant-item.tsx | 69 +++ .../assistant-select/color-picker.tsx | 82 ++++ .../create-edit-assistant-dialog.tsx | 330 ++++++++++++++ .../edit-delete-dropdown.module.css | 12 + .../assistant-select/edit-delete-dropdown.tsx | 95 ++++ .../assistant-select/icon-select.tsx | 185 ++++++++ src/components/assistant-select/index.tsx | 202 ++++++++ src/components/assistant-select/utils.tsx | 11 + src/components/canvas/content-composer.tsx | 1 + src/components/chat-interface/composer.tsx | 9 +- .../chat-interface/model-selector.tsx | 430 ------------------ .../alert-new-model-selector.tsx | 113 +++++ .../model-selector/constants.ts | 8 + .../chat-interface/model-selector/index.tsx | 101 ++++ .../model-selector/model-settings.tsx | 131 ++++++ .../model-selector/new-badge.tsx | 30 ++ .../model-selector/select-selector.tsx | 108 +++++ src/components/chat-interface/thread.tsx | 9 +- .../reflections-dialog/ReflectionsDialog.tsx | 62 ++- src/components/ui/badge.tsx | 36 ++ src/components/ui/inline-context-tooltip.tsx | 31 ++ src/constants.ts | 34 +- src/contexts/GraphContext.tsx | 30 +- src/hooks/useAssistants.tsx | 367 +++++++++++++++ src/hooks/useStore.tsx | 1 + src/hooks/useThread.tsx | 28 +- src/lib/cookies.ts | 7 + src/lib/supabase/add_assistant_id_to_user.ts | 38 -- src/types.ts | 1 + tailwind.config.ts | 15 +- yarn.lock | 202 +++++--- 48 files changed, 2707 insertions(+), 973 deletions(-) create mode 100644 src/agent/open-canvas/nodes/generate-artifact/index.ts create mode 100644 src/agent/open-canvas/nodes/generate-artifact/schemas.ts create mode 100644 src/agent/open-canvas/nodes/generate-artifact/utils.ts delete mode 100644 src/agent/open-canvas/nodes/generateArtifact.ts create mode 100644 src/agent/open-canvas/nodes/rewrite-artifact/index.ts create mode 100644 src/agent/open-canvas/nodes/rewrite-artifact/schemas.ts create mode 100644 src/agent/open-canvas/nodes/rewrite-artifact/update-meta.ts create mode 100644 src/agent/open-canvas/nodes/rewrite-artifact/utils.ts delete mode 100644 src/agent/open-canvas/nodes/rewriteArtifact.ts delete mode 100644 src/components/artifacts/actions_toolbar/custom/PromptContextTooltip.tsx create mode 100644 src/components/assistant-select/alert-new-feature.tsx create mode 100644 src/components/assistant-select/assistant-item.tsx create mode 100644 src/components/assistant-select/color-picker.tsx create mode 100644 src/components/assistant-select/create-edit-assistant-dialog.tsx create mode 100644 src/components/assistant-select/edit-delete-dropdown.module.css create mode 100644 src/components/assistant-select/edit-delete-dropdown.tsx create mode 100644 src/components/assistant-select/icon-select.tsx create mode 100644 src/components/assistant-select/index.tsx create mode 100644 src/components/assistant-select/utils.tsx delete mode 100644 src/components/chat-interface/model-selector.tsx create mode 100644 src/components/chat-interface/model-selector/alert-new-model-selector.tsx create mode 100644 src/components/chat-interface/model-selector/constants.ts create mode 100644 src/components/chat-interface/model-selector/index.tsx create mode 100644 src/components/chat-interface/model-selector/model-settings.tsx create mode 100644 src/components/chat-interface/model-selector/new-badge.tsx create mode 100644 src/components/chat-interface/model-selector/select-selector.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/inline-context-tooltip.tsx create mode 100644 src/hooks/useAssistants.tsx delete mode 100644 src/lib/supabase/add_assistant_id_to_user.ts diff --git a/package.json b/package.json index ccd143ab..6c720659 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,9 @@ "langsmith": "^0.1.61", "lodash": "^4.17.21", "lucide-react": "^0.441.0", - "next": "14.2.7", + "next": "14.2.10", "react": "^18", + "react-colorful": "^5.6.1", "react-dom": "^18", "react-icons": "^5.3.0", "react-json-view": "^1.21.3", @@ -100,7 +101,7 @@ "@typescript-eslint/eslint-plugin": "^8.12.2", "@typescript-eslint/parser": "^8.8.1", "eslint": "^8", - "eslint-config-next": "14.2.7", + "eslint-config-next": "14.2.10", "postcss": "^8", "prettier": "^3.3.3", "tailwind-scrollbar": "^3.1.0", diff --git a/src/agent/open-canvas/index.ts b/src/agent/open-canvas/index.ts index 2dd9d194..3947ad68 100644 --- a/src/agent/open-canvas/index.ts +++ b/src/agent/open-canvas/index.ts @@ -1,11 +1,11 @@ import { END, Send, START, StateGraph } from "@langchain/langgraph"; import { DEFAULT_INPUTS } from "../../constants"; import { customAction } from "./nodes/customAction"; -import { generateArtifact } from "./nodes/generateArtifact"; +import { generateArtifact } from "./nodes/generate-artifact"; import { generateFollowup } from "./nodes/generateFollowup"; import { generatePath } from "./nodes/generatePath"; import { reflectNode } from "./nodes/reflect"; -import { rewriteArtifact } from "./nodes/rewriteArtifact"; +import { rewriteArtifact } from "./nodes/rewrite-artifact"; import { rewriteArtifactTheme } from "./nodes/rewriteArtifactTheme"; import { updateArtifact } from "./nodes/updateArtifact"; import { replyToGeneralInput } from "./nodes/replyToGeneralInput"; diff --git a/src/agent/open-canvas/nodes/generate-artifact/index.ts b/src/agent/open-canvas/nodes/generate-artifact/index.ts new file mode 100644 index 00000000..0977946b --- /dev/null +++ b/src/agent/open-canvas/nodes/generate-artifact/index.ts @@ -0,0 +1,61 @@ +import { + OpenCanvasGraphAnnotation, + OpenCanvasGraphReturnType, +} from "../../state"; +import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { + getFormattedReflections, + getModelFromConfig, + getModelNameAndProviderFromConfig, + optionallyGetSystemPromptFromConfig, +} from "@/agent/utils"; +import { ARTIFACT_TOOL_SCHEMA } from "./schemas"; +import { ArtifactV3 } from "@/types"; +import { createArtifactContent, formatNewArtifactPrompt } from "./utils"; + +/** + * Generate a new artifact based on the user's query. + */ +export const generateArtifact = async ( + state: typeof OpenCanvasGraphAnnotation.State, + config: LangGraphRunnableConfig +): Promise => { + const { modelName } = getModelNameAndProviderFromConfig(config); + const smallModel = await getModelFromConfig(config); + + const modelWithArtifactTool = smallModel.bindTools( + [ + { + name: "generate_artifact", + schema: ARTIFACT_TOOL_SCHEMA, + }, + ], + { tool_choice: "generate_artifact" } + ); + + const memoriesAsString = await getFormattedReflections(config); + const formattedNewArtifactPrompt = formatNewArtifactPrompt( + memoriesAsString, + modelName + ); + + const userSystemPrompt = optionallyGetSystemPromptFromConfig(config); + const fullSystemPrompt = userSystemPrompt + ? `${userSystemPrompt}\n${formattedNewArtifactPrompt}` + : formattedNewArtifactPrompt; + + const response = await modelWithArtifactTool.invoke( + [{ role: "system", content: fullSystemPrompt }, ...state.messages], + { runName: "generate_artifact" } + ); + + const newArtifactContent = createArtifactContent(response.tool_calls?.[0]); + const newArtifact: ArtifactV3 = { + currentIndex: 1, + contents: [newArtifactContent], + }; + + return { + artifact: newArtifact, + }; +}; diff --git a/src/agent/open-canvas/nodes/generate-artifact/schemas.ts b/src/agent/open-canvas/nodes/generate-artifact/schemas.ts new file mode 100644 index 00000000..2e2d4a4f --- /dev/null +++ b/src/agent/open-canvas/nodes/generate-artifact/schemas.ts @@ -0,0 +1,33 @@ +import { PROGRAMMING_LANGUAGES } from "@/types"; +import { z } from "zod"; + +export const ARTIFACT_TOOL_SCHEMA = z.object({ + type: z + .enum(["code", "text"]) + .describe("The content type of the artifact generated."), + language: z + .enum( + PROGRAMMING_LANGUAGES.map((lang) => lang.language) as [ + string, + ...string[], + ] + ) + .optional() + .describe( + "The language/programming language of the artifact generated.\n" + + "If generating code, it should be one of the options, or 'other'.\n" + + "If not generating code, the language should ALWAYS be 'other'." + ), + isValidReact: z + .boolean() + .optional() + .describe( + "Whether or not the generated code is valid React code. Only populate this field if generating code." + ), + artifact: z.string().describe("The content of the artifact to generate."), + title: z + .string() + .describe( + "A short title to give to the artifact. Should be less than 5 words." + ), +}); diff --git a/src/agent/open-canvas/nodes/generate-artifact/utils.ts b/src/agent/open-canvas/nodes/generate-artifact/utils.ts new file mode 100644 index 00000000..4e6aca8e --- /dev/null +++ b/src/agent/open-canvas/nodes/generate-artifact/utils.ts @@ -0,0 +1,39 @@ +import { NEW_ARTIFACT_PROMPT } from "../../prompts"; +import { ArtifactCodeV3, ArtifactMarkdownV3 } from "@/types"; +import { ToolCall } from "@langchain/core/messages/tool"; + +export const formatNewArtifactPrompt = ( + memoriesAsString: string, + modelName: string +): string => { + return NEW_ARTIFACT_PROMPT.replace("{reflections}", memoriesAsString).replace( + "{disableChainOfThought}", + modelName.includes("claude") + ? "\n\nIMPORTANT: Do NOT preform chain of thought beforehand. Instead, go STRAIGHT to generating the tool response. This is VERY important." + : "" + ); +}; + +export const createArtifactContent = ( + toolCall: ToolCall | undefined +): ArtifactCodeV3 | ArtifactMarkdownV3 => { + const toolArgs = toolCall?.args; + const artifactType = toolArgs?.type; + + if (artifactType === "code") { + return { + index: 1, + type: "code", + title: toolArgs?.title, + code: toolArgs?.artifact, + language: toolArgs?.language, + }; + } + + return { + index: 1, + type: "text", + title: toolArgs?.title, + fullMarkdown: toolArgs?.artifact, + }; +}; diff --git a/src/agent/open-canvas/nodes/generateArtifact.ts b/src/agent/open-canvas/nodes/generateArtifact.ts deleted file mode 100644 index 7b832db5..00000000 --- a/src/agent/open-canvas/nodes/generateArtifact.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { initChatModel } from "langchain/chat_models/universal"; -import { z } from "zod"; -import { - ArtifactCodeV3, - ArtifactMarkdownV3, - ArtifactV3, - PROGRAMMING_LANGUAGES, - Reflections, -} from "../../../types"; -import { - ensureStoreInConfig, - formatReflections, - getModelNameAndProviderFromConfig, -} from "../../utils"; -import { NEW_ARTIFACT_PROMPT } from "../prompts"; -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; - -/** - * Generate a new artifact based on the user's query. - */ -export const generateArtifact = async ( - state: typeof OpenCanvasGraphAnnotation.State, - config: LangGraphRunnableConfig -): Promise => { - const { modelName, modelProvider, modelConfig } = - getModelNameAndProviderFromConfig(config); - const smallModel = await initChatModel(modelName, { - modelProvider, - // temperature: 0.5, - temperature: modelConfig.temperatureRange.current, - maxTokens: modelConfig.maxTokens.current, - }); - - const store = ensureStoreInConfig(config); - const assistantId = config.configurable?.assistant_id; - if (!assistantId) { - throw new Error("`assistant_id` not found in configurable"); - } - const memoryNamespace = ["memories", assistantId]; - const memoryKey = "reflection"; - const memories = await store.get(memoryNamespace, memoryKey); - const memoriesAsString = memories?.value - ? formatReflections(memories.value as Reflections) - : "No reflections found."; - - const modelWithArtifactTool = smallModel.bindTools( - [ - { - name: "generate_artifact", - schema: z.object({ - type: z - .enum(["code", "text"]) - .describe("The content type of the artifact generated."), - language: z - .enum( - PROGRAMMING_LANGUAGES.map((lang) => lang.language) as [ - string, - ...string[], - ] - ) - .optional() - .describe( - "The language/programming language of the artifact generated.\n" + - "If generating code, it should be one of the options, or 'other'.\n" + - "If not generating code, the language should ALWAYS be 'other'." - ), - isValidReact: z - .boolean() - .optional() - .describe( - "Whether or not the generated code is valid React code. Only populate this field if generating code." - ), - artifact: z - .string() - .describe("The content of the artifact to generate."), - title: z - .string() - .describe( - "A short title to give to the artifact. Should be less than 5 words." - ), - }), - }, - ], - { tool_choice: "generate_artifact" } - ); - - const formattedNewArtifactPrompt = NEW_ARTIFACT_PROMPT.replace( - "{reflections}", - memoriesAsString - ).replace( - "{disableChainOfThought}", - modelName.includes("claude") - ? "\n\nIMPORTANT: Do NOT preform chain of thought beforehand. Instead, go STRAIGHT to generating the tool response. This is VERY important." - : "" - ); - - const response = await modelWithArtifactTool.invoke( - [ - { role: "system", content: formattedNewArtifactPrompt }, - ...state.messages, - ], - { runName: "generate_artifact" } - ); - - const newArtifactType = response.tool_calls?.[0]?.args.type; - let newArtifactContent: ArtifactCodeV3 | ArtifactMarkdownV3; - if (newArtifactType === "code") { - newArtifactContent = { - index: 1, - type: "code", - title: response.tool_calls?.[0]?.args.title, - code: response.tool_calls?.[0]?.args.artifact, - language: response.tool_calls?.[0]?.args.language, - }; - } else { - newArtifactContent = { - index: 1, - type: "text", - title: response.tool_calls?.[0]?.args.title, - fullMarkdown: response.tool_calls?.[0]?.args.artifact, - }; - } - - const newArtifact: ArtifactV3 = { - currentIndex: 1, - contents: [newArtifactContent], - }; - - return { - artifact: newArtifact, - }; -}; diff --git a/src/agent/open-canvas/nodes/generatePath.ts b/src/agent/open-canvas/nodes/generatePath.ts index 03a0350b..69b3fecb 100644 --- a/src/agent/open-canvas/nodes/generatePath.ts +++ b/src/agent/open-canvas/nodes/generatePath.ts @@ -9,6 +9,7 @@ import { OpenCanvasGraphAnnotation } from "../state"; import { z } from "zod"; import { formatArtifactContentWithTemplate, + getModelFromConfig, getModelNameAndProviderFromConfig, } from "../../utils"; import { getArtifactContent } from "../../../contexts/utils"; @@ -93,12 +94,7 @@ export const generatePath = async ( ? "rewriteArtifact" : "generateArtifact"; - const { modelName, modelProvider } = - getModelNameAndProviderFromConfig(config); - const model = await initChatModel(modelName, { - temperature: 0, - modelProvider, - }); + const model = await getModelFromConfig(config); const modelWithTool = model.withStructuredOutput( z.object({ route: z diff --git a/src/agent/open-canvas/nodes/rewrite-artifact/index.ts b/src/agent/open-canvas/nodes/rewrite-artifact/index.ts new file mode 100644 index 00000000..7615366d --- /dev/null +++ b/src/agent/open-canvas/nodes/rewrite-artifact/index.ts @@ -0,0 +1,68 @@ +import { + OpenCanvasGraphAnnotation, + OpenCanvasGraphReturnType, +} from "../../state"; +import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { optionallyUpdateArtifactMeta } from "./update-meta"; +import { buildPrompt, createNewArtifactContent, validateState } from "./utils"; +import { + getFormattedReflections, + getModelFromConfig, + optionallyGetSystemPromptFromConfig, +} from "@/agent/utils"; +import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; + +export const rewriteArtifact = async ( + state: typeof OpenCanvasGraphAnnotation.State, + config: LangGraphRunnableConfig +): Promise => { + const smallModelWithConfig = (await getModelFromConfig(config)).withConfig({ + runName: "rewrite_artifact_model_call", + }); + const memoriesAsString = await getFormattedReflections(config); + const { currentArtifactContent, recentHumanMessage } = validateState(state); + + const artifactMetaToolCall = await optionallyUpdateArtifactMeta( + state, + config + ); + const artifactType = artifactMetaToolCall?.args?.type; + const isNewType = artifactType !== currentArtifactContent.type; + + const artifactContent = isArtifactMarkdownContent(currentArtifactContent) + ? currentArtifactContent.fullMarkdown + : currentArtifactContent.code; + + const formattedPrompt = buildPrompt({ + artifactContent, + memoriesAsString, + isNewType, + artifactMetaToolCall, + }); + + const userSystemPrompt = optionallyGetSystemPromptFromConfig(config); + const fullSystemPrompt = userSystemPrompt + ? `${userSystemPrompt}\n${formattedPrompt}` + : formattedPrompt; + + const newArtifactResponse = await smallModelWithConfig.invoke([ + { role: "system", content: fullSystemPrompt }, + recentHumanMessage, + ]); + + const newArtifactContent = createNewArtifactContent({ + artifactType, + state, + currentArtifactContent, + artifactMetaToolCall, + newContent: newArtifactResponse.content as string, + }); + + return { + artifact: { + ...state.artifact, + currentIndex: state.artifact.contents.length + 1, + contents: [...state.artifact.contents, newArtifactContent], + }, + }; +}; diff --git a/src/agent/open-canvas/nodes/rewrite-artifact/schemas.ts b/src/agent/open-canvas/nodes/rewrite-artifact/schemas.ts new file mode 100644 index 00000000..080e704a --- /dev/null +++ b/src/agent/open-canvas/nodes/rewrite-artifact/schemas.ts @@ -0,0 +1,22 @@ +import { PROGRAMMING_LANGUAGES } from "@/types"; +import { z } from "zod"; + +export const OPTIONALLY_UPDATE_ARTIFACT_META_SCHEMA = z.object({ + type: z.enum(["text", "code"]).describe("The type of the artifact content."), + title: z + .string() + .optional() + .describe( + "The new title to give the artifact. ONLY update this if the user is making a request which changes the subject/topic of the artifact." + ), + language: z + .enum( + PROGRAMMING_LANGUAGES.map((lang) => lang.language) as [ + string, + ...string[], + ] + ) + .describe( + "The language of the code artifact. This should be populated with the programming language if the user is requesting code to be written, or 'other', in all other cases." + ), +}); diff --git a/src/agent/open-canvas/nodes/rewrite-artifact/update-meta.ts b/src/agent/open-canvas/nodes/rewrite-artifact/update-meta.ts new file mode 100644 index 00000000..e0e2b11c --- /dev/null +++ b/src/agent/open-canvas/nodes/rewrite-artifact/update-meta.ts @@ -0,0 +1,55 @@ +import { LangGraphRunnableConfig } from "@langchain/langgraph"; +import { OpenCanvasGraphAnnotation } from "../../state"; +import { formatArtifactContent, getModelFromConfig } from "@/agent/utils"; +import { getArtifactContent } from "@/contexts/utils"; +import { GET_TITLE_TYPE_REWRITE_ARTIFACT } from "../../prompts"; +import { OPTIONALLY_UPDATE_ARTIFACT_META_SCHEMA } from "./schemas"; +import { ToolCall } from "@langchain/core/messages/tool"; +import { getFormattedReflections } from "../../../utils"; + +export async function optionallyUpdateArtifactMeta( + state: typeof OpenCanvasGraphAnnotation.State, + config: LangGraphRunnableConfig +): Promise { + const toolCallingModel = (await getModelFromConfig(config)) + .bindTools( + [ + { + name: "optionallyUpdateArtifactMeta", + schema: OPTIONALLY_UPDATE_ARTIFACT_META_SCHEMA, + description: "Update the artifact meta information, if necessary.", + }, + ], + { tool_choice: "optionallyUpdateArtifactMeta" } + ) + .withConfig({ runName: "optionally_update_artifact_meta" }); + + const memoriesAsString = await getFormattedReflections(config); + + const currentArtifactContent = state.artifact + ? getArtifactContent(state.artifact) + : undefined; + if (!currentArtifactContent) { + throw new Error("No artifact found"); + } + + const optionallyUpdateArtifactMetaPrompt = + GET_TITLE_TYPE_REWRITE_ARTIFACT.replace( + "{artifact}", + formatArtifactContent(currentArtifactContent, true) + ).replace("{reflections}", memoriesAsString); + + const recentHumanMessage = state.messages.findLast( + (message) => message.getType() === "human" + ); + if (!recentHumanMessage) { + throw new Error("No recent human message found"); + } + + const optionallyUpdateArtifactResponse = await toolCallingModel.invoke([ + { role: "system", content: optionallyUpdateArtifactMetaPrompt }, + recentHumanMessage, + ]); + + return optionallyUpdateArtifactResponse.tool_calls?.[0]; +} diff --git a/src/agent/open-canvas/nodes/rewrite-artifact/utils.ts b/src/agent/open-canvas/nodes/rewrite-artifact/utils.ts new file mode 100644 index 00000000..3dbac450 --- /dev/null +++ b/src/agent/open-canvas/nodes/rewrite-artifact/utils.ts @@ -0,0 +1,110 @@ +import { getArtifactContent } from "@/contexts/utils"; +import { isArtifactCodeContent } from "@/lib/artifact_content_types"; +import { ArtifactCodeV3, ArtifactMarkdownV3 } from "@/types"; +import { + OPTIONALLY_UPDATE_META_PROMPT, + UPDATE_ENTIRE_ARTIFACT_PROMPT, +} from "../../prompts"; +import { OpenCanvasGraphAnnotation } from "../../state"; +import { ToolCall } from "@langchain/core/messages/tool"; + +export const validateState = ( + state: typeof OpenCanvasGraphAnnotation.State +) => { + const currentArtifactContent = state.artifact + ? getArtifactContent(state.artifact) + : undefined; + if (!currentArtifactContent) { + throw new Error("No artifact found"); + } + + const recentHumanMessage = state.messages.findLast( + (message) => message.getType() === "human" + ); + if (!recentHumanMessage) { + throw new Error("No recent human message found"); + } + + return { currentArtifactContent, recentHumanMessage }; +}; + +const buildMetaPrompt = (artifactMetaToolCall: ToolCall | undefined) => { + const titleSection = + artifactMetaToolCall?.args?.title && + artifactMetaToolCall?.args?.type !== "code" + ? `And its title is (do NOT include this in your response):\n${artifactMetaToolCall.args.title}` + : ""; + + return OPTIONALLY_UPDATE_META_PROMPT.replace( + "{artifactType}", + artifactMetaToolCall?.args?.type + ).replace("{artifactTitle}", titleSection); +}; + +interface BuildPromptArgs { + artifactContent: string; + memoriesAsString: string; + isNewType: boolean; + artifactMetaToolCall: ToolCall | undefined; +} + +export const buildPrompt = ({ + artifactContent, + memoriesAsString, + isNewType, + artifactMetaToolCall, +}: BuildPromptArgs) => { + const metaPrompt = isNewType ? buildMetaPrompt(artifactMetaToolCall) : ""; + + return UPDATE_ENTIRE_ARTIFACT_PROMPT.replace( + "{artifactContent}", + artifactContent + ) + .replace("{reflections}", memoriesAsString) + .replace("{updateMetaPrompt}", metaPrompt); +}; + +interface CreateNewArtifactContentArgs { + artifactType: string; + state: typeof OpenCanvasGraphAnnotation.State; + currentArtifactContent: ArtifactCodeV3 | ArtifactMarkdownV3; + artifactMetaToolCall: ToolCall | undefined; + newContent: string; +} + +export const createNewArtifactContent = ({ + artifactType, + state, + currentArtifactContent, + artifactMetaToolCall, + newContent, +}: CreateNewArtifactContentArgs): ArtifactCodeV3 | ArtifactMarkdownV3 => { + const baseContent = { + index: state.artifact.contents.length + 1, + title: artifactMetaToolCall?.args?.title || currentArtifactContent.title, + }; + + if (artifactType === "code") { + return { + ...baseContent, + type: "code", + language: getLanguage(artifactMetaToolCall, currentArtifactContent), + code: newContent, + }; + } + + return { + ...baseContent, + type: "text", + fullMarkdown: newContent, + }; +}; + +const getLanguage = ( + artifactMetaToolCall: ToolCall | undefined, + currentArtifactContent: ArtifactCodeV3 | ArtifactMarkdownV3 // Replace 'any' with proper type +) => + artifactMetaToolCall?.args?.programmingLanguage || + (isArtifactCodeContent(currentArtifactContent) + ? currentArtifactContent.language + : "other"); diff --git a/src/agent/open-canvas/nodes/rewriteArtifact.ts b/src/agent/open-canvas/nodes/rewriteArtifact.ts deleted file mode 100644 index 628c73ba..00000000 --- a/src/agent/open-canvas/nodes/rewriteArtifact.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { initChatModel } from "langchain/chat_models/universal"; -import { z } from "zod"; -import { getArtifactContent } from "../../../contexts/utils"; -import { - isArtifactCodeContent, - isArtifactMarkdownContent, -} from "../../../lib/artifact_content_types"; -import { - ArtifactCodeV3, - ArtifactMarkdownV3, - ArtifactV3, - PROGRAMMING_LANGUAGES, - Reflections, -} from "../../../types"; -import { - ensureStoreInConfig, - formatArtifactContent, - formatReflections, - getModelNameAndProviderFromConfig, -} from "../../utils"; -import { - GET_TITLE_TYPE_REWRITE_ARTIFACT, - OPTIONALLY_UPDATE_META_PROMPT, - UPDATE_ENTIRE_ARTIFACT_PROMPT, -} from "../prompts"; -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; - -export const rewriteArtifact = async ( - state: typeof OpenCanvasGraphAnnotation.State, - config: LangGraphRunnableConfig -): Promise => { - const optionallyUpdateArtifactMetaSchema = z.object({ - type: z - .enum(["text", "code"]) - .describe("The type of the artifact content."), - title: z - .string() - .optional() - .describe( - "The new title to give the artifact. ONLY update this if the user is making a request which changes the subject/topic of the artifact." - ), - language: z - .enum( - PROGRAMMING_LANGUAGES.map((lang) => lang.language) as [ - string, - ...string[], - ] - ) - .describe( - "The language of the code artifact. This should be populated with the programming language if the user is requesting code to be written, or 'other', in all other cases." - ), - }); - const { modelName, modelProvider, modelConfig } = - getModelNameAndProviderFromConfig(config); - const toolCallingModel = ( - await initChatModel(modelName, { - modelProvider, - temperature: 0, - // temperature: modelConfig.temperatureRange.current, - maxTokens: modelConfig.maxTokens.current, - }) - ) - .bindTools( - [ - { - name: "optionallyUpdateArtifactMeta", - schema: optionallyUpdateArtifactMetaSchema, - description: "Update the artifact meta information, if necessary.", - }, - ], - { tool_choice: "optionallyUpdateArtifactMeta" } - ) - .withConfig({ runName: "optionally_update_artifact_meta" }); - - const smallModelWithConfig = ( - await initChatModel(modelName, { - temperature: 0, - modelProvider, - }) - ).withConfig({ - runName: "rewrite_artifact_model_call", - }); - - const store = ensureStoreInConfig(config); - const assistantId = config.configurable?.assistant_id; - if (!assistantId) { - throw new Error("`assistant_id` not found in configurable"); - } - const memoryNamespace = ["memories", assistantId]; - const memoryKey = "reflection"; - const memories = await store.get(memoryNamespace, memoryKey); - const memoriesAsString = memories?.value - ? formatReflections(memories.value as Reflections) - : "No reflections found."; - - const currentArtifactContent = state.artifact - ? getArtifactContent(state.artifact) - : undefined; - if (!currentArtifactContent) { - throw new Error("No artifact found"); - } - - const optionallyUpdateArtifactMetaPrompt = - GET_TITLE_TYPE_REWRITE_ARTIFACT.replace( - "{artifact}", - formatArtifactContent(currentArtifactContent, true) - ).replace("{reflections}", memoriesAsString); - - const recentHumanMessage = state.messages.findLast( - (message) => message.getType() === "human" - ); - if (!recentHumanMessage) { - throw new Error("No recent human message found"); - } - - const optionallyUpdateArtifactResponse = await toolCallingModel.invoke([ - { role: "system", content: optionallyUpdateArtifactMetaPrompt }, - recentHumanMessage, - ]); - const artifactMetaToolCall = optionallyUpdateArtifactResponse.tool_calls?.[0]; - const artifactType = artifactMetaToolCall?.args?.type; - const isNewType = artifactType !== currentArtifactContent.type; - - const artifactContent = isArtifactMarkdownContent(currentArtifactContent) - ? currentArtifactContent.fullMarkdown - : currentArtifactContent.code; - - const formattedPrompt = UPDATE_ENTIRE_ARTIFACT_PROMPT.replace( - "{artifactContent}", - artifactContent - ) - .replace("{reflections}", memoriesAsString) - .replace( - "{updateMetaPrompt}", - isNewType - ? OPTIONALLY_UPDATE_META_PROMPT.replace( - "{artifactType}", - artifactMetaToolCall?.args?.type - ).replace( - "{artifactTitle}", - artifactMetaToolCall?.args?.title && - artifactMetaToolCall?.args?.type !== "code" - ? `And its title is (do NOT include this in your response):\n${artifactMetaToolCall?.args?.title}` - : "" - ) - : "" - ); - - const newArtifactResponse = await smallModelWithConfig.invoke([ - { role: "system", content: formattedPrompt }, - recentHumanMessage, - ]); - - let newArtifactContent: ArtifactCodeV3 | ArtifactMarkdownV3; - if (artifactType === "code") { - newArtifactContent = { - index: state.artifact.contents.length + 1, - type: "code", - title: artifactMetaToolCall?.args?.title || currentArtifactContent.title, - language: - artifactMetaToolCall?.args?.programmingLanguage || - (isArtifactCodeContent(currentArtifactContent) - ? currentArtifactContent.language - : "other"), - code: newArtifactResponse.content as string, - }; - } else { - newArtifactContent = { - index: state.artifact.contents.length + 1, - type: "text", - title: artifactMetaToolCall?.args?.title || currentArtifactContent.title, - fullMarkdown: newArtifactResponse.content as string, - }; - } - - const newArtifact: ArtifactV3 = { - ...state.artifact, - currentIndex: state.artifact.contents.length + 1, - contents: [...state.artifact.contents, newArtifactContent], - }; - - return { - artifact: newArtifact, - }; -}; diff --git a/src/agent/utils.ts b/src/agent/utils.ts index b0bd6e2f..5d248c16 100644 --- a/src/agent/utils.ts +++ b/src/agent/utils.ts @@ -2,6 +2,7 @@ import { isArtifactCodeContent } from "@/lib/artifact_content_types"; import { CustomModelConfig } from "@/types"; import { BaseStore, LangGraphRunnableConfig } from "@langchain/langgraph"; import { ArtifactCodeV3, ArtifactMarkdownV3, Reflections } from "../types"; +import { initChatModel } from "langchain/chat_models/universal"; export const formatReflections = ( reflections: Reflections, @@ -75,6 +76,24 @@ export const formatReflections = ( return styleString + "\n\n" + contentString; }; +export async function getFormattedReflections( + config: LangGraphRunnableConfig +): Promise { + const store = ensureStoreInConfig(config); + const assistantId = config.configurable?.assistant_id; + if (!assistantId) { + throw new Error("`assistant_id` not found in configurable"); + } + const memoryNamespace = ["memories", assistantId]; + const memoryKey = "reflection"; + const memories = await store.get(memoryNamespace, memoryKey); + const memoriesAsString = memories?.value + ? formatReflections(memories.value as Reflections) + : "No reflections found."; + + return memoriesAsString; +} + export const ensureStoreInConfig = ( config: LangGraphRunnableConfig ): BaseStore => { @@ -161,3 +180,21 @@ export const getModelNameAndProviderFromConfig = ( throw new Error("Unknown model provider"); }; + +export function optionallyGetSystemPromptFromConfig( + config: LangGraphRunnableConfig +): string | undefined { + return config.configurable?.systemPrompt as string | undefined; +} + +export async function getModelFromConfig( + config: LangGraphRunnableConfig, +) { + const { modelName, modelProvider, modelConfig } = + getModelNameAndProviderFromConfig(config); + return await initChatModel(modelName, { + modelProvider, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, + }); +} diff --git a/src/components/artifacts/ArtifactRenderer.tsx b/src/components/artifacts/ArtifactRenderer.tsx index 5d4e5e87..ee79da2e 100644 --- a/src/components/artifacts/ArtifactRenderer.tsx +++ b/src/components/artifacts/ArtifactRenderer.tsx @@ -117,7 +117,7 @@ function NavigateArtifactHistory(props: NavigateArtifactHistoryProps) { function ArtifactRendererComponent(props: ArtifactRendererProps) { const { graphData, - threadData: { assistantId }, + assistantsData: { selectedAssistant }, userData: { user }, } = useGraphContext(); const { @@ -354,7 +354,7 @@ function ArtifactRendererComponent(props: ArtifactRendererProps) { />
- +
diff --git a/src/components/artifacts/actions_toolbar/custom/NewCustomQuickActionDialog.tsx b/src/components/artifacts/actions_toolbar/custom/NewCustomQuickActionDialog.tsx index c1ed520e..f6210264 100644 --- a/src/components/artifacts/actions_toolbar/custom/NewCustomQuickActionDialog.tsx +++ b/src/components/artifacts/actions_toolbar/custom/NewCustomQuickActionDialog.tsx @@ -20,7 +20,7 @@ import { useState, } from "react"; import { FullPrompt } from "./FullPrompt"; -import { InlineContextTooltip } from "./PromptContextTooltip"; +import { InlineContextTooltip } from "@/components/ui/inline-context-tooltip"; import { useStore } from "@/hooks/useStore"; import { useToast } from "@/hooks/use-toast"; import { v4 as uuidv4 } from "uuid"; @@ -28,6 +28,9 @@ import { CustomQuickAction } from "@/types"; import { TighterText } from "@/components/ui/header"; import { User } from "@supabase/supabase-js"; +const CUSTOM_INSTRUCTIONS_TOOLTIP_TEXT = `This field contains the custom instructions you set, which will then be used to instruct the LLM on how to re-generate the selected artifact.`; +const FULL_PROMPT_TOOLTIP_TEXT = `This is the full prompt that will be set to the LLM when you invoke this quick action, including your custom instructions and other default context.`; + interface NewCustomQuickActionDialogProps { user: User | undefined; isEditing: boolean; @@ -224,7 +227,11 @@ export function NewCustomQuickActionDialog(
Custom instructions - + +

+ {CUSTOM_INSTRUCTIONS_TOOLTIP_TEXT} +

+