Skip to content

Tasks ​

A task is a piece of work the agent is in the middle of across several messages — a booking being arranged, a multi-step lookup, something waiting on the user or on an external event. Tasks live in the agent_tasks table (migration 074) and are scoped to a conversation and, where known, a contact and a business, so two customers of the same agent never see each other's open work. They replaced the single per-agent ongoing_task value in agent_state (the legacy row is migrated once, on first use).

Shape ​

ColumnMeaning
goalthe outcome, e.g. Book a table for 4 at Luigi's on Friday and confirm to the user
statuspending, in_progress, waiting_user, waiting_external (open) · done, failed, cancelled (closed)
stepsJSON list of { title, status: pending | in_progress | done | failed | skipped, note? }
next_stepthe next concrete action
contextJSON scratch data collected so far (ids, dates, choices); merged on update
wake_atISO time at which a waiting task is re-activated
superseded_byset when a newer task replaces this one
sourcewho last changed it: agent, loop, auto_close, wake, user, legacy

How the agent uses tasks ​

Three tools, all scoped to the current conversation:

ToolEffect
set_ongoing_task(task, status, nextStep?, steps?, context?, wakeAt?, taskId?)create or update a task; wakeAt only applies to the waiting_* statuses
get_ongoing_task()list the open tasks in this conversation
clear_ongoing_task(outcome?, reason?, taskId?)close the newest open task (or taskId) as done, failed or cancelled

Every turn, the system prompt gets an Open Tasks In This Conversation block listing each open task's status, age, step checklist, next step and wake time. The block is informational: the model is told to prioritise the user's current message and continue a task only when the message relates to it.

Auto-close ​

After each turn, Jev judges every open task in the conversation against the latest exchange — completed? and abandoned? — and closes it at a probability ≥ 0.75 (done or cancelled, source = auto_close). The judgement is logged in the decision log as kind task_close. Where the data-flow policy withholds the partner model, tasks stay open until the agent or the user closes them.

Wake-ups ​

The Durable Object alarm sweep (the same one that runs schedules) flips every task whose wake_at has passed from waiting_* back to in_progress and inserts a system message into its conversation — Task wake-up: "…" is due. Next step: … — so the next turn picks it up. The event is published on the agent.schedule diagnostics channel as task_woken.

Dashboard and API ​

The chat page shows an open-tasks panel per conversation with steps, next step and wake time, and buttons to mark a task done or cancel it.

RoutePurpose
GET /api/agents/{id}/tasks?conversationId=&includeClosed=1list tasks (open first, newest first, max 30)
PATCH /api/agents/{id}/tasks/{taskId} { status, note? }change status from the dashboard (source = user); a closed status closes the task

Relation to memory ​

Tasks are the task memory kind: they are indexed for keyword search but never vectorised, so a finished booking does not resurface semantically weeks later. Durable facts learned while doing a task belong in remember, not in the task's context.

Learning from tasks and conversations ​

When a task closes as done, the traces behind it (every tool call in the conversation since the task started) are queued and the alarm sweep distils them into a learned skill — a procedure with trigger phrases, the exact tools and argument shapes that worked, and the pitfalls. Skills → Learned lists them with versions and success rates; a skill is retired automatically after repeated failures.

A conversation that never had a task can be learned from on demand: POST /api/agents/:id/skills/learned/distill-conversation/:conversationId (the Learn from this conversation button on the chat page). The first user message stands in as the goal.