-
Notifications
You must be signed in to change notification settings - Fork 4
Enhancement/auto gen personalization #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
be2ce11
93fba03
75abd9c
464ab35
eed1885
147a6c1
d208c3b
c7883af
f1cc7e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,14 +95,15 @@ function getSelectedCardsContext(body: any): string { | |
| return body.selectedCardsContext || ""; | ||
| } | ||
|
|
||
| // Regex to detect createFrom auto-generated prompts | ||
| const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\. Only add one quality YouTube video\.$/; | ||
| // Regex to detect createFrom auto-generated prompts (YouTube suffix is optional for custom type selections) | ||
| const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\.(?:\s*Only add one quality YouTube video\.)?$/; | ||
|
|
||
| /** | ||
| * Detect if the first user message is a createFrom auto-generated prompt | ||
| * and return additional system instructions for better workspace curation | ||
| * and return additional system instructions for better workspace curation. | ||
| * When genTypes is provided, only instructions for those types are included. | ||
| */ | ||
| function getCreateFromSystemPrompt(messages: any[]): string | null { | ||
| function getCreateFromSystemPrompt(messages: any[], genTypes: string[] | null): string | null { | ||
| // Find the first user message | ||
| const firstUserMessage = messages.find((m) => m.role === "user"); | ||
| if (!firstUserMessage) return null; | ||
|
|
@@ -121,29 +122,52 @@ function getCreateFromSystemPrompt(messages: any[]): string | null { | |
| if (!match) return null; | ||
|
|
||
| const topic = match[1]; | ||
| const allTypes = ['note', 'quiz', 'flashcard', 'youtube'] as const; | ||
| const validTypes = genTypes ? genTypes.filter(t => allTypes.includes(t as any)) : null; | ||
| const types = new Set(validTypes && validTypes.length > 0 ? validTypes : allTypes); | ||
|
|
||
| // Build type-specific update instructions — always include title param | ||
| const updateInstructions: string[] = []; | ||
|
Comment on lines
124
to
130
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invalid
|
||
| if (types.has('note')) updateInstructions.push(` - Use \`updateNote\` with noteName "Update me" and a descriptive \`title\` (e.g. "${topic} Notes")`); | ||
| if (types.has('flashcard')) updateInstructions.push(` - Use \`updateFlashcards\` with deckName "Update me" and a descriptive \`title\` (e.g. "${topic} Flashcards")`); | ||
| if (types.has('quiz')) updateInstructions.push(` - Use \`updateQuiz\` with quizName "Update me" and a descriptive \`title\` (e.g. "${topic} Quiz")`); | ||
|
|
||
| // Build type-specific quality guidelines | ||
| const qualityGuidelines: string[] = []; | ||
| if (types.has('note')) qualityGuidelines.push('- For notes: add a comprehensive summary of the topic'); | ||
| if (types.has('flashcard')) qualityGuidelines.push('- For flashcards: create exactly 5 meaningful question/answer pairs covering key concepts'); | ||
| if (types.has('quiz')) qualityGuidelines.push('- For quizzes: create challenging but fair questions that test understanding'); | ||
|
|
||
| // YouTube section only if selected | ||
| let youtubeSection = ''; | ||
| if (types.has('youtube')) { | ||
| youtubeSection = ` | ||
| YOUTUBE VIDEO: | ||
| - Search with specific, relevant terms for the topic | ||
| - Prefer videos that are educational/explanatory | ||
| - Look for high view counts and reputable channels as quality signals`; | ||
| } | ||
|
|
||
| // Build numbered instructions dynamically to avoid numbering gaps | ||
| const instructions: string[] = []; | ||
| let instrNum = 1; | ||
| if (updateInstructions.length > 0) { | ||
| instructions.push(`${instrNum++}. **Update ONLY these workspace items** about the topic:\n${updateInstructions.join('\n')}`); | ||
| } | ||
| instructions.push(`${instrNum++}. **Be thorough but focused** - Provide a solid foundation for understanding the topic without being overwhelming.`); | ||
| if (validTypes && validTypes.length > 0) { | ||
| instructions.push(`${instrNum++}. **Do NOT create or update any other item types** beyond what is listed above.`); | ||
| } | ||
| instructions.push(`${instrNum++}. **Do NOT ask the user questions** - This is an automated initialization, proceed directly with updating the workspace.`); | ||
|
|
||
| return ` | ||
| CREATE-FROM WORKSPACE INITIALIZATION MODE: | ||
| This is an automatic workspace initialization request. The user wants to transform this workspace into a curated learning/research space | ||
| ace about: "${topic}" | ||
| This is an automatic workspace initialization request. The user wants to transform this workspace into a curated learning/research space about: "${topic}" | ||
|
|
||
| CRITICAL INSTRUCTIONS FOR WORKSPACE CURATION: | ||
| 1. **For each of the existing workspace items** update the title and content to be about the topic: | ||
| - Use \`updateNote\` tool for notes | ||
| - Use \`updateFlashcards\` tool for flashcard sets | ||
| - Use \`updateQuiz\` tool for quizzes | ||
| 2. **Be thorough but focused** - Provide a solid foundation for understanding the topic without being overwhelming. | ||
| 3. **Do NOT ask the user questions** - This is an automated initialization, proceed directly with updating the workspace. | ||
|
|
||
| QUALITY GUIDELINES FOR CONTENT: | ||
| - For notes: add a comprehensive summary of the topic | ||
| - For flashcards: create exactly 5 meaningful question/answer pairs covering key concepts | ||
| - For quizzes: create challenging but fair questions that test understanding | ||
|
|
||
| QUALITY GUIDELINES FOR THE YOUTUBE VIDEO: | ||
| - Search with specific, relevant terms for the topic | ||
| - Prefer videos that are educational/explanatory | ||
| - Look for high view counts and reputable channels as quality signals | ||
| ${instructions.join('\n')} | ||
|
|
||
| ${qualityGuidelines.length > 0 ? `QUALITY GUIDELINES FOR CONTENT:\n${qualityGuidelines.join('\n')}` : ''}${youtubeSection} | ||
| `; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
|
|
@@ -224,7 +248,8 @@ export async function POST(req: Request) { | |
| ]; | ||
|
|
||
| // Inject createFrom workspace initialization prompt if detected | ||
| const createFromPrompt = getCreateFromSystemPrompt(cleanedMessages); | ||
| const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : null; | ||
| const createFromPrompt = getCreateFromSystemPrompt(cleanedMessages, genTypes); | ||
|
Comment on lines
+251
to
+252
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Proposed fix- const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : null;
+ const ALLOWED_GEN_TYPES = new Set(['note', 'quiz', 'flashcard', 'youtube']);
+ const genTypes: string[] | null = body.genTypes
+ ? body.genTypes.split(',').map((t: string) => t.trim()).filter((t: string) => ALLOWED_GEN_TYPES.has(t))
+ : null;
+ // Fall back to null if filtering removed all entries
+ const validGenTypes = genTypes && genTypes.length > 0 ? genTypes : null;🤖 Prompt for AI Agents |
||
| if (createFromPrompt) { | ||
| systemPromptParts.push(`\n\n${createFromPrompt}`); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -123,13 +123,19 @@ function CreateFromPromptHandler({ | |
| const timeoutIdsRef = useRef<ReturnType<typeof setTimeout>[]>([]); | ||
|
|
||
| const createFrom = searchParams.get("createFrom"); | ||
| const genTypes = searchParams.get("genTypes"); | ||
|
|
||
| useEffect(() => { | ||
| if (!createFrom || !workspaceId || isLoading || hasAutoSentRef.current) return; | ||
|
|
||
| setIsChatExpanded?.(true); | ||
|
|
||
| const wrapped = `Update the preexisting contents of this workspace to be about ${createFrom}. Only add one quality YouTube video.`; | ||
| // Build type-aware message: only mention YouTube if selected (or auto mode) | ||
| const types = genTypes ? genTypes.split(',').map(s => s.trim()).filter(Boolean) : null; | ||
| const includeYoutube = !types || types.includes('youtube'); | ||
| const wrapped = includeYoutube | ||
| ? `Update the preexisting contents of this workspace to be about ${createFrom}. Only add one quality YouTube video.` | ||
| : `Update the preexisting contents of this workspace to be about ${createFrom}.`; | ||
|
|
||
| let attempts = 0; | ||
| const maxAttempts = 12; | ||
|
|
@@ -152,6 +158,7 @@ function CreateFromPromptHandler({ | |
| clearAll(); | ||
| const url = new URL(window.location.href); | ||
| url.searchParams.delete("createFrom"); | ||
| url.searchParams.delete("genTypes"); | ||
| router.replace(url.pathname + url.search); | ||
| return; | ||
| } catch { | ||
|
|
@@ -168,7 +175,7 @@ function CreateFromPromptHandler({ | |
| ids.push(id); | ||
|
|
||
| return () => clearAll(); | ||
| }, [createFrom, workspaceId, isLoading, aui, router, setIsChatExpanded]); | ||
| }, [createFrom, genTypes, workspaceId, isLoading, aui, router, setIsChatExpanded]); | ||
|
|
||
| return null; | ||
| } | ||
|
|
@@ -189,19 +196,31 @@ function GenerateStudyMaterialsHandler({ | |
| const timeoutIdsRef = useRef<ReturnType<typeof setTimeout>[]>([]); | ||
|
|
||
| const action = searchParams.get("action"); | ||
| const genTypes = searchParams.get("genTypes"); | ||
|
|
||
| useEffect(() => { | ||
| if (action !== "generate_study_materials" || !workspaceId || isLoading || hasAutoSentRef.current) return; | ||
|
|
||
| setIsChatExpanded?.(true); | ||
|
|
||
| const prompt = `First, process any PDF files in this workspace. | ||
|
|
||
| Then, using the content: | ||
| 1. Update the note with a comprehensive summary | ||
| 2. Update the quiz with 5-10 relevant questions | ||
| 3. Update the flashcards with key terms and concepts | ||
| 4. Search and add one relevant YouTube video if possible`; | ||
| // Build type-aware prompt: only include steps for selected types | ||
| const types = genTypes ? new Set(genTypes.split(',').map(s => s.trim()).filter(Boolean)) : null; | ||
| const steps: string[] = []; | ||
| let n = 1; | ||
| if (!types || types.has('note')) steps.push(`${n++}. Update the note with a comprehensive summary`); | ||
| if (!types || types.has('quiz')) steps.push(`${n++}. Update the quiz with 5-10 relevant questions`); | ||
| if (!types || types.has('flashcard')) steps.push(`${n++}. Update the flashcards with key terms and concepts`); | ||
| if (!types || types.has('youtube')) steps.push(`${n++}. Search and add one relevant YouTube video if possible`); | ||
|
|
||
| // If genTypes was set but contained no recognized values, fall back to all types | ||
| if (steps.length === 0) { | ||
| steps.push('1. Update the note with a comprehensive summary'); | ||
| steps.push('2. Update the quiz with 5-10 relevant questions'); | ||
| steps.push('3. Update the flashcards with key terms and concepts'); | ||
| steps.push('4. Search and add one relevant YouTube video if possible'); | ||
| } | ||
|
Comment on lines
+206
to
+221
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invalid genTypes not detected
|
||
|
|
||
| const prompt = `First, process any PDF files in this workspace.\n\nThen, using the content:\n${steps.join('\n')}`; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
206
to
223
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. genTypes parsing misses whitespace
|
||
|
|
||
| let attempts = 0; | ||
| const maxAttempts = 12; | ||
|
|
@@ -224,6 +243,7 @@ Then, using the content: | |
| clearAll(); | ||
| const url = new URL(window.location.href); | ||
| url.searchParams.delete("action"); | ||
| url.searchParams.delete("genTypes"); | ||
| router.replace(url.pathname + url.search); | ||
| return; | ||
| } catch { | ||
|
|
@@ -240,7 +260,7 @@ Then, using the content: | |
| ids.push(id); | ||
|
|
||
| return () => clearAll(); | ||
| }, [action, workspaceId, isLoading, aui, router, setIsChatExpanded]); | ||
| }, [action, genTypes, workspaceId, isLoading, aui, router, setIsChatExpanded]); | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| import { AssistantCloud, AssistantRuntimeProvider } from "@assistant-ui/react"; | ||
| import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/react-ai-sdk"; | ||
| import { useMemo, useCallback } from "react"; | ||
| import { useSearchParams } from "next/navigation"; | ||
| import { AssistantAvailableProvider } from "@/contexts/AssistantAvailabilityContext"; | ||
| import { useUIStore } from "@/lib/stores/ui-store"; | ||
| import { useSession } from "@/lib/auth-client"; | ||
|
|
@@ -38,6 +39,11 @@ export function WorkspaceRuntimeProvider({ | |
| const selectedCardIdsSet = useUIStore((state) => state.selectedCardIds); | ||
| const selectedActions = useUIStore((state) => state.selectedActions); | ||
| const replySelections = useUIStore(useShallow((state) => state.replySelections)); | ||
| const searchParams = useSearchParams(); | ||
| // Only pass genTypes during auto-init flows (createFrom / generate_study_materials) | ||
| // to avoid leaking it into every subsequent chat request | ||
| const hasAutoInit = searchParams.has("createFrom") || searchParams.get("action") === "generate_study_materials"; | ||
| const genTypes = hasAutoInit ? searchParams.get("genTypes") : null; | ||
| const { data: session } = useSession(); | ||
|
Comment on lines
40
to
47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaking URL genTypes
|
||
|
|
||
| // Get workspace state to format selected cards context on client | ||
|
|
@@ -147,13 +153,14 @@ export function WorkspaceRuntimeProvider({ | |
| selectedCardsContext, // Pre-formatted context (client-side) instead of IDs | ||
| replySelections, | ||
| selectedActions, | ||
| genTypes, | ||
| }, | ||
| headers: { | ||
| // Headers for static context if needed | ||
| }, | ||
| }); | ||
| return transport; | ||
| }, [workspaceId, selectedModelId, activeFolderId, selectedCardsContext, replySelections, selectedActions]), | ||
| }, [workspaceId, selectedModelId, activeFolderId, selectedCardsContext, replySelections, selectedActions, genTypes]), | ||
| adapters: { | ||
| attachments: new SupabaseAttachmentAdapter(), | ||
| }, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The greedy capture in the create-from regex causes the topic to include the optional YouTube sentence, so generated prompts will treat that suffix as part of the topic. Use a non-greedy capture to stop at the first period.
Prompt for AI agents