# Session Endpoints

Endpoints for reading, updating and deleting sessions and their pending and finished tasks.

| Method | Path | Description |
|---|---|---|
| `GET` | `/v1/sessions` | `{sessions:[{id, self_id, name, state, model, count}]}`, most recently active first. `?filter=` is `all` (default), `active` (a run is live), `permanent` (everything but `temp-`) or `temporary` (`temp-` only) |
| `GET` | `/v1/usage` | **local** — 24 h / 7 d / 28 d total token usage across sessions. Since v1.0.11 each per-model row also carries `elapsed_ms` (summed provider round-trip time) and `output_tps` (output tokens per second, computed only over the rows that recorded an elapsed time). Since v1.1.0 the `input` of `claude` and `claude-code` rows includes cache writes (`write`), which those providers report separately; since v1.0.26 each usage record also stores the IDs of the tool calls the response made (not returned here) |
| `POST` | `/v1/session` | **local** — create a session; `{prefix}` defaults to `cli-` |
| `GET` `POST` `DELETE` | `/v1/session/:id` | **local** — one session's full state in one call: `id`, `self_id`, `name`, `role`, `state`, `model`, `reasoning`, `levels`, `count`. `role` (the persona body) replaced `rule` in v1.1.0; `rule` is still returned with the same value and still accepted on `POST` for older clients. `levels` starts with `auto` since v1.1.0 — the model selector then picks the reasoning level per request from the kind of work — and `auto_reasoning` was removed with the global toggle. `POST` is a partial update — `self_id` / `name` / `role` / `model` / `reasoning` are all optional and a field left out (or `null`) is untouched; `model: ""` resets to `auto`, `reasoning` must be one of `levels`. A duplicate `self_id` returns 409. `DELETE` removes the session directory, history, state, and vectors. `GET` also takes `?chat=1` to append the action log under `chat` and `?usage=1` to append per-model token usage under `usage`; both are off by default because the log can be large. Since v1.0.12 the `chat` payload is trimmed: for a task that already reached `done` / `canceled` / `error`, its `tool_*` and `thinking` lines and every assistant line but the last are dropped, so a finished task contributes its outcome rather than its whole trace. Since v1.3.0 the last assistant line is kept per turn (a turn starts at each `agent_result` line) rather than per task, so a task resumed by follow-ups or background reports keeps one reply per turn; since v1.3.1 an `agent_result` line also ends in ` reasoning=<level>` |
| `POST` | `/v1/session/:id/memory` | **local** — one memory operation, picked by `action`: `summary` rebuilds the rolling summary and returns `count`; `compact` drops older messages and returns `removed`; `reset` clears the conversation and returns `removed`, and requires `mode` — `summary` keeps the rolling summary, `all` wipes it too |
| `POST` | `/v1/session/:id/followup` | **local** — added in v1.1.2. Generates follow-up suggestions from the last 4 history messages (each clipped to 512 characters) and returns `{title, suggests}`: up to 3 suggestions of at most 32 characters, and a `title` of at most 32 characters only while the session still needs one (it is also saved as the session name). An empty session returns `{"title":"","suggests":[]}`; the call is capped at 30 s. Before v1.1.2 the suggestions arrived as an `EventSuggest` event at the end of the `/v1/send` stream, which no longer emits it — the dashboard now calls this endpoint after a run finishes |
| `POST` | `/v1/session/:id/cancel/:task_hash` | Cancel one running task. Returns `{ok, cancelled:true}` when that task hash is running in this process; otherwise (or for `current`) it records a canceled event on the session stream and returns `{ok, cancelled:false, stale:true}`. Since v1.2.0 the task hash is created and registered when the run starts, so a cancel lands from the run's first event; TUI runs execute in the daemon too and can be canceled here. Since v1.3.0 the call first stops the task's background jobs and discards its pending entry, whether or not the task is running; since v1.3.9 the discarded task is kept in chat history with a `[Canceled]` reply |
| `POST` | `/v1/session/:id/confirm/:confirm_hash` | Resolve an outstanding tool confirmation: `{approve, remember?, allow_turn?, abort?, cancel?, reason?, password?}`; since v1.3.3 `abort` stops the task and keeps its pending entry for resume, while `cancel` stops it and deletes the entry (since v1.3.9 after recording it in chat history as `[Canceled]`). 410 when the confirmation was already resolved or expired. Approving a confirmation that lists `restricted` entries — a restricted path, a `sudo` command (`run_command` / `background_command` argv `['sudo', ...]`) or a `sandbox: false` command — must come from loopback (403 otherwise) and passes the OS password check with `password` (401 on failure; the Linux `pkg_manage` case was Removed in v1.3.2 along with the tool); the check is skipped while the sudo ticket is still cached, which the confirm event reports as `password_cached` |

`GET` / `POST` / `DELETE /v1/session/:id`, `memory` and `followup` return 404 when the session directory does not exist.

`POST /v1/session/:id/event` was removed; the TUI now exchanges events with the daemon over its Unix socket (`~/.config/agenvoy/daemon.sock`). Removed in v1.2.0.

## Pending and completed tasks

| Method | Path | Description |
|---|---|---|
| `GET` | `/v1/session/:id/task` | List resumable pending (`ask_user` / confirm) tasks as `{pending:[{task_hash, objective, has_questions}]}`; the `background` count (v1.3.0) was Removed in v1.3.8, since a task no longer stays pending for background work. `?live=1` lists the pending tasks whose run is live instead. Tasks whose run is still live are excluded — a run refreshes `action:<session_id>:<task_hash>` in ToriiDB every 55 s with a 60 s TTL (v0.35.3), so a task left behind by a closed window or a killed process reappears here within a minute |
| `GET` | `/v1/session/:id/task/:task_hash/questions` | `{questions:[{question, detail?, options?, multi_select?, secret?}]}` of one pending task; 410 when the task was already resolved elsewhere |
| `POST` | `/v1/session/:id/task/:task_hash/resume` | `{answers?}`. Answers a pending task and resumes it, waiting up to 60 min for the run: `{session_id, text}`, or `{session_id, canceled:true}`; 410 when the task was already resolved elsewhere. Since v1.3.0 a resume without answers claims the task first and returns 409 `[Conflict] pending task: running` when a run already holds it |
| `DELETE` | `/v1/session/:id/task/:task_hash` | Discard a pending task without answering; 404 when there is no such pending task |
| `GET` | `/v1/session/:id/task/history` | **local** — completed tasks of this session, newest first: `{task_hash, end_at, objective, model, reasoning}` per row. `?keyword=` filters on the objective and the recorded action text |
| `GET` | `/v1/session/:id/task/:task_hash/history` | **local** — the full action record of one completed task, returned as a JSON string under `content`. 404 when that hash has no record |
