Changeset 0.28.0.1 (#173)
This commit is contained in:
290
docs/ICD/tasks.md
Normal file
290
docs/ICD/tasks.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user