fix: initial prompt not filled in after accepting new recipe (#3637)

This commit is contained in:
Zane
2025-07-31 10:49:28 -07:00
committed by GitHub
parent f1907abacb
commit b5e73c4c89
5 changed files with 40 additions and 27 deletions
+16 -1
View File
@@ -61,6 +61,7 @@ import { MainPanelLayout } from './Layout/MainPanelLayout';
import ChatInput from './ChatInput'; import ChatInput from './ChatInput';
import { ScrollArea, ScrollAreaHandle } from './ui/scroll-area'; import { ScrollArea, ScrollAreaHandle } from './ui/scroll-area';
import { RecipeWarningModal } from './ui/RecipeWarningModal'; import { RecipeWarningModal } from './ui/RecipeWarningModal';
import ParameterInputModal from './ParameterInputModal';
import { useChatEngine } from '../hooks/useChatEngine'; import { useChatEngine } from '../hooks/useChatEngine';
import { useRecipeManager } from '../hooks/useRecipeManager'; import { useRecipeManager } from '../hooks/useRecipeManager';
import { useSessionContinuation } from '../hooks/useSessionContinuation'; import { useSessionContinuation } from '../hooks/useSessionContinuation';
@@ -188,6 +189,9 @@ function BaseChatContent({
recipeConfig, recipeConfig,
initialPrompt, initialPrompt,
isGeneratingRecipe, isGeneratingRecipe,
isParameterModalOpen,
setIsParameterModalOpen,
handleParameterSubmit,
handleAutoExecution, handleAutoExecution,
recipeError, recipeError,
setRecipeError, setRecipeError,
@@ -524,7 +528,7 @@ function BaseChatContent({
chatState={chatState} chatState={chatState}
onStop={onStopGoose} onStop={onStopGoose}
commandHistory={commandHistory} commandHistory={commandHistory}
initialValue={_input || (messages.length === 0 ? initialPrompt : '')} initialValue={_input || ''}
setView={setView} setView={setView}
numTokens={sessionTokenCount} numTokens={sessionTokenCount}
inputTokens={sessionInputTokens || localInputTokens} inputTokens={sessionInputTokens || localInputTokens}
@@ -537,6 +541,8 @@ function BaseChatContent({
sessionCosts={sessionCosts} sessionCosts={sessionCosts}
setIsGoosehintsModalOpen={setIsGoosehintsModalOpen} setIsGoosehintsModalOpen={setIsGoosehintsModalOpen}
recipeConfig={recipeConfig} recipeConfig={recipeConfig}
recipeAccepted={recipeAccepted}
initialPrompt={initialPrompt}
{...customChatInputProps} {...customChatInputProps}
/> />
</div> </div>
@@ -564,6 +570,15 @@ function BaseChatContent({
}} }}
/> />
{/* Recipe Parameter Modal */}
{isParameterModalOpen && recipeConfig?.parameters && (
<ParameterInputModal
parameters={recipeConfig.parameters}
onSubmit={handleParameterSubmit}
onClose={() => setIsParameterModalOpen(false)}
/>
)}
{/* Recipe Error Modal */} {/* Recipe Error Modal */}
{recipeError && ( {recipeError && (
<div className="fixed inset-0 z-[300] flex items-center justify-center bg-black/50"> <div className="fixed inset-0 z-[300] flex items-center justify-center bg-black/50">
+16
View File
@@ -75,6 +75,8 @@ interface ChatInputProps {
setIsGoosehintsModalOpen?: (isOpen: boolean) => void; setIsGoosehintsModalOpen?: (isOpen: boolean) => void;
disableAnimation?: boolean; disableAnimation?: boolean;
recipeConfig?: Recipe | null; recipeConfig?: Recipe | null;
recipeAccepted?: boolean;
initialPrompt?: string;
} }
export default function ChatInput({ export default function ChatInput({
@@ -95,6 +97,8 @@ export default function ChatInput({
sessionCosts, sessionCosts,
setIsGoosehintsModalOpen, setIsGoosehintsModalOpen,
recipeConfig, recipeConfig,
recipeAccepted,
initialPrompt,
}: ChatInputProps) { }: ChatInputProps) {
const [_value, setValue] = useState(initialValue); const [_value, setValue] = useState(initialValue);
const [displayValue, setDisplayValue] = useState(initialValue); // For immediate visual feedback const [displayValue, setDisplayValue] = useState(initialValue); // For immediate visual feedback
@@ -200,6 +204,18 @@ export default function ChatInput({
setHasUserTyped(false); setHasUserTyped(false);
}, [initialValue]); // Keep only initialValue as a dependency }, [initialValue]); // Keep only initialValue as a dependency
// Handle recipe prompt updates
useEffect(() => {
// If recipe is accepted and we have an initial prompt, and no messages yet, set the prompt
if (recipeAccepted && initialPrompt && messages.length === 0 && !displayValue.trim()) {
setDisplayValue(initialPrompt);
setValue(initialPrompt);
setTimeout(() => {
textAreaRef.current?.focus();
}, 0);
}
}, [recipeAccepted, initialPrompt, messages.length, displayValue]);
// Draft functionality - load draft if no initial value or recipe // Draft functionality - load draft if no initial value or recipe
useEffect(() => { useEffect(() => {
// Reset draft loaded flag when context changes // Reset draft loaded flag when context changes
+1 -17
View File
@@ -28,7 +28,6 @@ import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { type View, ViewOptions } from '../App'; import { type View, ViewOptions } from '../App';
import BaseChat from './BaseChat'; import BaseChat from './BaseChat';
import ParameterInputModal from './ParameterInputModal';
import { useRecipeManager } from '../hooks/useRecipeManager'; import { useRecipeManager } from '../hooks/useRecipeManager';
import { useIsMobile } from '../hooks/use-mobile'; import { useIsMobile } from '../hooks/use-mobile';
import { useSidebar } from './ui/sidebar'; import { useSidebar } from './ui/sidebar';
@@ -57,13 +56,7 @@ export default function Pair({
const [isTransitioningFromHub, setIsTransitioningFromHub] = useState(false); const [isTransitioningFromHub, setIsTransitioningFromHub] = useState(false);
// Get recipe configuration and parameter handling // Get recipe configuration and parameter handling
const { const { initialPrompt: recipeInitialPrompt } = useRecipeManager(chat.messages, location.state);
recipeConfig,
initialPrompt: recipeInitialPrompt,
isParameterModalOpen,
setIsParameterModalOpen,
handleParameterSubmit,
} = useRecipeManager(chat.messages, location.state);
// Handle recipe loading from recipes view - reset chat if needed // Handle recipe loading from recipes view - reset chat if needed
useEffect(() => { useEffect(() => {
@@ -196,15 +189,6 @@ export default function Pair({
showPopularTopics={!isTransitioningFromHub} // Don't show popular topics while transitioning from Hub showPopularTopics={!isTransitioningFromHub} // Don't show popular topics while transitioning from Hub
suppressEmptyState={isTransitioningFromHub} // Suppress all empty state content while transitioning from Hub suppressEmptyState={isTransitioningFromHub} // Suppress all empty state content while transitioning from Hub
/> />
{/* Recipe Parameter Modal */}
{isParameterModalOpen && recipeConfig?.parameters && (
<ParameterInputModal
parameters={recipeConfig.parameters}
onSubmit={handleParameterSubmit}
onClose={() => setIsParameterModalOpen(false)}
/>
)}
</> </>
); );
} }
@@ -256,7 +256,7 @@ export default function ModelsBottomBar({
<> <>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem onClick={handleViewRecipe}> <DropdownMenuItem onClick={handleViewRecipe}>
<span>View Recipe</span> <span>View/Edit Recipe</span>
<Eye className="ml-auto h-4 w-4" /> <Eye className="ml-auto h-4 w-4" />
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem onClick={handleSaveRecipeClick}> <DropdownMenuItem onClick={handleSaveRecipeClick}>
+6 -8
View File
@@ -129,7 +129,9 @@ export const useRecipeManager = (messages: Message[], locationState?: LocationSt
// Get the recipe's initial prompt (always return the actual prompt, don't modify based on conversation state) // Get the recipe's initial prompt (always return the actual prompt, don't modify based on conversation state)
const initialPrompt = useMemo(() => { const initialPrompt = useMemo(() => {
if (!recipeConfig?.prompt || !recipeAccepted) return ''; if (!recipeConfig?.prompt || !recipeAccepted) {
return '';
}
const hasRequiredParams = recipeConfig.parameters && recipeConfig.parameters.length > 0; const hasRequiredParams = recipeConfig.parameters && recipeConfig.parameters.length > 0;
@@ -138,13 +140,9 @@ export const useRecipeManager = (messages: Message[], locationState?: LocationSt
return substituteParameters(recipeConfig.prompt, recipeParameters); return substituteParameters(recipeConfig.prompt, recipeParameters);
} }
// If there are no parameters, return the original prompt. // Always return the original prompt, whether it has parameters or not
if (!hasRequiredParams) { // The user should see the prompt with parameter placeholders before filling them in
return recipeConfig.prompt; return recipeConfig.prompt;
}
// Otherwise, we are waiting for parameters, so the input should be empty.
return '';
}, [recipeConfig, recipeParameters, recipeAccepted]); }, [recipeConfig, recipeParameters, recipeAccepted]);
// Handle parameter submission // Handle parameter submission