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.
feat(copilot): autopilot UX polish + skills/followups LD kill-switches + unified Scheduled page (#13202)
## Why Three things were left over after the autopilot consolidation shipped (#13190 + #13195): 1. **Naming drift** — the briefing pill said "Copilot library" even though the product is autopilot. 2. **Per-link hide on 0** — "1 skill · 0 follow-ups" reads as broken UX. Either count being zero should hide just that link. 3. **No kill-switch** — skills + scheduled-followups inject a `<available_skills>` / `<session_context>` block on every turn and gate the four MCP tools. If something regresses we need to disable them per-user without a redeploy. Plus one piece of unification a sleep-late-Friday user asked for: `/library/followups` should show **both** copilot followups AND recurring agent schedules, since they're the same APScheduler primitive with a `kind` discriminator and the UX of having two separate pages is silly. ## What ### LD kill-switches (default-on) Two new server-side LaunchDarkly flags, evaluated per-user, default `true`: - **`copilot-skills`** — gates the four MCP tools (`store_skill` / `read_skill` / `delete_skill` / `list_skills`) and the per-turn `<available_skills>` block. When off, `build_skills_context` returns empty (no list query, no Redis hit) and every tool returns a structured `feature_disabled` error. - **`copilot-scheduled-followups`** — gates the `schedule_followup` MCP tool and the `pending_followups` line inside `<session_context>`. When off, the tool returns `feature_disabled` and `build_session_context` collapses to the bare `session_id` line WITHOUT calling the scheduler RPC. Local override pattern unchanged: `FORCE_FLAG_COPILOT_SKILLS=false` / `FORCE_FLAG_COPILOT_SCHEDULED_FOLLOWUPS=false` for dev. ### Briefing pill (`CopilotLibrarySummary`) - Label: `Copilot library` → **`Autopilot library`**. - Counts are independent now: shows `N skill(s)` only if N > 0, shows `M scheduled` only if M > 0, drops the `·` separator when only one is shown. Still hides the whole pill when both are 0 (no degenerate state). - Scheduled count now sums **followups + graph schedules** so it mirrors what `/library/followups` displays. ### Unified Scheduled page (`/library/followups`) Route name unchanged for backward compat, but the page is now "Scheduled": - Title `Copilot follow-ups` → **`Scheduled`**. - `useFollowupsPage` fetches BOTH `listCopilotFollowupSchedules` AND `getV1ListExecutionSchedulesForAUser`, merges into a discriminated `ScheduleItem[]`, sorts by `next_run_time` ascending. - New `GraphScheduleListItem` component renders graph rows with an emerald "Agent run" badge, agent name, cron label, View dialog showing graph_id + schedule name, and a Delete flow that invalidates the graph-schedules query. - Existing `FollowupListItem` (copilot_turn) untouched — just rendered as one branch of the polymorphic list. - Empty-state copy: "No copilot follow-ups" → "Nothing scheduled" + mention both surfaces. ## How (highlights) - **Skills helper**: `is_skills_feature_enabled(user_id)` returns `True` for anonymous (no user_id) so we don't surprise-break unauthenticated paths; otherwise reads the flag with `default=True`. - **Followups helper**: `is_followups_feature_enabled(user_id)` same shape, lives in `session_context.py` so the gating function ships with the consumer. - **Cost half of the kill-switch**: when off, scheduler RPC / list-files / Redis fetches are all skipped — flipping the flag also drops the per-turn cost to zero, not "still calls but ignores result". - **Frontend merge over backend union**: kept the two existing typed REST endpoints (`/schedules` returns `list[GraphExecutionJobInfo]`, `/schedules/followups` returns `list[CopilotTurnJobInfo]`) and stitched them on the client. A unified `/schedules/all` endpoint with a discriminated union would have been cleaner but required a new model + openapi regen for marginal benefit. ## Test coverage - **Backend** (102 passed): - `build_skills_context_empty_when_flag_disabled` — short-circuit verified - `build_skills_context_normal_when_flag_enabled` — happy path still works - `store_skill_returns_feature_disabled_when_flag_off` + `list_skills_…` — tool gating - `build_session_context_skips_scheduler_when_followups_disabled` — verifies the scheduler RPC is NOT called when off (via `AssertionError(...)` side-effect on the mock) - `schedule_followup returns_feature_disabled_when_flag_off` — tool gating + scheduler spy - **Frontend**: existing skills + followups page suites should still pass post-rename; will run via CI. - **Live functional /pr-test**: planned on dev preview after the redeploy that pulls this commit. ## Out of scope - Unifying the MCP tool surface (one `schedule(kind=...)` instead of two tools) — refactor deferred. - New `/schedules/all` REST endpoint — frontend stitching is enough today. - Renaming the `/library/followups` route — backward compat with existing deep-links from the briefing pill etc. ## Checklist - [x] Code follows project style guidelines - [x] Self-review performed - [x] Tests added for new behaviors (flag-off paths) - [x] No new warnings - [x] Authorization unchanged — endpoints + helpers still scope by `user_id` from auth - [ ] CI green - [ ] `/pr-test` on dev-preview validates pill + Scheduled page + flag kill-switch
Z
Zamil Majdy committed
5a93de3f38b7c4e53fe5c3a44d35148b38beb43a
Parent: de39a05
Committed by GitHub <noreply@github.com>
on 5/24/2026, 2:53:39 AM