SIGN IN SIGN UP

AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.

0 0 73 Python

fix(frontend/library): unify schedule cache invalidation across all 4 affected query keys (#13204)

## Why

Followup to **#13202** (the autopilot UX + unified Scheduled page PR I
just merged).

During a critical post-merge audit prompted by the user's "be critical,
test all corner cases" prompt, I found that the unified
`/library/followups` page + the new "Autopilot library" briefing pill
BOTH read from the user-wide `/api/v1/schedules` endpoint, while the
existing per-agent schedule UI (`/library/agents/{id}`) reads from the
per-graph `/api/v1/graphs/{id}/schedules` endpoint. These are different
React Query keys backed by different endpoints, but they cache
**overlapping data** — every graph schedule lands in both.

Every mutation site (8 total — 1 from #13202, 7 pre-existing) was only
invalidating ONE of the affected keys. **Native /pr-test surfaced a 4th
stale consumer**: the `/library` fleet-summary "Scheduled" count derives
from `agent.is_scheduled` on the library-agents query, which no mutation
site ever invalidated.

Net effect: every schedule create / edit / delete leaves at least one
consumer (and often two) with stale cache until manual reload.

## What

**Single shared invalidator** wired into all 8 mutation sites,
invalidating **4 query keys**:

| Query key | Consumer |
|---|---|
| `/api/v1/schedules` (user-wide) | unified `/library/followups` +
Autopilot library pill |
| `/api/v1/copilot/followups` | copilot followup list inside the unified
page |
| `/api/v1/graphs/{id}/schedules` (per-graph) | agent detail sidebar +
selected-schedule view |
| `/api/library/agents` (partial-key match) | `/library` fleet-summary
"Scheduled" tab count, all variants (infinite, search, filter) |

| Mutation site | Old invalidation | Now |
|---|---|---|
| `useGraphScheduleListItem` (unified page delete — #13202) | user-wide
only | ALL four |
| `useFollowupListItem` (unified page followup delete — #13202) |
copilot-followups only | ALL four |
| `useScheduleDetailHeader` (agent detail delete) | per-graph only | ALL
four |
| `useSelectedScheduleActions` (selected-schedule delete) | per-graph
only | ALL four |
| `ScheduleActionsDropdown` (sidebar dropdown delete) | per-graph only |
ALL four |
| `useScheduleAgentModal` (create from agent detail) | per-graph only |
ALL four |
| `useEditScheduleModal` (PATCH from agent detail) | per-graph only |
ALL four |
| `useCronSchedulerDialog` (create from agent **builder**) | **NONE** 🐛
| ALL four |

That last one is the worst pre-existing bug: scheduling from the builder
didn't refresh the agent detail page either — completely independent of
my PR.

## How

New helper at
`autogpt_platform/frontend/src/services/schedules/invalidate-schedules.ts`:

```ts
export function invalidateAllScheduleQueries(
  queryClient: QueryClient,
  graphId?: string,
) {
  queryClient.invalidateQueries({ queryKey: getGetV1ListExecutionSchedulesForAUserQueryKey() });
  queryClient.invalidateQueries({ queryKey: getListCopilotFollowupSchedulesQueryKey() });
  queryClient.invalidateQueries({ queryKey: ["/api/library/agents"] }); // partial-key — hits every variant
  if (graphId) {
    queryClient.invalidateQueries({ queryKey: getGetV1ListExecutionSchedulesForAGraphQueryKey(graphId) });
  }
}
```

Every mutation site now calls this single helper instead of
cherry-picking one key. `graphId` is optional because copilot followup
mutations don't bind to a specific graph.

The library-agents key (`["/api/library/agents"]`) is matched as a
**partial prefix** — Tanstack Query's default behaviour — so it catches
the bare query AND every variant with params (search, filter,
pagination, plus the infinite-query form used by `/library`).

## Test coverage

- **Helper unit tests**: `invalidate-schedules.test.ts` — 2 tests
verifying both branches (with + without graphId) and asserting the exact
set of 3 or 4 invalidated query keys.
- **5 new hook test files** with renderHook + MSW, one per modified hook
— each spies on `invalidateAllScheduleQueries` to assert it's called
with the right `graphId` on the success path:
  - `useScheduleDetailHeader.test.tsx` (3 tests)
  - `useSelectedScheduleActions.test.tsx` (3 tests)
  - `useScheduleAgentModal.test.tsx` (2 tests)
- `useEditScheduleModal.test.tsx` (2 tests, with restored
`globalThis.fetch` per CodeRabbit nit)
- `useCronSchedulerDialog.test.tsx` (2 tests — explicit regression for
the previously-zero-invalidation bug)
- **Native /pr-test**: 4 scenarios pass on a local poetry/pnpm stack
with real backend + real browser interactions. See [test report
comment](https://github.com/Significant-Gravitas/AutoGPT/pull/13204#issuecomment-4527332405)
for screenshots.
- **Full vitest suite**: 2802 tests pass locally; codecov patch above
the 70% target.

## Out of scope

- No backend changes — pure client-side cache hygiene.
- The execution `runs` query (`getGetV1ListGraphExecutionsQueryKey`) is
intentionally NOT included in the helper since not every schedule
mutation creates a run; only the "Run now" path needs it and that
already invalidates it inline.

## Checklist

- [x] Code follows project style guidelines
- [x] Self-review performed
- [x] Helper unit-tested + every changed hook unit-tested
- [x] Native /pr-test confirms cross-page propagation across 4 scenarios
- [x] No new warnings
- [x] Pre-existing behavior preserved (mutations still invalidate the
keys they used to + the missing ones)
- [x] CI green
Z
Zamil Majdy committed
a13e70fd37a6bfe15019df78d7f841f73e5380ff
Parent: 5a93de3
Committed by GitHub <noreply@github.com> on 5/24/2026, 5:21:05 AM