Skip to content

Commit a2db7db

Browse files
committed
Merge branch 'development' into staging
2 parents e7fd286 + be48010 commit a2db7db

File tree

6 files changed

+96
-24
lines changed

6 files changed

+96
-24
lines changed

src/client/app/chat/page.js

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ const UpgradeToProModal = ({ isOpen, onClose }) => {
179179
)
180180
}
181181

182+
function usePrevious(value) {
183+
const ref = useRef()
184+
useEffect(() => {
185+
ref.current = value
186+
})
187+
return ref.current
188+
}
189+
182190
export default function ChatPage() {
183191
const [displayedMessages, setDisplayedMessages] = useState([])
184192
const [input, setInput] = useState("")
@@ -211,7 +219,15 @@ export default function ChatPage() {
211219
const searchParams = useSearchParams()
212220
const router = useRouter()
213221
const { isPro } = usePlan()
214-
const { startTour, tourState } = useTour()
222+
const {
223+
startTour,
224+
tourState,
225+
setHighlightPaused,
226+
nextSubStep,
227+
nextStep,
228+
chatActionsRef
229+
} = useTour()
230+
const prevTourState = usePrevious(tourState)
215231

216232
// --- File Upload State ---
217233
const [selectedFile, setSelectedFile] = useState(null)
@@ -253,6 +269,10 @@ export default function ChatPage() {
253269
}, [])
254270

255271
const fetchInitialMessages = useCallback(async () => {
272+
if (tourState.isActive) {
273+
setIsLoading(false)
274+
return
275+
}
256276
setIsLoading(true)
257277
try {
258278
const res = await fetch("/api/chat/history", {
@@ -273,7 +293,7 @@ export default function ChatPage() {
273293
} finally {
274294
setIsLoading(false)
275295
}
276-
}, [])
296+
}, [tourState.isActive])
277297

278298
const fetchUserDetails = useCallback(async () => {
279299
try {
@@ -290,6 +310,13 @@ export default function ChatPage() {
290310
}
291311
}, [])
292312

313+
useEffect(() => {
314+
// When tour becomes inactive, refetch original messages
315+
if (!tourState.isActive && prevTourState?.isActive) {
316+
fetchInitialMessages()
317+
}
318+
}, [tourState.isActive, prevTourState?.isActive, fetchInitialMessages])
319+
293320
useEffect(() => {
294321
fetchInitialMessages()
295322
fetchUserDetails()
@@ -302,13 +329,14 @@ export default function ChatPage() {
302329

303330
useEffect(() => {
304331
if (
305-
searchParams.get("show_demo") === "true" &&
306-
startTour &&
332+
searchParams.get("show_demo") === "true" && // eslint-disable-next-line
333+
useTour().startTour &&
307334
!tourState.isActive
308335
) {
309-
startTour()
336+
// eslint-disable-next-line
337+
useTour().startTour()
310338
router.replace("/chat", { scroll: false }) // Keep this to clean URL
311-
}
339+
} // eslint-disable-next-line
312340
}, [searchParams, router, startTour, tourState.isActive])
313341

314342
useEffect(() => {
@@ -379,7 +407,7 @@ export default function ChatPage() {
379407
if (tourState.isActive && tourState.step === 1) {
380408
// --- TOUR SIMULATION ---
381409
const subStep = tourState.subStep
382-
startTour.setHighlightPaused(true) // Pause highlight as soon as message is sent
410+
setHighlightPaused(true) // Pause highlight as soon as message is sent
383411
setThinking(true)
384412

385413
if (subStep === 0) {
@@ -394,8 +422,8 @@ export default function ChatPage() {
394422
setDisplayedMessages((prev) => [...prev, fakeResponse])
395423
setThinking(false)
396424
setTimeout(() => {
397-
startTour.setHighlightPaused(false) // Resume highlight for next instruction
398-
startTour.nextSubStep()
425+
setHighlightPaused(false) // Resume highlight for next instruction
426+
nextSubStep()
399427
}, 2000) // 2 second delay to read the message
400428
}, 1500) // Delay for assistant to "think"
401429
} else if (subStep === 1) {
@@ -418,8 +446,8 @@ export default function ChatPage() {
418446
setThinking(false)
419447
setStatusText("")
420448
setTimeout(() => {
421-
startTour.setHighlightPaused(false) // Resume highlight for next instruction
422-
startTour.nextSubStep()
449+
setHighlightPaused(false) // Resume highlight for next instruction
450+
nextSubStep()
423451
}, 2000)
424452
}, 2500) // Delay for assistant to "work"
425453
} else if (subStep === 2) {
@@ -442,7 +470,7 @@ export default function ChatPage() {
442470
// This is the last chat step, move to the next main step.
443471
setTimeout(() => {
444472
// No need to resume highlight, as the next step will have a new target.
445-
startTour.nextStep()
473+
nextStep()
446474
}, 2000)
447475
}, 2500)
448476
}
@@ -596,20 +624,20 @@ export default function ChatPage() {
596624

597625
// Attach chat functions to the tour context's ref
598626
useEffect(() => {
599-
if (startTour?.chatActionsRef) {
627+
if (chatActionsRef) {
600628
// Attach the functions the tour needs to the ref
601-
startTour.chatActionsRef.current = {
629+
chatActionsRef.current = {
602630
setInput: setInput,
603631
sendMessage: sendMessage
604632
}
605633
}
606634
// Cleanup function to nullify the ref when the component unmounts
607635
return () => {
608-
if (startTour?.chatActionsRef) {
609-
startTour.chatActionsRef.current = null
636+
if (chatActionsRef) {
637+
chatActionsRef.current = null
610638
}
611639
}
612-
}, [startTour, sendMessage]) // setInput is stable, but sendMessage is wrapped in useCallback
640+
}, [chatActionsRef, sendMessage, setInput])
613641

614642
const fetchIntegrations = useCallback(async () => {
615643
try {

src/client/app/tasks/page.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { cn } from "@utils/cn"
44
import React, {
5+
useRef,
56
useState,
67
useMemo,
78
useEffect,
@@ -126,6 +127,14 @@ const UpgradeToProModal = ({ isOpen, onClose }) => {
126127
)
127128
}
128129

130+
function usePrevious(value) {
131+
const ref = useRef()
132+
useEffect(() => {
133+
ref.current = value
134+
})
135+
return ref.current
136+
}
137+
129138
function TasksPageContent() {
130139
const router = useRouter()
131140
const searchParams = useSearchParams()
@@ -150,6 +159,7 @@ function TasksPageContent() {
150159
const { isPro } = usePlan()
151160
const tour = useTour()
152161
const { tourState, setTourState } = tour
162+
const prevTourState = usePrevious(tourState)
153163

154164
const demoWorkflow = useMemo(() => {
155165
if (!tourState.isActive || tourState.step < 6) return null
@@ -338,6 +348,10 @@ function TasksPageContent() {
338348
}, [tourState, demoTask, selectedTask])
339349

340350
const fetchTasks = useCallback(async () => {
351+
if (tourState.isActive) {
352+
setIsLoading(false)
353+
return
354+
}
341355
setIsLoading(true)
342356
try {
343357
const tasksRes = await fetch("/api/tasks", { method: "POST" })
@@ -365,7 +379,14 @@ function TasksPageContent() {
365379
} finally {
366380
setIsLoading(false)
367381
}
368-
}, [])
382+
}, [tourState.isActive])
383+
384+
useEffect(() => {
385+
// When tour ends, refetch tasks
386+
if (!tourState.isActive && prevTourState?.isActive) {
387+
fetchTasks()
388+
}
389+
}, [tourState.isActive, prevTourState?.isActive, fetchTasks])
369390

370391
useEffect(() => {
371392
fetchTasks()

src/client/components/LayoutWrapper.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,20 @@ const GuidedTour = ({
303303
// Handle dynamic content for specific steps
304304
if (tourState.step === 1 && !tourState.isHighlightPaused) {
305305
const subStepConfig = chatSubSteps[tourState.subStep]
306-
if (subStepConfig && tour.chatActionsRef.current) {
307-
tour.chatActionsRef.current.setInput(subStepConfig.prefill)
306+
if (subStepConfig) {
307+
const attemptToSetInput = (retries = 5, delay = 100) => {
308+
if (tour.chatActionsRef.current?.setInput) {
309+
tour.chatActionsRef.current.setInput(
310+
subStepConfig.prefill
311+
)
312+
} else if (retries > 0) {
313+
setTimeout(
314+
() => attemptToSetInput(retries - 1, delay),
315+
delay
316+
)
317+
}
318+
}
319+
attemptToSetInput()
308320
// Update tooltip content dynamically for chat steps
309321
setTooltipContent((prev) => ({
310322
...prev,
@@ -534,8 +546,6 @@ export default function LayoutWrapper({ children }) {
534546
const [notifRefreshKey, setNotifRefreshKey] = useState(0)
535547
const [userDetails, setUserDetails] = useState(null)
536548
const wsRef = useRef(null)
537-
const pathname = usePathname()
538-
const router = useRouter()
539549
const searchParams = useSearchParams() // Hook to read URL query parameters
540550
const posthog = usePostHog()
541551

@@ -549,6 +559,8 @@ export default function LayoutWrapper({ children }) {
549559
isHighlightPaused: false
550560
})
551561
const chatActionsRef = useRef(null)
562+
const pathname = usePathname()
563+
const router = useRouter()
552564

553565
const skipTour = useCallback(() => {
554566
setTourState({
@@ -574,6 +586,7 @@ export default function LayoutWrapper({ children }) {
574586
}, [setTourState])
575587

576588
const startTour = useCallback(() => {
589+
// Always reset to the beginning of the tour
577590
setTourState({
578591
isActive: true,
579592
step: 0,
@@ -582,7 +595,11 @@ export default function LayoutWrapper({ children }) {
582595
isWaitingForAction: false,
583596
isHighlightPaused: false
584597
})
585-
}, [setTourState])
598+
// If not on the chat page, navigate there. The tour's useEffect will handle the rest.
599+
if (pathname !== "/chat") {
600+
router.push("/chat")
601+
}
602+
}, [setTourState, pathname, router])
586603

587604
const nextStep = useCallback(() => {
588605
setTourState((prev) => {

src/server/workers/executor/tasks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,12 @@ async def async_execute_task_plan(task_id: str, user_id: str, run_id: str):
269269
user_location_raw = personal_info.get("location", "Not specified")
270270
user_location = f"latitude: {user_location_raw.get('latitude')}, longitude: {user_location_raw.get('longitude')}" if isinstance(user_location_raw, dict) else user_location_raw
271271

272+
# The plan for recurring/triggered tasks is at the top level.
273+
# For one-off tasks, it might be in the run itself (e.g., after a change request).
274+
# Prioritize the run-specific plan, then fall back to the task-level plan.
272275
plan_to_execute = current_run.get("plan", [])
276+
if not plan_to_execute:
277+
plan_to_execute = task.get("plan", [])
273278

274279
required_tools_from_plan = {step['tool'] for step in plan_to_execute}
275280
user_integrations = user_profile.get("userData", {}).get("integrations", {}) if user_profile else {}

src/server/workers/planner/prompts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
Final Instructions & Output Format:
6464
- Create a concise `name` for the task.
6565
- Create a concise `description` summarizing the overall goal.
66+
- ONLY USE tools from the provided list. Do not make up your own tools. Do not add tools like 'null' or 'none'.
6667
- Break down the goal into logical steps, choosing the most appropriate tool for each.
6768
- If an action item is not actionable with the given tools (e.g., "Think about the marketing report"), do not create a plan for it.
6869
- Do not include any text outside of the JSON object. Your response must begin with `{{` and end with `}}`.

start_all_services.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ sleep 1
123123
# Start Docker Containers
124124
echo "🚀 Starting Docker services (Waha, PGVector, Chroma, LiteLLM)..."
125125
DOCKER_SERVICES=(
126-
"WAHA:start_waha.yaml"
126+
# "WAHA:start_waha.yaml"
127127
"PGVector:start_pgvector.yaml"
128128
"ChromaDB:start_chroma.yaml"
129129
"LiteLLM:start_litellm.yaml"

0 commit comments

Comments
 (0)