mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
refactor(copilot): simplify cancel-auto-approve route, derive countdown from timestamp
- Route always returns cancelled=True, reason branch was dead code since cancel_auto_approve() unconditionally returns True - Use crypto.randomUUID() for new step IDs to avoid same-millisecond collisions on rapid insert clicks - Re-derive secondsLeft from created_at+auto_approve_seconds on each tick (and on visibilitychange) instead of naive decrement; browsers throttle setInterval in background tabs, causing the displayed countdown to drift far behind wall-clock time
This commit is contained in:
@@ -861,11 +861,8 @@ async def cancel_auto_approve_task(
|
||||
|
||||
from backend.copilot.tools.decompose_goal import cancel_auto_approve
|
||||
|
||||
cancelled = await cancel_auto_approve(session_id)
|
||||
return CancelSessionResponse(
|
||||
cancelled=cancelled,
|
||||
reason=None if cancelled else "no_pending_auto_approve",
|
||||
)
|
||||
await cancel_auto_approve(session_id)
|
||||
return CancelSessionResponse(cancelled=True)
|
||||
|
||||
|
||||
@router.post(
|
||||
|
||||
@@ -170,7 +170,7 @@ export function DecomposeGoalTool({
|
||||
setEditableSteps((prev) => {
|
||||
const next = [...prev];
|
||||
next.splice(afterIndex + 1, 0, {
|
||||
step_id: `step_new_${Date.now()}`,
|
||||
step_id: `step_new_${crypto.randomUUID()}`,
|
||||
description: "",
|
||||
action: "add_block",
|
||||
status: "pending",
|
||||
@@ -186,14 +186,39 @@ export function DecomposeGoalTool({
|
||||
}
|
||||
}, [showActions, isEditing]);
|
||||
|
||||
// Tick down only while the timer is active.
|
||||
// Re-derive remaining seconds from ``created_at`` on every tick (and on
|
||||
// tab visibility change) instead of decrementing a local counter.
|
||||
// ``setInterval`` is aggressively throttled in backgrounded tabs, so a
|
||||
// naive ``s - 1`` drifts behind wall-clock time — the user could reopen
|
||||
// the tab well past the deadline and still see e.g. "Starting in 45".
|
||||
// Re-deriving keeps the UI in sync with the server-side timer.
|
||||
const createdAt =
|
||||
output && isDecompositionOutput(output) ? output.created_at : undefined;
|
||||
useEffect(() => {
|
||||
if (!showActions || !timerActive) return;
|
||||
const interval = setInterval(() => {
|
||||
setSecondsLeft((s) => Math.max(0, s - 1));
|
||||
}, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [showActions, timerActive, part.toolCallId]);
|
||||
const deadlineMs = createdAt
|
||||
? new Date(createdAt).getTime() + countdownSeconds * 1000
|
||||
: null;
|
||||
function recompute() {
|
||||
if (deadlineMs !== null && !Number.isNaN(deadlineMs)) {
|
||||
const remaining = Math.max(
|
||||
0,
|
||||
Math.round((deadlineMs - Date.now()) / 1000),
|
||||
);
|
||||
setSecondsLeft(Math.min(countdownSeconds, remaining));
|
||||
} else {
|
||||
// Legacy session with no ``created_at`` — fall back to naive decrement.
|
||||
setSecondsLeft((s) => Math.max(0, s - 1));
|
||||
}
|
||||
}
|
||||
recompute();
|
||||
const interval = setInterval(recompute, 1000);
|
||||
document.addEventListener("visibilitychange", recompute);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
document.removeEventListener("visibilitychange", recompute);
|
||||
};
|
||||
}, [showActions, timerActive, part.toolCallId, createdAt, countdownSeconds]);
|
||||
|
||||
// Auto-approve when countdown reaches 0. The client fires at 60s; the
|
||||
// server fires 5s later as a fallback for the "user closed the tab" case.
|
||||
|
||||
Reference in New Issue
Block a user