-
Notifications
You must be signed in to change notification settings - Fork 668
feat: timing task #1677
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: timing task #1677
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Implementation Plan | ||
|
|
||
| ## Architecture | ||
|
|
||
| - **Shared types** (`src/shared/scheduledTasks.ts`) define the `Trigger`, | ||
| `Action`, `ScheduledTask`, and `ScheduledTasksSettings` shapes. | ||
| - **Route contracts** (`src/shared/contracts/routes/scheduledTasks.routes.ts`) | ||
| expose `scheduledTasks.{list,upsert,delete,toggle,fireNow}` via Zod | ||
| schemas, mirroring `onboarding.routes.ts`. | ||
| - **Persistence** is handled in `ConfigPresenter` (`get/setScheduledTasks`) | ||
| with a `normalizeScheduledTasksConfig` pass identical in pattern to | ||
| `normalizeHooksNotificationsConfig`. | ||
| - **Scheduling** lives in a new `ScheduledTasksService` | ||
| (`src/main/presenter/scheduledTasks/index.ts`). One `setTimeout` per | ||
| armed task, chained at most 12h at a time. Public surface: | ||
| - `start()` — read tasks, run startup pass (one-shot backfill, arm next | ||
| slot for recurring), called from the existing lifecycle init flow. | ||
| - `stop()` — clear all armed timers (called on app shutdown). | ||
| - `list()` / `upsert(task)` / `delete(id)` / `toggle(id, enabled)` / | ||
| `fireNow(id)` — back the IPC routes and rearm timers on mutation. | ||
| - `computeNextFireAt(task, after)` — pure function, exported for tests. | ||
| - **Action dispatch** is a small helper inside the service: switch on | ||
| `task.action.kind`, then call `notificationPresenter` and/or | ||
| `eventBus.sendToRenderer(DEEPLINK_EVENTS.START, ...)` and/or | ||
| `sessionService.createSession(...)`. | ||
|
|
||
| ## Wiring | ||
|
|
||
| - `Presenter` constructor (`src/main/presenter/index.ts`) instantiates | ||
| `ScheduledTasksService` next to `hooksNotifications`, passing it | ||
| `configPresenter`, `notificationPresenter`, `windowPresenter`, and a | ||
| thunk that resolves `sessionService` lazily (the route runtime owns | ||
| sessionService, so the service exposes a setter the route runtime calls | ||
| during bootstrap). | ||
| - `src/main/routes/index.ts` wires the five new route cases against | ||
| `runtime.scheduledTasksService` and, in the same place that constructs | ||
| the runtime, sets the service's session-service reference so auto-send | ||
| has somewhere to call. | ||
| - Lifecycle `after-start` hook invokes `scheduledTasksService.start()` | ||
| after the other presenters have come up; the existing `beforeQuit` hook | ||
| calls `stop()`. | ||
|
|
||
| ## UI | ||
|
|
||
| - Settings navigation adds `settings-scheduled-tasks` (group `tools`, | ||
| position 5.6, icon `lucide:clock-9`). | ||
| - `ScheduledTasksSettings.vue` mirrors `NotificationsHooksSettings.vue`: | ||
| ScrollArea + header + "新建任务" button + bordered cards per task. | ||
| - A renderer client `ScheduledTasksClient.ts` matches the | ||
| `OnboardingClient` shape. | ||
| - i18n keys go in every locale under `routes.settings-scheduled-tasks` and | ||
| `settings.scheduledTasks.*` so `pnpm run i18n` stays green. | ||
|
|
||
| ## Validation | ||
|
|
||
| - `pnpm run format` | ||
| - `pnpm run i18n` | ||
| - `pnpm run lint` | ||
| - `pnpm run typecheck` | ||
| - Unit tests in `test/main/presenter/scheduledTasks.test.ts` cover | ||
| `computeNextFireAt` (daily wrap, weekly across the week, one-shot past | ||
| with/without `lastFiredAt`) and `normalizeScheduledTasksConfig` | ||
| (drops malformed entries, deduplicates ids, preserves valid ones). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # Scheduled Tasks | ||
|
|
||
| ## Problem | ||
|
|
||
| Closes [#1567](https://github.com/ThinkInAIXYZ/deepchat/issues/1567). | ||
|
|
||
| Users want to schedule "reminders" and "planned tasks" inside DeepChat — | ||
| either a plain notification ("drink water at 4pm every day") or a scheduled | ||
| chat prompt ("every morning at 9 ask the deepchat agent for today's plan"). | ||
| No equivalent feature exists today; the only time-aware paths are | ||
| `hooksNotifications` (event-driven, not time-driven) and the deeplink | ||
| "start" flow (which has `autoSend` security-disabled, so it can only | ||
| prefill a chat draft). | ||
|
|
||
| ## User Story | ||
|
|
||
| As a DeepChat user, I want to create a scheduled task with a trigger time | ||
| (once at a specific datetime, daily, or weekly on a chosen day) and an | ||
| action (raise a system notification, prefill a new chat thread with a | ||
| preset prompt, or auto-send a preset prompt to a chosen agent/model). I | ||
| want my tasks to persist across app restarts; one-shot tasks that I missed | ||
| because the app was closed should still fire on next launch. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| - A "定时任务" entry exists in Settings → Tools (between Notifications & | ||
| Hooks and Plugins). It lists, creates, edits, toggles, deletes, and | ||
| manually fires user-defined scheduled tasks. | ||
| - Each task has: | ||
| - A name and an enabled toggle. | ||
| - A trigger of one of three kinds: `once` (a specific datetime), | ||
| `daily` (hour + minute), or `weekly` (day-of-week + hour + minute). | ||
| - An action of one of two kinds: `notify` (title + body for the system | ||
| notification) or `prompt` (notification title + chat message + optional | ||
| agent / provider / model / system prompt + `autoSend` toggle). | ||
| - When a task fires: | ||
| - `notify`: a system notification appears via `notificationPresenter`, | ||
| subject to the existing `notificationsEnabled` config. | ||
| - `prompt` with `autoSend = false`: a system notification appears and the | ||
| main window's new-thread page receives the deeplink-start payload, | ||
| prefilling the chat input. | ||
| - `prompt` with `autoSend = true`: `sessionService.createSession` is | ||
| invoked directly using the configured agent/provider/model, so the LLM | ||
| actually responds without user interaction. A notification is raised | ||
| when the session is created. | ||
| - One-shot tasks whose `firesAt` was in the past at launch and that have no | ||
| `lastFiredAt` recorded are fired once on startup (backfill). Recurring | ||
| tasks are not backfilled — they simply jump to the next slot. | ||
| - Task records survive app restart (persisted through `ConfigPresenter`'s | ||
| ElectronStore as the `scheduledTasks` key). | ||
|
|
||
| ## Non-goals | ||
|
|
||
| - Cron-expression input. Daily / weekly / once is sufficient for the | ||
| feature ask; a future iteration may add `cron` and `interval` trigger | ||
| kinds. | ||
| - Per-task timezone handling. Triggers use the OS's local time. | ||
| - Letting the LLM schedule tasks via an MCP tool. Possible follow-up. | ||
| - Calendar / iCal export. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Tasks | ||
|
|
||
| - [x] Add SDD artifacts. | ||
| - [x] Define shared types (`src/shared/scheduledTasks.ts`) and route contracts. | ||
| - [x] Implement `ScheduledTasksService` (presenter + `computeNextFireAt` + action dispatch). | ||
| - [x] Wire `ConfigPresenter` persistence (`scheduledTasks` key) with normalize-on-read. | ||
| - [x] Register routes in `src/main/routes/index.ts` and instantiate in `Presenter` constructor. | ||
| - [x] Hook lifecycle: start on `after-start`, stop on `beforeQuit`. | ||
| - [x] Add renderer client `src/renderer/api/ScheduledTasksClient.ts`. | ||
| - [x] Add settings navigation entry and dynamic route component. | ||
| - [x] Implement `ScheduledTasksSettings.vue` (CRUD, mirror NotificationsHooks layout). | ||
| - [x] Add i18n keys across all locales. | ||
| - [x] Unit tests for `computeNextFireAt` and `normalizeScheduledTasksConfig`. | ||
| - [x] Add service tests for notification firing, one-shot disable, and prompt auto-send dispatch. | ||
| - [x] Run `pnpm run format`, `pnpm run i18n`, `pnpm run lint`, `pnpm run typecheck`. | ||
| - [x] Address PR review comments without changing scheduled-task behavior. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Plan | ||
|
|
||
| ## Approach | ||
|
|
||
| - Keep the fix scoped to `src/renderer/settings/components/ScheduledTasksSettings.vue`. | ||
| - Make the settings page feel less cramped by separating the page header, empty state, task header, trigger panel, and action panel with clearer surfaces and spacing. | ||
| - Simplify visual weight by using softer panels, clearer section headers, and responsive control groups instead of dense nested card chrome. | ||
| - Keep each task card scannable with a compact status/summary row, a prominent editable name, and action buttons that wrap cleanly on smaller widths. | ||
| - Change the prompt action control grid so each column can shrink (`min-w-0`) and stacks earlier when space is tight. | ||
| - Force select triggers/buttons to use `w-full min-w-0` and truncate visible labels. | ||
| - Replace the model ID input with a `Popover` + existing `ModelSelect` picker. | ||
| - Resolve the displayed model name through `useModelStore.enabledModels`, with a fallback to the stored model ID. | ||
| - Close the model popover after selection and persist via the existing task upsert path. | ||
|
|
||
| ## Data Flow | ||
|
|
||
| - Existing task action stores `providerId` and `modelId`. | ||
| - Agent selection may set both fields from `agent.config.defaultModelPreset`. | ||
| - Model picker selection updates `providerId` and `modelId` explicitly. | ||
|
|
||
| ## Validation | ||
|
|
||
| - Run formatting and lint checks required by repository guidelines. | ||
| - Run i18n validation and ensure any new user-facing text is backed by locale keys. | ||
| - Review the changed template for responsive truncation and no new raw strings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Scheduled Task Prompt Picker UX | ||
|
|
||
| ## User Story | ||
|
|
||
| As a user configuring scheduled tasks, I want the task list to feel clean, balanced, and easy to scan, and I want prompt agent/model controls to fit cleanly in the task card with selectable options, so I can configure automation without overlapping fields or manually typing model IDs. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| - Scheduled task settings use a cleaner, more balanced layout with readable hierarchy between page header, task header, trigger settings, and action settings. | ||
| - Task cards avoid overly heavy nested borders and keep controls aligned in a responsive two-panel composition. | ||
| - Agent and model controls in prompt actions do not overlap at common settings window widths. | ||
| - Long agent names or IDs are truncated inside their control instead of expanding the grid column. | ||
| - The model field is a selectable model picker populated from enabled models, not a free-form text input. | ||
| - Selecting an agent still applies its default model preset when available. | ||
| - Selecting a model persists both `providerId` and `modelId` for the scheduled task. | ||
| - Existing notify actions, trigger controls, and prompt text fields keep their current behavior. | ||
|
|
||
| ## Non-Goals | ||
|
|
||
| - No changes to scheduled task execution semantics. | ||
| - No new model filtering rules beyond excluding ACP and using enabled models. | ||
| - No new IPC or persistence schema changes. | ||
|
|
||
| ## Constraints | ||
|
|
||
| - Follow existing Vue 3 Composition API and shadcn/Tailwind patterns. | ||
| - Reuse existing model picker components where possible. | ||
| - Avoid new user-facing strings unless required. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Tasks | ||
|
|
||
| - [x] Locate scheduled task prompt action UI. | ||
| - [x] Specify layout and model picker acceptance criteria. | ||
| - [x] Update prompt action agent/model controls. | ||
| - [x] Refine scheduled task card layout and i18n-backed UI copy. | ||
| - [x] Run required format/i18n/lint checks. | ||
| - [x] Rebalance scheduled task settings layout surfaces and spacing. | ||
| - [x] Re-run i18n validation after layout changes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Implementation Plan | ||
|
|
||
| - Convert scheduled task trigger/action values to plain objects before invoking the scheduled task IPC route. | ||
| - Keep the change local to `ScheduledTasksSettings.vue` so route contracts and main-process logic remain unchanged. | ||
| - Validate with formatting, typecheck, lint, and the focused scheduled tasks test suite. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Scheduled Tasks Clone Error | ||
|
|
||
| ## Problem | ||
|
|
||
| Editing a scheduled task in Settings can fail with `Error: An object could not be cloned.` from `ScheduledTasksSettings.vue` when persisting a task. | ||
|
|
||
| ## Cause | ||
|
|
||
| The settings page stores tasks in Vue reactive state. `persistTask` forwards `task.trigger` and `task.action` directly to the IPC client. Those nested objects can be Vue proxies, which are not structured-cloneable by Electron IPC. | ||
|
|
||
| ## Expected Behavior | ||
|
|
||
| Persisting an edited scheduled task sends a plain serializable payload to the route and succeeds without clone errors. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Tasks | ||
|
|
||
| - [x] Add SDD issue artifacts. | ||
| - [x] Serialize scheduled task edit payloads before IPC. | ||
| - [x] Run focused scheduled tasks test and typecheck. | ||
| - [x] Run i18n and lint. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Implementation Plan | ||
|
|
||
| - Reuse `ChatService` in the route runtime and call `sendMessage` after creating a scheduled task session. | ||
| - Load agents with `ConfigClient.listAgents()` in `ScheduledTasksSettings.vue`. | ||
| - Replace the raw agent ID input with an agent select and persist the selected agent plus its default provider/model preset. | ||
| - Keep manual model override available for users who need it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Scheduled Tasks Real Dispatch | ||
|
|
||
| ## Problem | ||
|
|
||
| Scheduled task prompt actions feel fake: `autoSend` creates a session but does not actually send the prompt to the agent, and the settings UI requires users to type raw agent/model IDs by hand. | ||
|
|
||
| ## Expected Behavior | ||
|
|
||
| - `autoSend` creates a session and sends the configured message through the normal chat pipeline. | ||
| - The settings UI lists real enabled agents so users can select a target instead of guessing IDs. | ||
| - Selecting an agent carries over its default model preset when available. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Tasks | ||
|
|
||
| - [x] Add SDD issue artifacts. | ||
| - [x] Send prompt after scheduled auto-send session creation. | ||
| - [x] Use real enabled agents in scheduled task settings. | ||
| - [x] Run formatting, lint, typecheck, i18n, and focused tests. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.