mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-28 22:17:48 +02:00
* feat(autopilot): add scheduled/triggered automation for AI agents Introduce the Autopilot feature — recurring automations that assign work to AI agents on a schedule or manual trigger. Supports two execution modes: create_issue (creates an issue for the agent to work on) and run_only (directly enqueues an agent task without issue pollution). Backend: migration (3 tables + 2 columns), sqlc queries, AutopilotService with concurrency policies (skip/queue/replace), HTTP CRUD + trigger endpoints, background cron scheduler (30s tick), event listeners for issue→run and task→run status sync. Frontend: types, API client methods, TanStack Query hooks with optimistic mutations, realtime cache invalidation, list page with create dialog, detail page with trigger management and run history, sidebar nav + routes for both web and desktop apps. * feat(autopilot): improve UX — trigger config, edit dialog, template gallery - Replace raw cron input with friendly frequency tabs (Hourly/Daily/Weekdays/Weekly/Custom), time picker, and timezone dropdown defaulting to user's local timezone - Fix Select components showing UUIDs instead of names (Base UI render function pattern) - Add Edit button on detail page opening a unified edit dialog - Remove project/concurrency/issue-title-template from create/edit (simplify for users) - Add trigger configuration inline during autopilot creation - Add template gallery on empty state (6 step-by-step workflow templates) - Rename "Description" to "Prompt" throughout UI - Inject autopilot run timestamp into issue description for agent date awareness - Treat issue status "in_review" as run completion (fixes skip on next trigger) - Make migration idempotent with IF NOT EXISTS clauses
35 lines
1.0 KiB
TypeScript
35 lines
1.0 KiB
TypeScript
import { queryOptions } from "@tanstack/react-query";
|
|
import { api } from "../api";
|
|
|
|
export const autopilotKeys = {
|
|
all: (wsId: string) => ["autopilots", wsId] as const,
|
|
list: (wsId: string) => [...autopilotKeys.all(wsId), "list"] as const,
|
|
detail: (wsId: string, id: string) =>
|
|
[...autopilotKeys.all(wsId), "detail", id] as const,
|
|
runs: (wsId: string, id: string) =>
|
|
[...autopilotKeys.all(wsId), "runs", id] as const,
|
|
};
|
|
|
|
export function autopilotListOptions(wsId: string) {
|
|
return queryOptions({
|
|
queryKey: autopilotKeys.list(wsId),
|
|
queryFn: () => api.listAutopilots(),
|
|
select: (data) => data.autopilots,
|
|
});
|
|
}
|
|
|
|
export function autopilotDetailOptions(wsId: string, id: string) {
|
|
return queryOptions({
|
|
queryKey: autopilotKeys.detail(wsId, id),
|
|
queryFn: () => api.getAutopilot(id),
|
|
});
|
|
}
|
|
|
|
export function autopilotRunsOptions(wsId: string, id: string) {
|
|
return queryOptions({
|
|
queryKey: autopilotKeys.runs(wsId, id),
|
|
queryFn: () => api.listAutopilotRuns(id),
|
|
select: (data) => data.runs,
|
|
});
|
|
}
|