Show update instructions CTA to trigger copilot when new data sources are attached to agents

This commit is contained in:
akhisud3195 2025-05-09 19:41:10 +05:30
parent e4cd71e6b1
commit 5bc1dc8b37
3 changed files with 82 additions and 14 deletions

View file

@ -34,7 +34,7 @@ interface AppProps {
dataSources?: z.infer<typeof DataSource>[]; dataSources?: z.infer<typeof DataSource>[];
} }
const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ const App = forwardRef<{ handleCopyChat: () => void; handleUserMessage: (message: string) => void }, AppProps>(function App({
projectId, projectId,
workflow, workflow,
dispatch, dispatch,
@ -133,7 +133,8 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({
}, [messages, onCopyJson]); }, [messages, onCopyJson]);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
handleCopyChat handleCopyChat,
handleUserMessage
}), [handleCopyChat]); }), [handleCopyChat]);
return ( return (
@ -194,25 +195,25 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({
); );
}); });
export function Copilot({ export const Copilot = forwardRef<{ handleUserMessage: (message: string) => void }, {
projectId,
workflow,
chatContext = undefined,
dispatch,
isInitialState = false,
dataSources,
}: {
projectId: string; projectId: string;
workflow: z.infer<typeof Workflow>; workflow: z.infer<typeof Workflow>;
chatContext?: z.infer<typeof CopilotChatContext>; chatContext?: z.infer<typeof CopilotChatContext>;
dispatch: (action: WorkflowDispatch) => void; dispatch: (action: WorkflowDispatch) => void;
isInitialState?: boolean; isInitialState?: boolean;
dataSources?: z.infer<typeof DataSource>[]; dataSources?: z.infer<typeof DataSource>[];
}) { }>(({
projectId,
workflow,
chatContext = undefined,
dispatch,
isInitialState = false,
dataSources,
}, ref) => {
const [copilotKey, setCopilotKey] = useState(0); const [copilotKey, setCopilotKey] = useState(0);
const [showCopySuccess, setShowCopySuccess] = useState(false); const [showCopySuccess, setShowCopySuccess] = useState(false);
const [messages, setMessages] = useState<z.infer<typeof CopilotMessage>[]>([]); const [messages, setMessages] = useState<z.infer<typeof CopilotMessage>[]>([]);
const appRef = useRef<{ handleCopyChat: () => void }>(null); const appRef = useRef<{ handleCopyChat: () => void; handleUserMessage: (message: string) => void }>(null);
function handleNewChat() { function handleNewChat() {
setCopilotKey(prev => prev + 1); setCopilotKey(prev => prev + 1);
@ -228,6 +229,16 @@ export function Copilot({
}, 2000); }, 2000);
} }
// Expose handleUserMessage through ref
useImperativeHandle(ref, () => ({
handleUserMessage: (message: string) => {
const app = appRef.current as any;
if (app?.handleUserMessage) {
app.handleUserMessage(message);
}
}
}), []);
return ( return (
<Panel variant="copilot" <Panel variant="copilot"
tourTarget="copilot" tourTarget="copilot"
@ -288,5 +299,5 @@ export function Copilot({
</div> </div>
</Panel> </Panel>
); );
} });

View file

@ -22,6 +22,7 @@ import { EditableField } from "@/app/lib/components/editable-field";
import { USE_TRANSFER_CONTROL_OPTIONS } from "@/app/lib/feature_flags"; import { USE_TRANSFER_CONTROL_OPTIONS } from "@/app/lib/feature_flags";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Info } from "lucide-react"; import { Info } from "lucide-react";
import { useCopilot } from "../copilot/use-copilot";
// Common section header styles // Common section header styles
const sectionHeaderStyles = "text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400"; const sectionHeaderStyles = "text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400";
@ -44,6 +45,7 @@ export function AgentConfig({
handleUpdate, handleUpdate,
handleClose, handleClose,
useRag, useRag,
triggerCopilotChat,
}: { }: {
projectId: string, projectId: string,
workflow: z.infer<typeof Workflow>, workflow: z.infer<typeof Workflow>,
@ -56,6 +58,7 @@ export function AgentConfig({
handleUpdate: (agent: z.infer<typeof WorkflowAgent>) => void, handleUpdate: (agent: z.infer<typeof WorkflowAgent>) => void,
handleClose: () => void, handleClose: () => void,
useRag: boolean, useRag: boolean,
triggerCopilotChat: (message: string) => void,
}) { }) {
const [isAdvancedConfigOpen, setIsAdvancedConfigOpen] = useState(false); const [isAdvancedConfigOpen, setIsAdvancedConfigOpen] = useState(false);
const [showGenerateModal, setShowGenerateModal] = useState(false); const [showGenerateModal, setShowGenerateModal] = useState(false);
@ -65,11 +68,42 @@ export function AgentConfig({
const [localName, setLocalName] = useState(agent.name); const [localName, setLocalName] = useState(agent.name);
const [nameError, setNameError] = useState<string | null>(null); const [nameError, setNameError] = useState<string | null>(null);
const [activeTab, setActiveTab] = useState<TabType>('instructions'); const [activeTab, setActiveTab] = useState<TabType>('instructions');
const [showRagCta, setShowRagCta] = useState(false);
const [previousRagSources, setPreviousRagSources] = useState<string[]>([]);
const {
start: startCopilotChat,
} = useCopilot({
projectId,
workflow,
context: null,
dataSources
});
useEffect(() => { useEffect(() => {
setLocalName(agent.name); setLocalName(agent.name);
}, [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 // Add effect to handle control type update when transfer control is disabled
useEffect(() => { useEffect(() => {
if (!USE_TRANSFER_CONTROL_OPTIONS && agent.controlType !== 'retain') { if (!USE_TRANSFER_CONTROL_OPTIONS && agent.controlType !== 'retain') {
@ -455,7 +489,7 @@ export function AgentConfig({
RAG RAG
</label> </label>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<div> <div className="flex items-center gap-3">
<Select <Select
variant="bordered" variant="bordered"
placeholder="Add data source" placeholder="Add data source"
@ -481,6 +515,17 @@ export function AgentConfig({
)) ))
} }
</Select> </Select>
{showRagCta && (
<CustomButton
variant="primary"
size="sm"
onClick={handleUpdateInstructions}
className="whitespace-nowrap"
>
Update Instructions
</CustomButton>
)}
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">

View file

@ -611,6 +611,16 @@ export function WorkflowEditor({
const [isMcpImportModalOpen, setIsMcpImportModalOpen] = useState(false); const [isMcpImportModalOpen, setIsMcpImportModalOpen] = useState(false);
const [isInitialState, setIsInitialState] = useState(true); const [isInitialState, setIsInitialState] = useState(true);
const [showTour, setShowTour] = useState(true); const [showTour, setShowTour] = useState(true);
const copilotRef = useRef<{ handleUserMessage: (message: string) => void }>(null);
// Function to trigger copilot chat
const triggerCopilotChat = useCallback((message: string) => {
setShowCopilot(true);
// Small delay to ensure copilot is mounted
setTimeout(() => {
copilotRef.current?.handleUserMessage(message);
}, 100);
}, []);
console.log(`workflow editor chat key: ${state.present.chatKey}`); console.log(`workflow editor chat key: ${state.present.chatKey}`);
@ -992,6 +1002,7 @@ export function WorkflowEditor({
handleUpdate={handleUpdateAgent.bind(null, state.present.selection.name)} handleUpdate={handleUpdateAgent.bind(null, state.present.selection.name)}
handleClose={handleUnselectAgent} handleClose={handleUnselectAgent}
useRag={useRag} useRag={useRag}
triggerCopilotChat={triggerCopilotChat}
/>} />}
{state.present.selection?.type === "tool" && <ToolConfig {state.present.selection?.type === "tool" && <ToolConfig
key={state.present.selection.name} key={state.present.selection.name}
@ -1020,6 +1031,7 @@ export function WorkflowEditor({
onResize={(size) => setCopilotWidth(size)} onResize={(size) => setCopilotWidth(size)}
> >
<Copilot <Copilot
ref={copilotRef}
projectId={state.present.workflow.projectId} projectId={state.present.workflow.projectId}
workflow={state.present.workflow} workflow={state.present.workflow}
dispatch={dispatch} dispatch={dispatch}