Implement task-scoped sessions, queued run chaining, and session reset API
Heartbeat service now resolves session state per-task using agentTaskSessions, with resolveNextSessionState handling codec-based serialization and fallback to legacy sessionId. Queued runs are chained — when a run finishes or is reaped, the next queued run for the same agent starts automatically. Queued runs for an agent with an already-running run wait instead of failing. Add task-sessions list endpoint and extend reset-session to accept optional taskKey for targeted session clearing. Block pending_approval agents from API key auth. Update agent/company delete cascades to include task sessions. Update spec docs with task-session architecture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -423,7 +423,7 @@ This separation keeps adapter config runtime-agnostic while allowing the heartbe
|
||||
|
||||
## 9.1 New table: `agent_runtime_state`
|
||||
|
||||
One row per agent for resumable adapter state.
|
||||
One row per agent for aggregate runtime counters and legacy compatibility.
|
||||
|
||||
- `agent_id` uuid pk fk `agents.id`
|
||||
- `company_id` uuid fk not null
|
||||
@@ -441,6 +441,24 @@ One row per agent for resumable adapter state.
|
||||
|
||||
Invariant: exactly one runtime state row per agent.
|
||||
|
||||
## 9.1.1 New table: `agent_task_sessions`
|
||||
|
||||
One row per `(company_id, agent_id, adapter_type, task_key)` for resumable session state.
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `agent_id` uuid fk not null
|
||||
- `adapter_type` text not null
|
||||
- `task_key` text not null
|
||||
- `session_params_json` jsonb null (adapter-defined shape)
|
||||
- `session_display_id` text null (for UI/debug)
|
||||
- `last_run_id` uuid fk `heartbeat_runs.id` null
|
||||
- `last_error` text null
|
||||
- `created_at` timestamptz not null
|
||||
- `updated_at` timestamptz not null
|
||||
|
||||
Invariant: unique `(company_id, agent_id, adapter_type, task_key)`.
|
||||
|
||||
## 9.2 New table: `agent_wakeup_requests`
|
||||
|
||||
Queue + audit for wakeups.
|
||||
@@ -662,13 +680,15 @@ On server startup:
|
||||
- backward-compatible alias to wakeup API
|
||||
3. `GET /agents/:agentId/runtime-state`
|
||||
- board-only debug view
|
||||
4. `POST /agents/:agentId/runtime-state/reset-session`
|
||||
- clears stored session ID
|
||||
5. `GET /heartbeat-runs/:runId/events?afterSeq=:n`
|
||||
4. `GET /agents/:agentId/task-sessions`
|
||||
- board-only list of task-scoped adapter sessions
|
||||
5. `POST /agents/:agentId/runtime-state/reset-session`
|
||||
- clears all task sessions for the agent, or one when `taskKey` is provided
|
||||
6. `GET /heartbeat-runs/:runId/events?afterSeq=:n`
|
||||
- fetch persisted lightweight timeline
|
||||
6. `GET /heartbeat-runs/:runId/log`
|
||||
7. `GET /heartbeat-runs/:runId/log`
|
||||
- reads full log stream via `RunLogStore` (or redirects/presigned URL for object store)
|
||||
7. `GET /api/companies/:companyId/events/ws`
|
||||
8. `GET /api/companies/:companyId/events/ws`
|
||||
- websocket stream
|
||||
|
||||
## 13.2 Mutation logging
|
||||
@@ -726,7 +746,7 @@ All wakeup/run state mutations must create `activity_log` entries:
|
||||
## 15. Acceptance Criteria
|
||||
|
||||
1. Agent with `claude-local` or `codex-local` can run, exit, and persist run result.
|
||||
2. Session ID is persisted and used for next run resume automatically.
|
||||
2. Session parameters are persisted per task scope and reused automatically for same-task resumes.
|
||||
3. Token usage is persisted per run and accumulated per agent runtime state.
|
||||
4. Timer, assignment, on-demand, and automation wakeups all enqueue through one coordinator.
|
||||
5. Pause/terminate interrupts running local process and prevents new wakeups.
|
||||
@@ -737,7 +757,6 @@ All wakeup/run state mutations must create `activity_log` entries:
|
||||
## 16. Open Questions
|
||||
|
||||
1. Should timer default be `null` (off until enabled) or `300` seconds by default?
|
||||
2. For invalid resume session errors, should default behavior be fail-fast or auto-reset-and-retry-once?
|
||||
3. What should the default retention policy be for full log objects vs Postgres metadata?
|
||||
4. Should agent API credentials be allowed in prompt templates by default, or require explicit opt-in toggle?
|
||||
5. Should websocket be the only realtime channel, or should we also expose SSE for simpler clients?
|
||||
2. What should the default retention policy be for full log objects vs Postgres metadata?
|
||||
3. Should agent API credentials be allowed in prompt templates by default, or require explicit opt-in toggle?
|
||||
4. Should websocket be the only realtime channel, or should we also expose SSE for simpler clients?
|
||||
|
||||
@@ -71,11 +71,13 @@ Templates support variables like `{{agent.id}}`, `{{agent.name}}`, and run conte
|
||||
|
||||
## 4. Session resume behavior
|
||||
|
||||
Paperclip stores session IDs for resumable adapters.
|
||||
Paperclip stores resumable session state per `(agent, taskKey, adapterType)`.
|
||||
`taskKey` is derived from wakeup context (`taskKey`, `taskId`, or `issueId`).
|
||||
|
||||
- Next heartbeat reuses the saved session automatically.
|
||||
- This gives continuity across heartbeats.
|
||||
- You can reset a session if context gets stale or confused.
|
||||
- A heartbeat for the same task key reuses the previous session for that task.
|
||||
- Different task keys for the same agent keep separate session state.
|
||||
- If restore fails, adapters should retry once with a fresh session and continue.
|
||||
- You can reset all sessions for an agent or reset one task session by task key.
|
||||
|
||||
Use session reset when:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user