diff --git a/apps/rowboat/app/projects/[projectId]/copilot/app.tsx b/apps/rowboat/app/projects/[projectId]/copilot/app.tsx index 251dba04..b352f8d3 100644 --- a/apps/rowboat/app/projects/[projectId]/copilot/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/copilot/app.tsx @@ -34,7 +34,7 @@ interface AppProps { dataSources?: z.infer[]; } -const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ +const App = forwardRef<{ handleCopyChat: () => void; handleUserMessage: (message: string) => void }, AppProps>(function App({ projectId, workflow, dispatch, @@ -133,7 +133,8 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ }, [messages, onCopyJson]); useImperativeHandle(ref, () => ({ - handleCopyChat + handleCopyChat, + handleUserMessage }), [handleCopyChat]); return ( @@ -194,25 +195,25 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ ); }); -export function Copilot({ - projectId, - workflow, - chatContext = undefined, - dispatch, - isInitialState = false, - dataSources, -}: { +export const Copilot = forwardRef<{ handleUserMessage: (message: string) => void }, { projectId: string; workflow: z.infer; chatContext?: z.infer; dispatch: (action: WorkflowDispatch) => void; isInitialState?: boolean; dataSources?: z.infer[]; -}) { +}>(({ + projectId, + workflow, + chatContext = undefined, + dispatch, + isInitialState = false, + dataSources, +}, ref) => { const [copilotKey, setCopilotKey] = useState(0); const [showCopySuccess, setShowCopySuccess] = useState(false); const [messages, setMessages] = useState[]>([]); - const appRef = useRef<{ handleCopyChat: () => void }>(null); + const appRef = useRef<{ handleCopyChat: () => void; handleUserMessage: (message: string) => void }>(null); function handleNewChat() { setCopilotKey(prev => prev + 1); @@ -228,6 +229,16 @@ export function Copilot({ }, 2000); } + // Expose handleUserMessage through ref + useImperativeHandle(ref, () => ({ + handleUserMessage: (message: string) => { + const app = appRef.current as any; + if (app?.handleUserMessage) { + app.handleUserMessage(message); + } + } + }), []); + return ( ); -} +}); diff --git a/apps/rowboat/app/projects/[projectId]/entities/agent_config.tsx b/apps/rowboat/app/projects/[projectId]/entities/agent_config.tsx index 1b6163f6..13425d64 100644 --- a/apps/rowboat/app/projects/[projectId]/entities/agent_config.tsx +++ b/apps/rowboat/app/projects/[projectId]/entities/agent_config.tsx @@ -22,6 +22,7 @@ import { EditableField } from "@/app/lib/components/editable-field"; import { USE_TRANSFER_CONTROL_OPTIONS } from "@/app/lib/feature_flags"; import { Input } from "@/components/ui/input"; import { Info } from "lucide-react"; +import { useCopilot } from "../copilot/use-copilot"; // Common section header styles const sectionHeaderStyles = "text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400"; @@ -44,6 +45,7 @@ export function AgentConfig({ handleUpdate, handleClose, useRag, + triggerCopilotChat, }: { projectId: string, workflow: z.infer, @@ -56,6 +58,7 @@ export function AgentConfig({ handleUpdate: (agent: z.infer) => void, handleClose: () => void, useRag: boolean, + triggerCopilotChat: (message: string) => void, }) { const [isAdvancedConfigOpen, setIsAdvancedConfigOpen] = useState(false); const [showGenerateModal, setShowGenerateModal] = useState(false); @@ -65,11 +68,42 @@ export function AgentConfig({ const [localName, setLocalName] = useState(agent.name); const [nameError, setNameError] = useState(null); const [activeTab, setActiveTab] = useState('instructions'); + const [showRagCta, setShowRagCta] = useState(false); + const [previousRagSources, setPreviousRagSources] = useState([]); + const { + start: startCopilotChat, + } = useCopilot({ + projectId, + workflow, + context: null, + dataSources + }); + useEffect(() => { setLocalName(agent.name); }, [agent.name]); + // Track changes in RAG datasources + useEffect(() => { + const currentSources = agent.ragDataSources || []; + // Show CTA when transitioning from 0 to 1 datasource + if (currentSources.length === 1 && previousRagSources.length === 0) { + setShowRagCta(true); + } + // Hide CTA when all datasources are deleted + if (currentSources.length === 0) { + setShowRagCta(false); + } + setPreviousRagSources(currentSources); + }, [agent.ragDataSources]); + + const handleUpdateInstructions = async () => { + const message = `Update the instructions for agent "${agent.name}" to use the rag tool (rag_search) since data sources have been added. If this has already been done, do not take any action, but let me know.`; + triggerCopilotChat(message); + setShowRagCta(false); + }; + // Add effect to handle control type update when transfer control is disabled useEffect(() => { if (!USE_TRANSFER_CONTROL_OPTIONS && agent.controlType !== 'retain') { @@ -455,7 +489,7 @@ export function AgentConfig({ RAG
-
+