forked from langchain-ai/open-canvas
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
41 changed files
with
2,057 additions
and
533 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { ChatOpenAI } from "@langchain/openai"; | ||
import { OpenCanvasGraphAnnotation, OpenCanvasGraphReturnType } from "../state"; | ||
import { | ||
CUSTOM_QUICK_ACTION_ARTIFACT_CONTENT_PROMPT, | ||
CUSTOM_QUICK_ACTION_ARTIFACT_PROMPT_PREFIX, | ||
CUSTOM_QUICK_ACTION_CONVERSATION_CONTEXT, | ||
REFLECTIONS_QUICK_ACTION_PROMPT, | ||
} from "../prompts"; | ||
import { ensureStoreInConfig, formatReflections } from "../../utils"; | ||
import { | ||
ArtifactContent, | ||
CustomQuickAction, | ||
Reflections, | ||
} from "../../../types"; | ||
import { LangGraphRunnableConfig } from "@langchain/langgraph"; | ||
import { BaseMessage } from "@langchain/core/messages"; | ||
|
||
const formatMessages = (messages: BaseMessage[]): string => | ||
messages | ||
.map( | ||
(msg) => | ||
`<${msg.getType()}>\n${msg.content as string}\n</${msg.getType()}>` | ||
) | ||
.join("\n"); | ||
|
||
export const customAction = async ( | ||
state: typeof OpenCanvasGraphAnnotation.State, | ||
config: LangGraphRunnableConfig | ||
): Promise<OpenCanvasGraphReturnType> => { | ||
if (!state.customQuickActionId) { | ||
throw new Error("No custom quick action ID found."); | ||
} | ||
|
||
const smallModel = new ChatOpenAI({ | ||
model: "gpt-4o-mini", | ||
temperature: 0.5, | ||
}); | ||
|
||
const store = ensureStoreInConfig(config); | ||
const assistantId = config.configurable?.assistant_id; | ||
if (!assistantId) { | ||
throw new Error("`assistant_id` not found in configurable"); | ||
} | ||
const customActionsNamespace = ["custom_actions", assistantId]; | ||
const actionsKey = "actions"; | ||
|
||
const memoryNamespace = ["memories", assistantId]; | ||
const memoryKey = "reflection"; | ||
|
||
const [customActionsItem, memories] = await Promise.all([ | ||
store.get(customActionsNamespace, actionsKey), | ||
store.get(memoryNamespace, memoryKey), | ||
]); | ||
if (!customActionsItem?.value) { | ||
throw new Error("No custom actions found."); | ||
} | ||
const customQuickAction = customActionsItem.value[ | ||
state.customQuickActionId | ||
] as CustomQuickAction | undefined; | ||
if (!customQuickAction) { | ||
throw new Error( | ||
`No custom quick action found from ID ${state.customQuickActionId}` | ||
); | ||
} | ||
|
||
let currentArtifactContent: ArtifactContent | undefined; | ||
if (state.artifact) { | ||
currentArtifactContent = state.artifact.contents.find( | ||
(art) => art.index === state.artifact.currentContentIndex | ||
); | ||
} | ||
if (!currentArtifactContent) { | ||
throw new Error("No artifact content found."); | ||
} | ||
|
||
let formattedPrompt = `<custom-instructions>\n${customQuickAction.prompt}\n</custom-instructions>`; | ||
if (customQuickAction.includeReflections && memories?.value) { | ||
const memoriesAsString = formatReflections(memories.value as Reflections); | ||
const reflectionsPrompt = REFLECTIONS_QUICK_ACTION_PROMPT.replace( | ||
"{reflections}", | ||
memoriesAsString | ||
); | ||
formattedPrompt += `\n\n${reflectionsPrompt}`; | ||
} | ||
|
||
if (customQuickAction.includePrefix) { | ||
formattedPrompt = `${CUSTOM_QUICK_ACTION_ARTIFACT_PROMPT_PREFIX}\n\n${formattedPrompt}`; | ||
} | ||
|
||
if (customQuickAction.includeRecentHistory) { | ||
const formattedConversationHistory = | ||
CUSTOM_QUICK_ACTION_CONVERSATION_CONTEXT.replace( | ||
"{conversation}", | ||
formatMessages(state.messages.slice(-5)) | ||
); | ||
formattedPrompt += `\n\n${formattedConversationHistory}`; | ||
} | ||
|
||
formattedPrompt += `\n\n${CUSTOM_QUICK_ACTION_ARTIFACT_CONTENT_PROMPT.replace("{artifactContent}", currentArtifactContent.content)}`; | ||
|
||
const newArtifactValues = await smallModel.invoke([ | ||
{ role: "user", content: formattedPrompt }, | ||
]); | ||
|
||
const newArtifact = { | ||
...state.artifact, | ||
currentContentIndex: state.artifact.contents.length + 1, | ||
contents: [ | ||
...state.artifact.contents, | ||
{ | ||
...currentArtifactContent, | ||
index: state.artifact.contents.length + 1, | ||
content: newArtifactValues.content as string, | ||
}, | ||
], | ||
}; | ||
|
||
return { | ||
artifact: newArtifact, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,6 +76,7 @@ export const rewriteArtifact = async ( | |
"php", | ||
"python", | ||
"html", | ||
"sql", | ||
"other", | ||
]) | ||
.optional() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
import { Client } from "@langchain/langgraph-sdk"; | ||
import { LANGGRAPH_API_URL } from "@/constants"; | ||
import { User } from "@supabase/supabase-js"; | ||
import { verifyUserAuthenticated } from "../../../../../lib/supabase/verify_user_server"; | ||
|
||
export async function POST(req: NextRequest) { | ||
let user: User | undefined; | ||
try { | ||
user = await verifyUserAuthenticated(); | ||
if (!user) { | ||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); | ||
} | ||
} catch (e) { | ||
console.error("Failed to fetch user", e); | ||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); | ||
} | ||
|
||
const { namespace, key, id } = await req.json(); | ||
|
||
const lgClient = new Client({ | ||
apiKey: process.env.LANGCHAIN_API_KEY, | ||
apiUrl: LANGGRAPH_API_URL, | ||
}); | ||
|
||
try { | ||
const currentItems = await lgClient.store.getItem(namespace, key); | ||
if (!currentItems?.value) { | ||
return new NextResponse( | ||
JSON.stringify({ | ||
error: "Item not found", | ||
success: false, | ||
}), | ||
{ | ||
status: 404, | ||
headers: { "Content-Type": "application/json" }, | ||
} | ||
); | ||
} | ||
|
||
const newValues = Object.fromEntries( | ||
Object.entries(currentItems.value).filter(([k]) => k !== id) | ||
); | ||
|
||
await lgClient.store.putItem(namespace, key, newValues); | ||
|
||
return new NextResponse(JSON.stringify({ success: true }), { | ||
status: 200, | ||
headers: { "Content-Type": "application/json" }, | ||
}); | ||
} catch (_) { | ||
return new NextResponse( | ||
JSON.stringify({ error: "Failed to share run after multiple attempts." }), | ||
{ | ||
status: 500, | ||
headers: { "Content-Type": "application/json" }, | ||
} | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.