This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/tasks.md
2026-03-11 14:45:37 +00:00

291 lines
6.3 KiB
Markdown

# Tasks
Autonomous agent scheduling. A task is a cron-driven or one-shot prompt
execution in a headless service channel — no human participant in the loop.
## Configuration
Global config keys (set via `PUT /admin/settings/:key`):
| Key | Default | Description |
|-----|---------|-------------|
| `tasks.enabled` | `true` | Master kill switch for task scheduler |
| `tasks.allow_personal` | `true` | Allow non-admin users to create tasks |
| `tasks.max_concurrent` | `5` | Max tasks running simultaneously |
| `tasks.personal_require_byok` | `false` | Personal tasks must use BYOK provider |
Default budget ceilings (overridable per task):
| Key | Default |
|-----|---------|
| `tasks.default_max_tokens` | `4096` |
| `tasks.default_max_tool_calls` | `10` |
| `tasks.default_max_wall_clock` | `300` (seconds) |
## Personal Tasks
### List My Tasks
```
GET /tasks
```
Returns tasks owned by the current user.
**Auth:** Authenticated.
### Create Task
```
POST /tasks
```
```json
{
"name": "Morning News Digest",
"description": "Summarize top tech news",
"task_type": "prompt",
"persona_id": "uuid|null",
"model_id": "claude-sonnet-4-20250514",
"system_prompt": "You are a news summarizer.",
"user_prompt": "Summarize the top 5 tech news stories from today.",
"schedule": "@daily",
"timezone": "America/New_York",
"max_tokens": 4096,
"max_tool_calls": 10,
"max_wall_clock": 300,
"output_mode": "channel",
"webhook_url": "https://...",
"provider_config_id": "uuid|null",
"notify_on_complete": false,
"notify_on_failure": true,
"tool_grants": ["web_search", "url_fetch"]
}
```
`task_type`: `prompt` (direct LLM execution) or `workflow` (instantiate
a workflow in the service channel).
`schedule`: cron expression or `once`. Supported patterns: `@hourly`,
`@daily`, `@weekly`, `*/N * * * *` (every N minutes), full 5-field cron
via `robfig/cron/v3`.
`output_mode`: `channel` (default — output stays in service channel),
`note` (creates a note from the output), `webhook` (POST result to URL).
**Auth:** `tasks.create` permission required.
### Get Task
```
GET /tasks/:id
```
**Auth:** Owner or admin.
### Update Task
```
PUT /tasks/:id
```
Partial update. All fields from create are accepted.
**Auth:** `tasks.create` permission, must be owner.
### Delete Task
```
DELETE /tasks/:id
```
**Auth:** `tasks.create` permission, must be owner.
### Run Now (Manual Trigger)
```
POST /tasks/:id/run
```
Immediately executes the task regardless of schedule. Creates a new
task run. Returns 409 if a run is already active.
**Auth:** `tasks.create` permission, must be owner.
### Kill Active Run
```
POST /tasks/:id/kill
```
Cancels the active run. Sets status to `cancelled`.
**Auth:** `tasks.create` permission, must be owner.
### List Runs
```
GET /tasks/:id/runs
```
Returns run history for the task, most recent first.
**Auth:** Owner or admin.
## Team Tasks
Team-scoped tasks visible to all team members, manageable by team admins.
### List Team Tasks (Member)
```
GET /teams/:teamId/tasks
```
Returns tasks scoped to the team. Read-only for members.
**Auth:** Team member.
### List Team Task Runs (Member)
```
GET /teams/:teamId/tasks/:id/runs
```
**Auth:** Team member.
### Create Team Task (Admin)
```
POST /teams/:teamId/tasks
```
Same shape as personal task creation. Team scope is injected automatically.
**Auth:** `tasks.create` permission, team admin.
### Update/Delete/Run/Kill Team Task
```
PUT /teams/:teamId/tasks/:id
DELETE /teams/:teamId/tasks/:id
POST /teams/:teamId/tasks/:id/run
POST /teams/:teamId/tasks/:id/kill
```
**Auth:** `tasks.create` permission, team admin.
## Admin Tasks
Platform-wide task management.
### List All Tasks
```
GET /admin/tasks
```
Returns all tasks across all users and teams.
**Auth:** Platform admin.
### Admin Run/Kill/Delete
```
POST /admin/tasks/:id/run
POST /admin/tasks/:id/kill
DELETE /admin/tasks/:id
```
**Auth:** Platform admin.
## Task Object
```json
{
"id": "uuid",
"owner_id": "uuid",
"team_id": "uuid|null",
"name": "Morning News Digest",
"description": "...",
"scope": "personal|team|global",
"task_type": "prompt|workflow",
"persona_id": "uuid|null",
"model_id": "claude-sonnet-4-20250514",
"system_prompt": "...",
"user_prompt": "...",
"workflow_id": "uuid|null",
"tool_grants": ["web_search", "url_fetch"],
"schedule": "@daily",
"timezone": "America/New_York",
"is_active": true,
"max_tokens": 4096,
"max_tool_calls": 10,
"max_wall_clock": 300,
"output_mode": "channel|note|webhook",
"output_channel_id": "uuid|null",
"webhook_url": "https://...",
"webhook_secret": "...",
"provider_config_id": "uuid|null",
"notify_on_complete": false,
"notify_on_failure": true,
"last_run_at": "...|null",
"next_run_at": "...|null",
"run_count": 42,
"created_at": "...",
"updated_at": "..."
}
```
## Task Run Object
```json
{
"id": "uuid",
"task_id": "uuid",
"channel_id": "uuid|null",
"status": "running|completed|failed|budget_exceeded|cancelled",
"started_at": "...",
"completed_at": "...|null",
"tokens_used": 1234,
"tool_calls": 3,
"wall_clock": 45,
"error": "...|null"
}
```
## Execution
The `TaskScheduler` is a background goroutine polling every 30 seconds.
1. Finds tasks where `next_run_at <= now` and `is_active = true`
2. Skips if an active run exists (`GetActiveRun` returns non-nil)
3. Creates or reuses a `service` channel (`output_channel_id`)
4. Persists the `user_prompt` as a message in the service channel
5. Runs `CoreToolLoop` (headless completion — same as streaming but no SSE)
6. Enforces budgets: `max_tokens`, `max_tool_calls`, `max_wall_clock`
7. On budget breach: status = `budget_exceeded`, owner notified
8. On completion: updates `last_run_at`, calculates `next_run_at`
**Provider resolution:** BYOK → team provider → global provider → routing
policy. If `tasks.personal_require_byok` is true, personal tasks that
don't have a BYOK provider fail at step 5.
## Webhooks
Tasks with `webhook_url` fire a POST on completion:
```json
{
"task_id": "uuid",
"run_id": "uuid",
"status": "completed|failed|budget_exceeded",
"output": "...",
"tokens_used": 1234,
"timestamp": "..."
}
```
Signed with HMAC-SHA256 using `webhook_secret` in the
`X-Switchboard-Signature` header. Retry: 3 attempts, exponential backoff.