diff --git a/src/agent/open-canvas/nodes/customAction.ts b/src/agent/open-canvas/nodes/customAction.ts index 4013400a..76e8d86b 100644 --- a/src/agent/open-canvas/nodes/customAction.ts +++ b/src/agent/open-canvas/nodes/customAction.ts @@ -16,8 +16,8 @@ import { } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; import { BaseMessage } from "@langchain/core/messages"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { isArtifactMarkdownContent } from "../../../lib/artifact_content_types"; const formatMessages = (messages: BaseMessage[]): string => messages diff --git a/src/agent/open-canvas/nodes/generateFollowup.ts b/src/agent/open-canvas/nodes/generateFollowup.ts index 0a57525e..f46946fd 100644 --- a/src/agent/open-canvas/nodes/generateFollowup.ts +++ b/src/agent/open-canvas/nodes/generateFollowup.ts @@ -8,8 +8,8 @@ import { Reflections, } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { isArtifactMarkdownContent } from "../../../lib/artifact_content_types"; /** * Generate a followup message after generating or updating an artifact. diff --git a/src/agent/open-canvas/nodes/generatePath.ts b/src/agent/open-canvas/nodes/generatePath.ts index a4eeb9a8..6ac8ea5a 100644 --- a/src/agent/open-canvas/nodes/generatePath.ts +++ b/src/agent/open-canvas/nodes/generatePath.ts @@ -9,8 +9,8 @@ import { import { OpenCanvasGraphAnnotation } from "../state"; import { z } from "zod"; import { formatArtifactContentWithTemplate } from "../../utils"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { ArtifactCodeV3, ArtifactMarkdownV3 } from "@/types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { ArtifactCodeV3, ArtifactMarkdownV3 } from "../../../types"; /** * Routes to the proper node in the graph based on the user's query. diff --git a/src/agent/open-canvas/nodes/respondToQuery.ts b/src/agent/open-canvas/nodes/respondToQuery.ts index dddbe4f6..43945562 100644 --- a/src/agent/open-canvas/nodes/respondToQuery.ts +++ b/src/agent/open-canvas/nodes/respondToQuery.ts @@ -12,7 +12,7 @@ import { Reflections, } from "../../../types"; import { CURRENT_ARTIFACT_PROMPT, NO_ARTIFACT_PROMPT } from "../prompts"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; /** * Generate responses to questions. Does not generate artifacts. diff --git a/src/agent/open-canvas/nodes/rewriteArtifact.ts b/src/agent/open-canvas/nodes/rewriteArtifact.ts index 4bbb3f91..ac66fd84 100644 --- a/src/agent/open-canvas/nodes/rewriteArtifact.ts +++ b/src/agent/open-canvas/nodes/rewriteArtifact.ts @@ -19,11 +19,11 @@ import { } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; import { z } from "zod"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; import { isArtifactCodeContent, isArtifactMarkdownContent, -} from "@/lib/artifact_content_types"; +} from "../../../lib/artifact_content_types"; export const rewriteArtifact = async ( state: typeof OpenCanvasGraphAnnotation.State, diff --git a/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts b/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts index 158546ca..4d550b83 100644 --- a/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts +++ b/src/agent/open-canvas/nodes/rewriteArtifactTheme.ts @@ -10,8 +10,8 @@ import { import { ensureStoreInConfig, formatReflections } from "../../utils"; import { ArtifactV3, Reflections } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { isArtifactMarkdownContent } from "../../../lib/artifact_content_types"; export const rewriteArtifactTheme = async ( state: typeof OpenCanvasGraphAnnotation.State, diff --git a/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts b/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts index 4188261a..9751fcb8 100644 --- a/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts +++ b/src/agent/open-canvas/nodes/rewriteCodeArtifactTheme.ts @@ -7,8 +7,8 @@ import { PORT_LANGUAGE_CODE_ARTIFACT_PROMPT, } from "../prompts"; import { ArtifactCodeV3, ArtifactV3 } from "../../../types"; -import { isArtifactCodeContent } from "@/lib/artifact_content_types"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; +import { isArtifactCodeContent } from "../../../lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; export const rewriteCodeArtifactTheme = async ( state: typeof OpenCanvasGraphAnnotation.State diff --git a/src/agent/open-canvas/nodes/updateArtifact.ts b/src/agent/open-canvas/nodes/updateArtifact.ts index 193ff6f8..53f85b78 100644 --- a/src/agent/open-canvas/nodes/updateArtifact.ts +++ b/src/agent/open-canvas/nodes/updateArtifact.ts @@ -4,8 +4,8 @@ import { UPDATE_HIGHLIGHTED_ARTIFACT_PROMPT } from "../prompts"; import { ensureStoreInConfig, formatReflections } from "../../utils"; import { ArtifactCodeV3, ArtifactV3, Reflections } from "../../../types"; import { LangGraphRunnableConfig } from "@langchain/langgraph"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactCodeContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { isArtifactCodeContent } from "../../../lib/artifact_content_types"; /** * Update an existing artifact based on the user's query. diff --git a/src/agent/open-canvas/nodes/updateHighlightedText.ts b/src/agent/open-canvas/nodes/updateHighlightedText.ts index 7082c330..be581e08 100644 --- a/src/agent/open-canvas/nodes/updateHighlightedText.ts +++ b/src/agent/open-canvas/nodes/updateHighlightedText.ts @@ -1,8 +1,8 @@ import { ChatOpenAI } from "@langchain/openai"; import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; import { ArtifactMarkdownV3 } from "../../../types"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../../hooks/use-graph/utils"; +import { isArtifactMarkdownContent } from "../../../lib/artifact_content_types"; 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. diff --git a/src/agent/reflection/index.ts b/src/agent/reflection/index.ts index 3ec912dd..5d9b8d9c 100644 --- a/src/agent/reflection/index.ts +++ b/src/agent/reflection/index.ts @@ -9,8 +9,8 @@ import { ArtifactCodeV3, ArtifactMarkdownV3, Reflections } from "../../types"; import { REFLECT_SYSTEM_PROMPT, REFLECT_USER_PROMPT } from "./prompts"; import { z } from "zod"; import { ensureStoreInConfig, formatReflections } from "../utils"; -import { getArtifactContent } from "@/hooks/use-graph/utils"; -import { isArtifactMarkdownContent } from "@/lib/artifact_content_types"; +import { getArtifactContent } from "../../hooks/use-graph/utils"; +import { isArtifactMarkdownContent } from "../../lib/artifact_content_types"; export const reflect = async ( state: typeof ReflectionGraphAnnotation.State, diff --git a/src/components/Canvas.tsx b/src/components/Canvas.tsx index 31928adc..da86a947 100644 --- a/src/components/Canvas.tsx +++ b/src/components/Canvas.tsx @@ -54,6 +54,7 @@ export function Canvas(props: CanvasProps) { setUpdateRenderedArtifactRequired, isArtifactSaved, firstTokenReceived, + selectedBlocks, } = useGraph({ userId: props.user.id, threadId, @@ -200,6 +201,7 @@ export function Canvas(props: CanvasProps) { artifact={artifact} setArtifact={setArtifact} setSelectedBlocks={setSelectedBlocks} + selectedBlocks={selectedBlocks} assistantId={assistantId} handleGetReflections={getReflections} handleDeleteReflections={deleteReflections} diff --git a/src/components/artifacts/ArtifactRenderer.tsx b/src/components/artifacts/ArtifactRenderer.tsx index 021aeda4..f9050ac4 100644 --- a/src/components/artifacts/ArtifactRenderer.tsx +++ b/src/components/artifacts/ArtifactRenderer.tsx @@ -56,6 +56,7 @@ export interface ArtifactRendererProps { reflections: (Reflections & { updatedAt: Date }) | undefined; handleDeleteReflections: () => Promise; handleGetReflections: () => Promise; + selectedBlocks: TextHighlight | undefined; setSelectedBlocks: Dispatch>; isStreaming: boolean; updateRenderedArtifactRequired: boolean; @@ -273,6 +274,13 @@ export function ArtifactRenderer(props: ArtifactRendererProps) { } }, [isSelectionActive, selectionBox]); + useEffect(() => { + if (!!props.selectedBlocks && !isSelectionActive) { + // Selection is not active but selected blocks are present. Clear them. + props.setSelectedBlocks(undefined); + } + }, [props.selectedBlocks, isSelectionActive]); + let currentArtifactContent: ArtifactCodeV3 | ArtifactMarkdownV3 | undefined = undefined; try { @@ -505,15 +513,24 @@ export function ArtifactRenderer(props: ArtifactRendererProps) { )} {currentArtifactContent.type === "text" ? ( - + ) : null} {currentArtifactContent.type === "code" ? ( void }; +type SharedComponentProps = { + handleClose: () => void; + language: ProgrammingLanguageOptions; + streamMessage: (input: GraphInput) => Promise; +}; type ToolbarOption = { id: string; @@ -24,6 +20,7 @@ type ToolbarOption = { }; export interface CodeToolbarProps { + isTextSelected: boolean; language: ProgrammingLanguageOptions; streamMessage: (input: GraphInput) => Promise; } @@ -81,6 +78,7 @@ export function CodeToolBar(props: CodeToolbarProps) { const toggleExpand = (event: React.MouseEvent) => { event.stopPropagation(); + if (props.isTextSelected) return; setIsExpanded(!isExpanded); setActiveOption(null); }; @@ -151,9 +149,16 @@ export function CodeToolBar(props: CodeToolbarProps) { ) : ( diff --git a/src/components/artifacts/actions_toolbar/custom/index.tsx b/src/components/artifacts/actions_toolbar/custom/index.tsx index 706dd23a..25540982 100644 --- a/src/components/artifacts/actions_toolbar/custom/index.tsx +++ b/src/components/artifacts/actions_toolbar/custom/index.tsx @@ -23,17 +23,20 @@ import { cn } from "@/lib/utils"; import { useToast } from "@/hooks/use-toast"; export interface CustomQuickActionsProps { + isTextSelected: boolean; assistantId: string | undefined; userId: string; streamMessage: (input: GraphInput) => Promise; } const DropdownMenuItemWithDelete = ({ + disabled, title, onDelete, onEdit, onClick, }: { + disabled: boolean; title: string; onDelete: () => Promise; onEdit: () => void; @@ -47,10 +50,15 @@ const DropdownMenuItemWithDelete = ({ onMouseEnter={() => setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} > - + {title} + { + if (props.isTextSelected) return; + setOpen(o); + }} + > @@ -174,6 +196,7 @@ export function CustomQuickActions(props: CustomQuickActionsProps) { {customQuickActions.map((action) => ( await handleDelete(action.id)} title={action.title} onClick={async () => await handleQuickActionClick(action.id)} @@ -184,6 +207,7 @@ export function CustomQuickActions(props: CustomQuickActionsProps) { )} diff --git a/src/components/artifacts/actions_toolbar/text/index.tsx b/src/components/artifacts/actions_toolbar/text/index.tsx index f76cef33..e2890841 100644 --- a/src/components/artifacts/actions_toolbar/text/index.tsx +++ b/src/components/artifacts/actions_toolbar/text/index.tsx @@ -8,7 +8,10 @@ import { GraphInput } from "@/hooks/use-graph/useGraph"; import { TooltipIconButton } from "@/components/ui/assistant-ui/tooltip-icon-button"; import { MagicPencilSVG } from "@/components/icons/magic_pencil"; -type SharedComponentProps = ActionsToolbarProps & { handleClose: () => void }; +type SharedComponentProps = { + handleClose: () => void; + streamMessage: (input: GraphInput) => Promise; +}; type ToolbarOption = { id: string; @@ -18,6 +21,7 @@ type ToolbarOption = { }; export interface ActionsToolbarProps { + isTextSelected: boolean; streamMessage: (input: GraphInput) => Promise; } @@ -74,6 +78,7 @@ export function ActionsToolbar(props: ActionsToolbarProps) { const toggleExpand = (event: React.MouseEvent) => { event.stopPropagation(); + if (props.isTextSelected) return; setIsExpanded(!isExpanded); setActiveOption(null); }; @@ -134,9 +139,16 @@ export function ActionsToolbar(props: ActionsToolbarProps) { ) : ( diff --git a/src/constants.ts b/src/constants.ts index ce775e06..67ad429e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,5 @@ export const LANGGRAPH_API_URL = - process.env.LANGGRAPH_API_URL ?? "http://localhost:65336"; + process.env.LANGGRAPH_API_URL ?? "http://localhost:53974"; // 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"; diff --git a/yarn.lock b/yarn.lock index e820e96c..7545cbf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -661,10 +661,10 @@ zod "^3.22.4" zod-to-json-schema "^3.22.3" -"@langchain/langgraph-checkpoint@~0.0.9": - version "0.0.9" - resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.9.tgz#fdeb7654b112831161093d2867323e0450706ad8" - integrity sha512-9KrTxnKqTCRDxYOsvQ4UOuM878S1Sp4ZUejfGBdZc9yaWGzRGV4aEYJGt8GDSBwBUYd7gz2gNi+q4xtxvwIZig== +"@langchain/langgraph-checkpoint@~0.0.10": + version "0.0.11" + resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.11.tgz#65c40bc175faca98ed0901df9e76682585710e8d" + integrity sha512-nroHHkAi/UPn9LqqZcgOydfB8qZw5TXuXDFc43MIydnW4lb8m9hVHnQ3lgb2WGSgtbZJnsIx0TzL19oemJBRKg== dependencies: uuid "^10.0.0" @@ -679,11 +679,11 @@ uuid "^9.0.0" "@langchain/langgraph@^0.2.10": - version "0.2.10" - resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.10.tgz#f026b132c5e5e01bd91803bd0124c94bdad6076a" - integrity sha512-xkWkcpngcpz32nglzQyX2SyS00I+h2Ao2XjTxtONCmPJR6N4HCXJzgpEekpvUeCN1XtggWGBMWNBb75Z8CgGfQ== + version "0.2.17" + resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.17.tgz#e9b0e5da8e7d6d0a93d415dbdd6be797effbdd19" + integrity sha512-BeFs7eO5Rg0BHH03HBjxV2BYZrAsaYKFBCKhTYvAr9x5EQ8jGrV2h7tZOZJk2T7wT2QSF+2AwpFXkwbQBT1ohQ== dependencies: - "@langchain/langgraph-checkpoint" "~0.0.9" + "@langchain/langgraph-checkpoint" "~0.0.10" double-ended-queue "^2.1.0-0" uuid "^10.0.0" zod "^3.23.8"