diff --git a/package.json b/package.json index dbed37b..6c72065 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 052961d..d1fe99a 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/generate-artifact/index.ts b/src/agent/open-canvas/nodes/generate-artifact/index.ts index 1386c6d..0977946 100644 --- a/src/agent/open-canvas/nodes/generate-artifact/index.ts +++ b/src/agent/open-canvas/nodes/generate-artifact/index.ts @@ -21,7 +21,7 @@ export const generateArtifact = async ( config: LangGraphRunnableConfig ): Promise => { const { modelName } = getModelNameAndProviderFromConfig(config); - const smallModel = await getModelFromConfig(config, 0.5); + const smallModel = await getModelFromConfig(config); const modelWithArtifactTool = smallModel.bindTools( [ diff --git a/src/agent/open-canvas/nodes/generatePath.ts b/src/agent/open-canvas/nodes/generatePath.ts index 96b2108..b66f0fd 100644 --- a/src/agent/open-canvas/nodes/generatePath.ts +++ b/src/agent/open-canvas/nodes/generatePath.ts @@ -9,10 +9,9 @@ import { OpenCanvasGraphAnnotation } from "../state"; import { z } from "zod"; import { formatArtifactContentWithTemplate, - getModelNameAndProviderFromConfig, + getModelFromConfig, } from "../../utils"; import { getArtifactContent } from "../../../contexts/utils"; -import { initChatModel } from "langchain/chat_models/universal"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; /** @@ -22,7 +21,6 @@ export const generatePath = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ) => { - console.log("config.configurable!!", config.configurable); if (state.highlightedCode) { return { next: "updateArtifact", @@ -94,12 +92,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/replyToGeneralInput.ts b/src/agent/open-canvas/nodes/replyToGeneralInput.ts index 5cd71d2..fbca61a 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/rewriteArtifactTheme.ts b/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts index 0d5c73e..43bdad4 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 b1203c8..e098bf6 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 74f97b6..65b9f52 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 e37f441..3a9c133 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 37b88de..e4172a5 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"; import { initChatModel } from "langchain/chat_models/universal"; @@ -133,33 +134,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, }; } @@ -172,14 +187,12 @@ export function optionallyGetSystemPromptFromConfig( return config.configurable?.systemPrompt as string | undefined; } -export async function getModelFromConfig( - config: LangGraphRunnableConfig, - temperature = 0 -) { - const { modelName, modelProvider } = +export async function getModelFromConfig(config: LangGraphRunnableConfig) { + const { modelName, modelProvider, modelConfig } = getModelNameAndProviderFromConfig(config); return await initChatModel(modelName, { - temperature, modelProvider, + temperature: modelConfig.temperatureRange.current, + maxTokens: modelConfig.maxTokens.current, }); } diff --git a/src/components/canvas/canvas.tsx b/src/components/canvas/canvas.tsx index f8b3696..5a8cc64 100644 --- a/src/components/canvas/canvas.tsx +++ b/src/components/canvas/canvas.tsx @@ -1,8 +1,12 @@ "use client"; import { ArtifactRenderer } from "@/components/artifacts/ArtifactRenderer"; -import { ContentComposerChatInterface } from "./content-composer"; -import { ALL_MODEL_NAMES } from "@/constants"; +import { + ALL_MODEL_NAMES, + DEFAULT_MODEL_CONFIG, + DEFAULT_MODEL_NAME, +} 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 +14,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); @@ -88,9 +93,22 @@ export function CanvasComponent() { // Chat should only be "started" if there are messages present if ((thread.values as Record)?.messages?.length) { setChatStarted(true); - setModelName( - thread?.metadata?.customModelName as ALL_MODEL_NAMES - ); + if (thread?.metadata?.customModelName) { + setModelName( + thread.metadata.customModelName as ALL_MODEL_NAMES + ); + } else { + setModelName(DEFAULT_MODEL_NAME); + } + + if (thread?.metadata?.modelConfig) { + setModelConfig( + thread?.metadata?.customModelName as ALL_MODEL_NAMES, + thread.metadata?.modelConfig as CustomModelConfig + ); + } else { + setModelConfig(DEFAULT_MODEL_NAME, DEFAULT_MODEL_CONFIG); + } } else { setChatStarted(false); } diff --git a/src/components/chat-interface/model-selector/constants.ts b/src/components/chat-interface/model-selector/constants.ts new file mode 100644 index 0000000..1424eaa --- /dev/null +++ b/src/components/chat-interface/model-selector/constants.ts @@ -0,0 +1,13 @@ +import { + ANTHROPIC_MODELS, + OPENAI_MODELS, + FIREWORKS_MODELS, + GEMINI_MODELS, +} from "@/constants"; + +export const ALL_MODELS = [ + ...ANTHROPIC_MODELS, + ...OPENAI_MODELS, + ...FIREWORKS_MODELS, + ...GEMINI_MODELS, +]; diff --git a/src/components/chat-interface/model-selector/index.tsx b/src/components/chat-interface/model-selector/index.tsx index a7a6915..8d0672d 100644 --- a/src/components/chat-interface/model-selector/index.tsx +++ b/src/components/chat-interface/model-selector/index.tsx @@ -1,62 +1,61 @@ "use client"; import LLMIcon from "@/components/icons/svg/LLMIcon.svg"; -import NextImage from "next/image"; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; + Command, + CommandGroup, + CommandItem, + CommandList, +} from "@/components/ui/command"; import { - ALL_MODEL_NAMES, - ANTHROPIC_MODELS, - OPENAI_MODELS, - FIREWORKS_MODELS, - GEMINI_MODELS, - LS_HAS_SEEN_MODEL_DROPDOWN_ALERT, -} from "@/constants"; -import { Dispatch, SetStateAction, useState } from "react"; + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { ALL_MODEL_NAMES, ALL_MODELS } from "@/constants"; +import { cn } from "@/lib/utils"; +import { CustomModelConfig } from "@/types"; +import { CaretSortIcon, GearIcon } from "@radix-ui/react-icons"; +import { Check } from "lucide-react"; +import NextImage from "next/image"; +import { useCallback, useState } from "react"; import { AlertNewModelSelectorFeature } from "./alert-new-model-selector"; +import { ModelConfigPanel } from "./model-config-pannel"; import { IsNewBadge } from "./new-badge"; -const allModels = [ - ...ANTHROPIC_MODELS, - ...OPENAI_MODELS, - ...FIREWORKS_MODELS, - ...GEMINI_MODELS, -]; - -const modelNameToLabel = (modelName: ALL_MODEL_NAMES) => { - const model = allModels.find((m) => m.name === modelName); - return model?.label ?? modelName; -}; - interface ModelSelectorProps { modelName: ALL_MODEL_NAMES; - setModelName: Dispatch>; + setModelName: (name: ALL_MODEL_NAMES) => void; chatStarted: boolean; + modelConfig: CustomModelConfig; + setModelConfig: ( + modelName: ALL_MODEL_NAMES, + config: CustomModelConfig + ) => void; + modelConfigs: Record; } -export default function ModelSelector(props: ModelSelectorProps) { - const { modelName, setModelName } = props; +export default function ModelSelector({ + chatStarted, + modelName, + setModelConfig, + setModelName, + modelConfigs, +}: ModelSelectorProps) { const [showAlert, setShowAlert] = useState(false); + const [open, setOpen] = useState(false); + const [openConfigModelId, setOpenConfigModelId] = + useState(null); - const isSelectedModelNew = !!allModels.find( - (model) => model.name === modelName && model.isNew + const handleModelChange = useCallback( + async (newModel: ALL_MODEL_NAMES) => { + setModelName(newModel); + setOpen(false); + }, + [setModelName] ); - 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) => { + const allAllowedModels = ALL_MODELS.filter((model) => { if ( model.name.includes("fireworks/") && process.env.NEXT_PUBLIC_FIREWORKS_ENABLED === "false" @@ -86,42 +85,89 @@ export default function ModelSelector(props: ModelSelectorProps) { return true; }); + const selectedModelLabel = + ALL_MODELS.find((m) => m.name === modelName)?.label || modelName; + const isSelectedModelNew = ALL_MODELS.some( + (m) => m.name === modelName && m.isNew + ); + return (
- + + +
+ + + {selectedModelLabel} + {isSelectedModelNew && } + + +
+
+ + + + {allAllowedModels.map((model) => ( + + + + + {model.label} + {model.isNew && } + + + {openConfigModelId === model.name ? ( + + setOpenConfigModelId(open ? model.name : null) + } + onClick={(e) => e.stopPropagation()} + setModelConfig={setModelConfig} + /> + ) : ( + + )} + + + ))} + + + +
diff --git a/src/components/chat-interface/model-selector/model-config-pannel.tsx b/src/components/chat-interface/model-selector/model-config-pannel.tsx new file mode 100644 index 0000000..fb9df00 --- /dev/null +++ b/src/components/chat-interface/model-selector/model-config-pannel.tsx @@ -0,0 +1,150 @@ +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { CustomModelConfig, ModelConfigurationParams } from "@/types"; + +import { Button } from "@/components/ui/button"; +import { Slider } from "@/components/ui/slider"; +import { ALL_MODEL_NAMES } from "@/constants"; +import { cn } from "@/lib/utils"; +import { GearIcon, ResetIcon } from "@radix-ui/react-icons"; +import { useCallback } from "react"; + +interface ModelConfigPanelProps { + model: ModelConfigurationParams; + modelConfig: CustomModelConfig; + className?: string; + isOpen: boolean; + onOpenChange: (open: boolean) => void; + onClick: (e: any) => any; + setModelConfig: ( + modelName: ALL_MODEL_NAMES, + config: CustomModelConfig + ) => void; +} + +export function ModelConfigPanel({ + model, + modelConfig, + className, + isOpen, + onOpenChange, + onClick, + setModelConfig, +}: ModelConfigPanelProps) { + console.log("modelConfig ", modelConfig); + + const handleTemperatureChange = useCallback( + (value: number[]) => { + setModelConfig(model.name, { + ...modelConfig, + temperatureRange: { + ...modelConfig.temperatureRange, + current: value[0], + }, + }); + }, + [setModelConfig, modelConfig, model] + ); + + const handleMaxTokensChange = useCallback( + (value: number[]) => { + setModelConfig(model.name, { + ...modelConfig, + maxTokens: { + ...modelConfig.maxTokens, + current: value[0], + }, + }); + }, + [setModelConfig, modelConfig, model] + ); + + const handleReset = useCallback(() => { + setModelConfig(model.name, { + ...modelConfig, + temperatureRange: { + ...modelConfig.temperatureRange, + current: modelConfig.temperatureRange.default, + }, + maxTokens: { + ...modelConfig.maxTokens, + current: modelConfig.maxTokens.default, + }, + }); + }, [setModelConfig, modelConfig, model]); + + return ( + + + + + e.stopPropagation()} + > +
+ + + +
+
+
+ ); +} + +const ModelSettingSlider = ({ + title, + description, + value, + range, + onChange, +}: { + title: string; + description: string; + value: number; + range: { min: number; max: number; step: number }; + onChange: (value: number[]) => void; +}) => ( +
+

{title}

+

{description}

+ +
{value}
+
+); diff --git a/src/components/chat-interface/thread.tsx b/src/components/chat-interface/thread.tsx index eaf5b24..1b43e79 100644 --- a/src/components/chat-interface/thread.tsx +++ b/src/components/chat-interface/thread.tsx @@ -1,19 +1,19 @@ +import { useGraphContext } from "@/contexts/GraphContext"; +import { useToast } from "@/hooks/use-toast"; +import { ProgrammingLanguageOptions } from "@/types"; import { ThreadPrimitive } from "@assistant-ui/react"; +import { Thread as ThreadType } from "@langchain/langgraph-sdk"; import { ArrowDownIcon, SquarePen } from "lucide-react"; import { Dispatch, FC, SetStateAction } from "react"; -import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button"; -import { ProgrammingLanguageOptions } from "@/types"; -import ModelSelector from "./model-selector"; import { ReflectionsDialog } from "../reflections-dialog/ReflectionsDialog"; -import { ThreadHistory } from "./thread-history"; +import { useLangSmithLinkToolUI } from "../tool-hooks/LangSmithLinkToolUI"; +import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button"; import { TighterText } from "../ui/header"; -import { Thread as ThreadType } from "@langchain/langgraph-sdk"; -import { ThreadWelcome } from "./welcome"; import { Composer } from "./composer"; import { AssistantMessage, UserMessage } from "./messages"; -import { useToast } from "@/hooks/use-toast"; -import { useLangSmithLinkToolUI } from "../tool-hooks/LangSmithLinkToolUI"; -import { useGraphContext } from "@/contexts/GraphContext"; +import ModelSelector from "./model-selector"; +import { ThreadHistory } from "./thread-history"; +import { ThreadWelcome } from "./welcome"; const ThreadScrollToBottom: FC = () => { return ( @@ -50,7 +50,14 @@ export const Thread: FC = (props: ThreadProps) => { const { toast } = useToast(); const { userData: { user }, - threadData: { createThread, modelName, setModelName }, + threadData: { + createThread, + modelName, + setModelName, + modelConfig, + setModelConfig, + modelConfigs, + }, assistantsData: { selectedAssistant }, graphData: { clearState, runId, feedbackSubmitted, setFeedbackSubmitted }, } = useGraphContext(); @@ -68,9 +75,10 @@ export const Thread: FC = (props: ThreadProps) => { return; } setModelName(modelName); + setModelConfig(modelName, 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", @@ -93,6 +101,9 @@ export const Thread: FC = (props: ThreadProps) => { chatStarted={false} modelName={modelName} setModelName={setModelName} + modelConfig={modelConfig} + setModelConfig={setModelConfig} + modelConfigs={modelConfigs} /> )} @@ -142,6 +153,9 @@ export const Thread: FC = (props: ThreadProps) => { chatStarted={true} modelName={modelName} setModelName={setModelName} + modelConfig={modelConfig} + setModelConfig={setModelConfig} + modelConfigs={modelConfigs} /> diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx new file mode 100644 index 0000000..8f23c71 --- /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 0000000..b7a19e9 --- /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 3fc0ab5..db107b3 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,7 @@ +import { CustomModelConfig, ModelConfigurationParams } from "./types"; + export const LANGGRAPH_API_URL = - process.env.LANGGRAPH_API_URL ?? "http://localhost:53404"; + process.env.LANGGRAPH_API_URL ?? "http://localhost:54646"; // v2 is tied to the 'open-canvas-prod' deployment. export const ASSISTANT_ID_COOKIE = "oc_assistant_id_v2"; // export const ASSISTANT_ID_COOKIE = "oc_assistant_id"; @@ -25,45 +27,123 @@ 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: 4096, + current: 4096, + }, + }, isNew: false, }, ]; -export const ANTHROPIC_MODELS = [ +export const ANTHROPIC_MODELS: ModelConfigurationParams[] = [ { name: "claude-3-5-haiku-20241022", label: "Claude 3.5 Haiku", + config: { + provider: "anthropic", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 4096, + default: 4096, + current: 4096, + }, + }, isNew: true, }, { name: "claude-3-haiku-20240307", label: "Claude 3 Haiku (old)", + config: { + provider: "anthropic", + temperatureRange: { + min: 0, + max: 1, + default: 0.5, + current: 0.5, + }, + maxTokens: { + min: 1, + max: 4096, + default: 4096, + current: 4096, + }, + }, isNew: false, }, - // { - // 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: 4096, + current: 4096, + }, + }, isNew: false, }, ]; -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: 4096, + current: 4096, + }, + }, isNew: false, }, ]; -export const DEFAULT_MODEL_NAME: ALL_MODEL_NAMES = "gpt-4o-mini"; + +export const ALL_MODELS: ModelConfigurationParams[] = [ + ...OPENAI_MODELS, + ...ANTHROPIC_MODELS, + ...FIREWORKS_MODELS, + ...GEMINI_MODELS, +]; + 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"]; @@ -73,3 +153,11 @@ export type ALL_MODEL_NAMES = | ANTHROPIC_MODEL_NAMES | FIREWORKS_MODEL_NAMES | GEMINI_MODEL_NAMES; + +export const DEFAULT_MODEL_NAME: ALL_MODEL_NAMES = OPENAI_MODELS[0].name; + +export const DEFAULT_MODEL_CONFIG: CustomModelConfig = { + ...OPENAI_MODELS[0].config, + temperatureRange: { ...OPENAI_MODELS[0].config.temperatureRange }, + maxTokens: { ...OPENAI_MODELS[0].config.maxTokens }, +}; diff --git a/src/contexts/GraphContext.tsx b/src/contexts/GraphContext.tsx index 6bcb939..7104956 100644 --- a/src/contexts/GraphContext.tsx +++ b/src/contexts/GraphContext.tsx @@ -1,25 +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_MODEL_CONFIG, + DEFAULT_MODEL_NAME, + THREAD_ID_COOKIE_NAME, +} from "@/constants"; +import { CustomModelConfig } from "@/types"; + +import { useToast } from "@/hooks/use-toast"; +import { useAssistants } from "@/hooks/useAssistants"; +import { useRuns } from "@/hooks/useRuns"; import { useThread } from "@/hooks/useThread"; -import { debounce } from "lodash"; +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 { ArtifactLengthOptions, ArtifactToolResponse, @@ -33,25 +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"; -import { useAssistants } from "@/hooks/useAssistants"; + 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; @@ -310,6 +313,7 @@ export function GraphProvider({ children }: { children: ReactNode }) { config: { configurable: { customModelName: threadData.modelName, + modelConfig: threadData.modelConfigs[threadData.modelName], }, }, } @@ -879,8 +883,13 @@ export function GraphProvider({ children }: { children: ReactNode }) { threadData.setModelName( thread.metadata.customModelName as ALL_MODEL_NAMES ); + threadData.setModelConfig( + thread.metadata.customModelName as ALL_MODEL_NAMES, + thread.metadata.modelConfig as CustomModelConfig + ); } else { threadData.setModelName(DEFAULT_MODEL_NAME); + threadData.setModelConfig(DEFAULT_MODEL_NAME, DEFAULT_MODEL_CONFIG); } const castValues: { diff --git a/src/hooks/useThread.tsx b/src/hooks/useThread.tsx index 4cc6e47..0e0fcfa 100644 --- a/src/hooks/useThread.tsx +++ b/src/hooks/useThread.tsx @@ -1,10 +1,13 @@ import { ALL_MODEL_NAMES, + ALL_MODELS, + DEFAULT_MODEL_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"; @@ -16,22 +19,58 @@ export function useThread() { const [modelName, setModelName] = useState(DEFAULT_MODEL_NAME); + const [modelConfigs, setModelConfigs] = useState< + Record + >(() => { + // Initialize with default configs for all models + const initialConfigs: Record = + {} as Record; + ALL_MODELS.forEach((model) => { + initialConfigs[model.name] = { + ...model.config, + temperatureRange: { ...model.config.temperatureRange }, + maxTokens: { ...model.config.maxTokens }, + }; + }); + return initialConfigs; + }); + + const setModelConfig = ( + modelName: ALL_MODEL_NAMES, + config: CustomModelConfig + ) => { + setModelConfigs((prevConfigs) => ({ + ...prevConfigs, + [modelName]: { + ...config, + temperatureRange: { ...config.temperatureRange }, + maxTokens: { ...config.maxTokens }, + }, + })); + }; + + const modelConfig = modelConfigs[modelName]; + const createThread = async ( customModelName: ALL_MODEL_NAMES = DEFAULT_MODEL_NAME, + customModelConfig: CustomModelConfig = modelConfig, userId: string ): Promise => { const client = createClient(); - console.log("creating thread!", customModelName); + try { const thread = await client.threads.create({ metadata: { supabase_user_id: userId, customModelName, + modelConfig: customModelConfig, }, }); setThreadId(thread.thread_id); setCookie(THREAD_ID_COOKIE_NAME, thread.thread_id); setModelName(customModelName); + console.log("setting model config", customModelConfig); + setModelConfig(customModelName, customModelConfig); await getUserThreads(userId); return thread; } catch (e) { @@ -67,7 +106,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; } @@ -82,7 +121,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; } }; @@ -156,7 +195,20 @@ export function useThread() { const client = createClient(); const thread = await client.threads.get(id); if (thread.metadata && thread.metadata.customModelName) { - setModelName(thread.metadata.customModelName as ALL_MODEL_NAMES); + if (thread.metadata.customModelName) { + setModelName(thread.metadata.customModelName as ALL_MODEL_NAMES); + } else { + setModelName(DEFAULT_MODEL_NAME); + } + + if (thread.metadata.modelConfig) { + setModelConfig( + thread.metadata.customModelName as ALL_MODEL_NAMES, + thread.metadata.modelConfig as CustomModelConfig + ); + } else { + setModelConfig(DEFAULT_MODEL_NAME, DEFAULT_MODEL_CONFIG); + } } return thread; } catch (e) { @@ -180,7 +232,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 { @@ -195,6 +247,8 @@ export function useThread() { userThreads, isUserThreadsLoading, modelName, + modelConfig, + modelConfigs, createThread, clearThreadsWithNoValues, searchOrCreateThread, @@ -203,5 +257,6 @@ export function useThread() { getThreadById, setThreadId, setModelName, + setModelConfig, }; } diff --git a/src/types.ts b/src/types.ts index 22fbd6c..036e6b1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -265,3 +265,26 @@ 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; + isNew: boolean; +} diff --git a/yarn.lock b/yarn.lock index e044054..0174f30 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" @@ -1011,6 +1018,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" @@ -1067,11 +1081,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" @@ -1082,6 +1110,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" @@ -1107,6 +1156,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" @@ -1142,6 +1203,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" @@ -1152,6 +1220,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" @@ -1181,6 +1259,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" @@ -1219,6 +1305,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" @@ -1256,6 +1362,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" @@ -1272,6 +1386,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" @@ -1288,6 +1411,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" @@ -1389,6 +1520,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" @@ -1473,11 +1612,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" @@ -1485,6 +1639,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" @@ -1492,6 +1654,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" @@ -2747,6 +2916,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" @@ -6682,7 +6859,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== @@ -6690,6 +6867,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" @@ -7262,8 +7450,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== @@ -7351,8 +7547,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==