feat(scheduler): Add Slack scheduled tasks#368
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
8dfdc8b to
9dade87
Compare
Add a state-adapter backed scheduler for Slack-authored Junior tasks. Use active-context Slack tools, calendar recurrence, and an authenticated cron tick endpoint. Wrap scheduled runs in marker-delimited task prompts and deliver results back through Slack. Add integration and eval coverage for task management, recurrence, tick dispatch, and delivery. Refs #114 Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Require scheduled task edits and deletes to come from the creator so a thread member cannot change work that later runs with another user's credentials. Keep scheduler tick auth scoped to scheduler secrets and prune deleted tasks from scheduler scan indexes. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Use the inbound Slack workspace context when a message raw payload lacks team_id so schedule tools still receive the destination workspace. Prefer the workspace team over user_team for Slack Connect author payloads, and keep the shared context outside ingress-only modules. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep existing recurrence metadata when a schedule update only changes task content. This prevents unrelated edits from shifting bi-weekly or monthly anchors to the current next run. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Claim an active-run slot per scheduled task before creating a run so schedule edits cannot start a second due instant while the previous run is still active. Clear the slot only when that same run reaches a terminal state. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Return blocked instead of failed when scheduled Slack execution pauses for MCP or plugin authorization. This keeps recurring tasks from advancing past credential requirements. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Add a public scheduler plugin page that explains built-in registration, cron route setup, required environment variables, and Slack verification. Link the page from the plugin overview, sidebar, and legacy plugin redirect list. Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Add a private testing package for eval HTTP interception and route sandbox egress through a single interceptor hook after credential headers are applied. Remove eval-only sandbox command stubs and the test credential broker so evals use production credential wiring with test data seeded at the harness boundary. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Route scheduled task execution through the trusted plugin heartbeat path only. This removes the duplicate tick endpoint, runner, and executor while keeping stale recurring-task and duplicate-task recovery coverage on heartbeat. Keep test HTTP interception scoped to the private testing HTTP entrypoint and remove the unused app-level interceptor option from public docs. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep private dispatch helpers local and document the remaining exported dispatch contracts. Report scheduler heartbeat dispatch counts only for newly dispatched work while preserving the bounded processing limit for reconciled runs. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Use timing-safe comparison for heartbeat bearer secrets and avoid exposing eval egress exception text over HTTP. Keep invalid plugin dispatch requests from consuming heartbeat fanout, prune terminal dispatches from the recovery index, and release conversation locks when dispatch claiming races. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep scheduled task containment inside the scheduler plugin by relying on requester context instead of a core scheduler suppression flag. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep scheduler evals focused on user-visible Slack behavior and drop the unused schedule-tool override from the harness. Co-Authored-By: GPT-5 Codex <codex@openai.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7cdb18e. Configure here.
Store the incomplete dispatch index as one state value so heartbeat reads never observe a delete-and-reappend gap. Fail lock contention instead of silently dropping recovery index updates. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Clear mutable GitHub fixture state during eval setup so issue data cannot leak between scenarios in the same worker. Co-Authored-By: GPT-5 Codex <codex@openai.com>
Render trusted plugin heartbeat logs with labeled plugin and dispatch count fields so scheduler activity is understandable in local dev output. Co-Authored-By: GPT-5 Codex <codex@openai.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.

Add Slack-authored scheduled Junior tasks backed by the existing state adapter and the trusted plugin boundary.
Users can create and manage scheduled tasks from the active Slack DM or channel. Simple one-off reminders can be scheduled immediately from an explicit reminder request, while recurring schedules and broader scheduled work remain confirm-first with a normalized task contract.
Scheduler Runtime
Scheduled tasks store durable task contracts with exact next-run instants, timezone-aware recurrence, destination scoping, creator audit metadata, and a Junior system execution actor. Scheduled runs do not borrow the creator's OAuth tokens or start interactive auth flows; missing non-user credentials block the run instead.
The scheduler claims due work idempotently, prevents overlapping runs for the same task, supports run-now without rewriting the stored calendar schedule, and recovers abandoned pending dispatches. Old missed occurrences are skipped instead of dispatched late, recurring schedules advance to the next future run, and equivalent stale duplicate tasks in the same destination are paused behind the older canonical task.
Plugin API
This adds the trusted plugin surfaces needed by the scheduler:
hooks.tools(ctx)lets trusted plugins expose tool definitions through the host registration boundary.hooks.heartbeat(ctx)lets trusted plugins run bounded periodic work from/api/internal/heartbeat.ctx.stategives plugins namespaced durable state.ctx.loggives plugins a plugin-scoped structured logger on trusted hook contexts.ctx.agent.dispatch(...)creates signed, durable background agent dispatches for Slack destinations.ctx.agent.get(...)returns plugin-scoped dispatch projections for reconciliation.The public plugin API also now includes the related tool, dispatch, heartbeat, state, logger, and context types. Plugins still do not receive raw routes, Slack clients, Vercel primitives, Redis handles,
waitUntil, orgenerateAssistantReply; core owns validation, signing, callback execution, dispatch locking, and recovery.Local Development And Isolation
Root
pnpm devnow runs the example app throughscripts/dev-server.mjs, registers the scheduler plugin path, and starts a local heartbeat loop with dev-only internal defaults when secrets are unset. Tests and evals get a defaultJUNIOR_STATE_KEY_PREFIX, and deployments can set the same variable to namespace shared Redis state.Validated with targeted scheduler, heartbeat, Slack schedule-tool, state-prefix, eval harness, and scheduler eval coverage, plus typecheck, docs check, architecture boundary checks, Slack boundary checks, and the dev-server syntax check.
Refs #114