diff --git a/package.json b/package.json index 2188acd7..9b0f3a6d 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "lucide-react": "^0.441.0", "next": "14.2.7", "react": "^18", + "react-colorful": "^5.6.1", "react-dom": "^18", "react-icons": "^5.3.0", "react-json-view": "^1.21.3", 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..1386c6de --- /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, 0.5); + + 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 bd61bd46..00000000 --- a/src/agent/open-canvas/nodes/generateArtifact.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { NEW_ARTIFACT_PROMPT } from "../prompts"; -import { - ArtifactCodeV3, - ArtifactMarkdownV3, - ArtifactV3, - 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"; - -/** - * Generate a new artifact based on the user's query. - */ -export const generateArtifact = async ( - state: typeof OpenCanvasGraphAnnotation.State, - config: LangGraphRunnableConfig -): Promise => { - const { modelName, modelProvider } = - getModelNameAndProviderFromConfig(config); - const smallModel = await initChatModel(modelName, { - temperature: 0.5, - modelProvider, - }); - - 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..96b2108d 100644 --- a/src/agent/open-canvas/nodes/generatePath.ts +++ b/src/agent/open-canvas/nodes/generatePath.ts @@ -22,6 +22,7 @@ export const generatePath = async ( state: typeof OpenCanvasGraphAnnotation.State, config: LangGraphRunnableConfig ) => { + console.log("config.configurable!!", config.configurable); if (state.highlightedCode) { return { next: "updateArtifact", 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 067a522f..00000000 --- a/src/agent/open-canvas/nodes/rewriteArtifact.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; -import { - GET_TITLE_TYPE_REWRITE_ARTIFACT, - OPTIONALLY_UPDATE_META_PROMPT, - UPDATE_ENTIRE_ARTIFACT_PROMPT, -} from "../prompts"; -import { - ensureStoreInConfig, - formatArtifactContent, - formatReflections, - getModelNameAndProviderFromConfig, -} from "../../utils"; -import { - ArtifactCodeV3, - ArtifactMarkdownV3, - ArtifactV3, - 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"; - -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 } = - getModelNameAndProviderFromConfig(config); - const toolCallingModel = ( - await initChatModel(modelName, { - temperature: 0, - modelProvider, - }) - ) - .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 e58c64cc..37b88de4 100644 --- a/src/agent/utils.ts +++ b/src/agent/utils.ts @@ -1,6 +1,7 @@ import { isArtifactCodeContent } from "@/lib/artifact_content_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, @@ -74,6 +75,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 => { @@ -146,3 +165,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, + temperature = 0 +) { + const { modelName, modelProvider } = + getModelNameAndProviderFromConfig(config); + return await initChatModel(modelName, { + temperature, + modelProvider, + }); +} diff --git a/src/components/artifacts/ArtifactRenderer.tsx b/src/components/artifacts/ArtifactRenderer.tsx index a7ef3304..ee79da2e 100644 --- a/src/components/artifacts/ArtifactRenderer.tsx +++ b/src/components/artifacts/ArtifactRenderer.tsx @@ -354,7 +354,7 @@ function ArtifactRendererComponent(props: ArtifactRendererProps) { />
- +
Custom instructions - + +

+ {CUSTOM_INSTRUCTIONS_TOOLTIP_TEXT} +

+