mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
persist recipe across route changes
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
Reference in New Issue
Block a user