Files
oikos/migrations/018_tasks.up.sql
dtoro 72e9fe534e feat(tasks): phase 1 — elevate chat session to a task (schema + task entity)
Migration 018 adds goal/status/outcome/summary/entity_id to agent_sessions
and creates session_plan_steps + session_questions. Registers a 'task'
entity type and an 'involves' (task→entity) relationship in the ontology
so each session anchors its knowledge and involved-entity edges on the
existing relationships graph.

nomos createSession now mints a task:<session-id> entity (type task) and
links it via agent_sessions.entity_id — best-effort so chat never blocks on
it. listSessions/GET /sessions surface the new task fields.

No behaviour change yet; this is the data foundation for the task board and
live context panel. Verified end-to-end against the local stack: migration
applied, ontology ingested (60 types/47 rels), a new session mints a linked
task entity and the API returns status/goal/entity_id.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 12:25:28 +02:00

54 lines
2.7 KiB
SQL

-- 018_tasks.up.sql
-- Elevate a chat session into a "task": a goal-structured unit of work with a
-- lifecycle status, an outcome, and a one-line summary — the first-class object
-- the task board and the live context panel render. See
-- plans/2026-07-11-goal-oriented-chat-control-panel.md.
--
-- entity_id links the session to its OWN entity (type 'task', registered in
-- seeds/ontology.yaml) so knowledge notes and involved-entity edges hang off
-- the existing relationships graph unchanged — get_relations and
-- get_entity_knowledge just work. Intentionally no hard FK (mirrors 017's
-- decoupling): a race between task-entity creation and the session insert must
-- not be able to break the session.
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS goal TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'active';
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS outcome TEXT;
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS summary TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS entity_id UUID;
-- Ordered plan steps. A step is a described unit of work that maps to a
-- run/request_execution call (no fixed step enum, per general-gated-execution).
-- execution_id is the gated action a step runs, if any; its terminal status
-- auto-closes the step server-side.
CREATE TABLE IF NOT EXISTS session_plan_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
seq INT NOT NULL,
title TEXT NOT NULL,
detail TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending',
-- pending | running | done | failed | skipped | blocked
execution_id UUID,
target_slug TEXT,
started_at TIMESTAMPTZ,
finished_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_plan_steps_session ON session_plan_steps(session_id, seq);
-- Structured decisions the agent surfaces to the operator mid-task. context
-- carries { entities:[], options:[], why:"" } for the pinned question card.
CREATE TABLE IF NOT EXISTS session_questions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
prompt TEXT NOT NULL,
context JSONB NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'open', -- open | answered | dismissed
answer TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
answered_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_questions_session_open
ON session_questions(session_id) WHERE status = 'open';