Recipe variables (#5365)
Co-authored-by: Douwe Osinga <douwe@squareup.com> Co-authored-by: Zane Staggs <zane@squareup.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import { useCostTracking } from '../hooks/useCostTracking';
|
|||||||
import RecipeActivities from './recipes/RecipeActivities';
|
import RecipeActivities from './recipes/RecipeActivities';
|
||||||
import { useToolCount } from './alerts/useToolCount';
|
import { useToolCount } from './alerts/useToolCount';
|
||||||
import { getThinkingMessage } from '../types/message';
|
import { getThinkingMessage } from '../types/message';
|
||||||
|
import ParameterInputModal from './ParameterInputModal';
|
||||||
|
|
||||||
interface BaseChatProps {
|
interface BaseChatProps {
|
||||||
setChat: (chat: ChatType) => void;
|
setChat: (chat: ChatType) => void;
|
||||||
@@ -49,7 +50,7 @@ function BaseChatContent({
|
|||||||
|
|
||||||
const disableAnimation = location.state?.disableAnimation || false;
|
const disableAnimation = location.state?.disableAnimation || false;
|
||||||
const [hasStartedUsingRecipe, setHasStartedUsingRecipe] = React.useState(false);
|
const [hasStartedUsingRecipe, setHasStartedUsingRecipe] = React.useState(false);
|
||||||
const [hasAcceptedRecipe, setHasAcceptedRecipe] = useState<boolean>();
|
const [hasNotAcceptedRecipe, setHasNotAcceptedRecipe] = useState<boolean>();
|
||||||
const [hasRecipeSecurityWarnings, setHasRecipeSecurityWarnings] = useState(false);
|
const [hasRecipeSecurityWarnings, setHasRecipeSecurityWarnings] = useState(false);
|
||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
@@ -63,12 +64,19 @@ function BaseChatContent({
|
|||||||
|
|
||||||
const onStreamFinish = useCallback(() => {}, []);
|
const onStreamFinish = useCallback(() => {}, []);
|
||||||
|
|
||||||
const { session, messages, chatState, handleSubmit, stopStreaming, sessionLoadError } =
|
const {
|
||||||
useChatStream({
|
session,
|
||||||
sessionId,
|
messages,
|
||||||
onStreamFinish,
|
chatState,
|
||||||
initialMessage,
|
handleSubmit,
|
||||||
});
|
stopStreaming,
|
||||||
|
sessionLoadError,
|
||||||
|
setRecipeUserParams,
|
||||||
|
} = useChatStream({
|
||||||
|
sessionId,
|
||||||
|
onStreamFinish,
|
||||||
|
initialMessage,
|
||||||
|
});
|
||||||
|
|
||||||
const handleFormSubmit = (e: React.FormEvent) => {
|
const handleFormSubmit = (e: React.FormEvent) => {
|
||||||
const customEvent = e as unknown as CustomEvent;
|
const customEvent = e as unknown as CustomEvent;
|
||||||
@@ -95,7 +103,7 @@ function BaseChatContent({
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const accepted = await window.electron.hasAcceptedRecipeBefore(recipe);
|
const accepted = await window.electron.hasAcceptedRecipeBefore(recipe);
|
||||||
setHasAcceptedRecipe(accepted);
|
setHasNotAcceptedRecipe(!accepted);
|
||||||
|
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
const scanResult = await scanRecipe(recipe);
|
const scanResult = await scanRecipe(recipe);
|
||||||
@@ -107,7 +115,7 @@ function BaseChatContent({
|
|||||||
const handleRecipeAccept = async (accept: boolean) => {
|
const handleRecipeAccept = async (accept: boolean) => {
|
||||||
if (recipe && accept) {
|
if (recipe && accept) {
|
||||||
await window.electron.recordRecipeHash(recipe);
|
await window.electron.recordRecipeHash(recipe);
|
||||||
setHasAcceptedRecipe(true);
|
setHasNotAcceptedRecipe(false);
|
||||||
} else {
|
} else {
|
||||||
setView('chat');
|
setView('chat');
|
||||||
}
|
}
|
||||||
@@ -283,7 +291,7 @@ function BaseChatContent({
|
|||||||
sessionCosts={sessionCosts}
|
sessionCosts={sessionCosts}
|
||||||
setIsGoosehintsModalOpen={setIsGoosehintsModalOpen}
|
setIsGoosehintsModalOpen={setIsGoosehintsModalOpen}
|
||||||
recipe={recipe}
|
recipe={recipe}
|
||||||
recipeAccepted={hasAcceptedRecipe}
|
recipeAccepted={!hasNotAcceptedRecipe}
|
||||||
initialPrompt={initialPrompt}
|
initialPrompt={initialPrompt}
|
||||||
toolCount={toolCount || 0}
|
toolCount={toolCount || 0}
|
||||||
autoSubmit={false}
|
autoSubmit={false}
|
||||||
@@ -294,7 +302,7 @@ function BaseChatContent({
|
|||||||
|
|
||||||
{recipe && (
|
{recipe && (
|
||||||
<RecipeWarningModal
|
<RecipeWarningModal
|
||||||
isOpen={!hasAcceptedRecipe}
|
isOpen={!!hasNotAcceptedRecipe}
|
||||||
onConfirm={() => handleRecipeAccept(true)}
|
onConfirm={() => handleRecipeAccept(true)}
|
||||||
onCancel={() => handleRecipeAccept(false)}
|
onCancel={() => handleRecipeAccept(false)}
|
||||||
recipeDetails={{
|
recipeDetails={{
|
||||||
@@ -306,14 +314,13 @@ function BaseChatContent({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/*/!* Recipe Parameter Modal *!/*/}
|
{recipe?.parameters && recipe.parameters.length > 0 && !session?.user_recipe_values && (
|
||||||
{/*{isParameterModalOpen && filteredParameters.length > 0 && (*/}
|
<ParameterInputModal
|
||||||
{/* <ParameterInputModal*/}
|
parameters={recipe.parameters}
|
||||||
{/* parameters={filteredParameters}*/}
|
onSubmit={setRecipeUserParams}
|
||||||
{/* onSubmit={handleParameterSubmit}*/}
|
onClose={() => setView('chat')}
|
||||||
{/* onClose={() => setIsParameterModalOpen(false)}*/}
|
/>
|
||||||
{/* />*/}
|
)}
|
||||||
{/*)}*/}
|
|
||||||
|
|
||||||
{/*/!* Create Recipe from Session Modal *!/*/}
|
{/*/!* Create Recipe from Session Modal *!/*/}
|
||||||
{/*<CreateRecipeFromSessionModal*/}
|
{/*<CreateRecipeFromSessionModal*/}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { ChatState } from '../types/chatState';
|
import { ChatState } from '../types/chatState';
|
||||||
import { Conversation, Message, resumeAgent, Session } from '../api';
|
import {
|
||||||
|
Conversation,
|
||||||
|
Message,
|
||||||
|
resumeAgent,
|
||||||
|
Session,
|
||||||
|
updateFromSession,
|
||||||
|
updateSessionUserRecipeValues,
|
||||||
|
} from '../api';
|
||||||
import { getApiUrl } from '../config';
|
import { getApiUrl } from '../config';
|
||||||
import { createUserMessage, getCompactingMessage, getThinkingMessage } from '../types/message';
|
import { createUserMessage, getCompactingMessage, getThinkingMessage } from '../types/message';
|
||||||
|
|
||||||
@@ -71,6 +78,7 @@ interface UseChatStreamReturn {
|
|||||||
messages: Message[];
|
messages: Message[];
|
||||||
chatState: ChatState;
|
chatState: ChatState;
|
||||||
handleSubmit: (userMessage: string) => Promise<void>;
|
handleSubmit: (userMessage: string) => Promise<void>;
|
||||||
|
setRecipeUserParams: (values: Record<string, string>) => Promise<void>;
|
||||||
stopStreaming: () => void;
|
stopStreaming: () => void;
|
||||||
sessionLoadError?: string;
|
sessionLoadError?: string;
|
||||||
}
|
}
|
||||||
@@ -370,6 +378,44 @@ export function useChatStream({
|
|||||||
[sessionId, setMessagesAndLog, onFinish]
|
[sessionId, setMessagesAndLog, onFinish]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setRecipeUserParams = useCallback(
|
||||||
|
async (user_recipe_values: Record<string, string>) => {
|
||||||
|
if (session) {
|
||||||
|
await updateSessionUserRecipeValues({
|
||||||
|
path: {
|
||||||
|
session_id: sessionId,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
userRecipeValues: user_recipe_values,
|
||||||
|
},
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
// TODO(Douwe): get this from the server instead of emulating it here
|
||||||
|
setSession({
|
||||||
|
...session,
|
||||||
|
user_recipe_values,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setSessionLoadError("can't call setRecipeParams without a session");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[sessionId, session, setSessionLoadError]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// This should happen on the server when the session is loaded or changed
|
||||||
|
// use session.id to support changing of sessions rather than depending on the
|
||||||
|
// stable sessionId.
|
||||||
|
if (session) {
|
||||||
|
updateFromSession({
|
||||||
|
body: {
|
||||||
|
session_id: session.id,
|
||||||
|
},
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [session]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialMessage && session && messages.length === 0 && chatState === ChatState.Idle) {
|
if (initialMessage && session && messages.length === 0 && chatState === ChatState.Idle) {
|
||||||
log.messages('auto-submit-initial', 0, { initialMessage: initialMessage.slice(0, 50) });
|
log.messages('auto-submit-initial', 0, { initialMessage: initialMessage.slice(0, 50) });
|
||||||
@@ -397,5 +443,6 @@ export function useChatStream({
|
|||||||
chatState,
|
chatState,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
stopStreaming,
|
stopStreaming,
|
||||||
|
setRecipeUserParams,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user