persist recipe across route changes

This commit is contained in:
Zane Staggs
2025-07-11 14:41:22 -07:00
parent 20c104edb2
commit 3b81b9cd50
7 changed files with 55 additions and 5 deletions
+1
View File
@@ -609,6 +609,7 @@ export default function App() {
title: 'Pair Chat',
messages: [],
messageHistoryIndex: 0,
recipeConfig: null, // Initialize with no recipe
});
const { getExtensions, addExtension, read } = useConfig();
+2
View File
@@ -67,6 +67,7 @@ import { useSessionContinuation } from '../hooks/useSessionContinuation';
import { useFileDrop } from '../hooks/useFileDrop';
import { useCostTracking } from '../hooks/useCostTracking';
import { Message } from '../types/message';
import { Recipe } from '../recipe';
// Context for sharing current model info
const CurrentModelContext = createContext<{ model: string; mode: string } | null>(null);
@@ -77,6 +78,7 @@ export interface ChatType {
title: string;
messageHistoryIndex: number;
messages: Message[];
recipeConfig?: Recipe | null; // Add recipe configuration to chat state
}
interface BaseChatProps {
+3
View File
@@ -27,6 +27,7 @@ import { SessionInsights } from './sessions/SessionsInsights';
import ChatInput from './ChatInput';
import { generateSessionId } from '../sessions';
import { ChatContextManagerProvider } from './context_management/ChatContextManager';
import { Recipe } from '../recipe';
import 'react-toastify/dist/ReactToastify.css';
export interface ChatType {
@@ -34,6 +35,7 @@ export interface ChatType {
title: string;
messageHistoryIndex: number;
messages: Message[];
recipeConfig?: Recipe | null; // Add recipe configuration to chat state
}
export default function Hub({
@@ -65,6 +67,7 @@ export default function Hub({
title: 'New Chat',
messages: [], // Always start with empty messages
messageHistoryIndex: 0,
recipeConfig: null, // Clear recipe for new chats from Hub
};
// Update the PAIR chat state (not the hub chat state)
+3
View File
@@ -31,6 +31,7 @@ import { Message } from '../types/message';
import BaseChat from './BaseChat';
import ParameterInputModal from './ParameterInputModal';
import { useRecipeManager } from '../hooks/useRecipeManager';
import { Recipe } from '../recipe';
import 'react-toastify/dist/ReactToastify.css';
export interface ChatType {
@@ -38,6 +39,7 @@ export interface ChatType {
title: string;
messageHistoryIndex: number;
messages: Message[];
recipeConfig?: Recipe | null; // Add recipe configuration to chat state
}
export default function Pair({
@@ -74,6 +76,7 @@ export default function Pair({
title: location.state.recipeConfig.title || 'Recipe Chat',
messages: [], // Clear messages to start fresh
messageHistoryIndex: 0,
recipeConfig: location.state.recipeConfig, // Set the recipe config in chat state
};
setChat(newChat);
+20
View File
@@ -1,12 +1,15 @@
import React, { createContext, useContext, ReactNode } from 'react';
import { ChatType } from '../components/BaseChat';
import { generateSessionId } from '../sessions';
import { Recipe } from '../recipe';
interface ChatContextType {
chat: ChatType;
setChat: (chat: ChatType) => void;
resetChat: () => void;
hasActiveSession: boolean;
setRecipeConfig: (recipe: Recipe | null) => void;
clearRecipeConfig: () => void;
}
const ChatContext = createContext<ChatContextType | undefined>(undefined);
@@ -25,6 +28,21 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children, chat, setC
title: 'New Chat',
messages: [],
messageHistoryIndex: 0,
recipeConfig: null, // Clear recipe when resetting chat
});
};
const setRecipeConfig = (recipe: Recipe | null) => {
setChat({
...chat,
recipeConfig: recipe,
});
};
const clearRecipeConfig = () => {
setChat({
...chat,
recipeConfig: null,
});
};
@@ -35,6 +53,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children, chat, setC
setChat,
resetChat,
hasActiveSession,
setRecipeConfig,
clearRecipeConfig,
};
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
+2
View File
@@ -14,6 +14,7 @@ export const useChat = ({ setIsLoadingSession, setView, setPairChat }: UseChatAr
title: 'New Chat',
messages: [],
messageHistoryIndex: 0,
recipeConfig: null, // Initialize with no recipe
});
// Check for resumeSessionId in URL parameters
@@ -37,6 +38,7 @@ export const useChat = ({ setIsLoadingSession, setView, setPairChat }: UseChatAr
title: sessionDetails.metadata?.description || `ID: ${sessionDetails.session_id}`,
messages: sessionDetails.messages,
messageHistoryIndex: sessionDetails.messages.length,
recipeConfig: null, // Sessions don't have recipes by default
};
setChat(sessionChat);
+24 -5
View File
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
import { createRecipe, Recipe } from '../recipe';
import { Message, createUserMessage } from '../types/message';
import { updateSystemPromptWithParameters } from '../utils/providerUtils';
import { useChatContext } from '../contexts/ChatContext';
interface LocationState {
recipeConfig?: Recipe;
@@ -15,18 +16,36 @@ export const useRecipeManager = (messages: Message[], locationState?: LocationSt
const [recipeParameters, setRecipeParameters] = useState<Record<string, string> | null>(null);
const [readyForAutoUserPrompt, setReadyForAutoUserPrompt] = useState(false);
// Get chat context to access persisted recipe
const { chat, setRecipeConfig } = useChatContext();
// Get recipeConfig from multiple sources with priority:
// 1. Navigation state (from recipes view)
// 2. App config (from deeplinks)
// 1. Chat context (persisted recipe)
// 2. Navigation state (from recipes view)
// 3. App config (from deeplinks)
const recipeConfig = useMemo(() => {
// First check if recipe config is passed via navigation state
// First check if we have a persisted recipe in chat context
if (chat.recipeConfig) {
return chat.recipeConfig;
}
// Then check if recipe config is passed via navigation state
if (locationState?.recipeConfig) {
// Persist the recipe to chat context for future use
setRecipeConfig(locationState.recipeConfig);
return locationState.recipeConfig as Recipe;
}
// Fallback to app config (from deeplinks)
return window.appConfig.get('recipeConfig') as Recipe | null;
}, [locationState]);
const appRecipeConfig = window.appConfig.get('recipeConfig') as Recipe | null;
if (appRecipeConfig) {
// Persist the recipe to chat context for future use
setRecipeConfig(appRecipeConfig);
return appRecipeConfig;
}
return null;
}, [chat.recipeConfig, locationState, setRecipeConfig]);
// Show parameter modal if recipe has parameters and they haven't been set yet
useEffect(() => {