feat(planning): plans, validation, planner and a restart-safe executor
Plans turn intentions into revisable dependency graphs (migration 0027): objective, assumptions, ordered or dependent steps, capabilities, expected observations, preconditions, risk, estimates, budget, completion criteria, abort conditions and the alternatives considered. - Validation owns structure: acyclic dependencies, registered and unlocked capabilities only, schema-valid parameters, targets that agree with parameters, read-only checks, a closed set of step kinds and internal actions. Model proposals are parsed into the same structure; fields that could carry authority or claim progress are reported as ignored, and an invalid draft is stored as a draft that never runs. - The planner prefers deterministic strategies: a direct action verified by observation, a read-only diagnosis that requests temporary scoped log access with risk and fallback stated, and an escalation that diagnoses and informs the operator instead of repeating a failed action. Failed strategies are not reused; a model is consulted only when none applies. - The executor holds no state in memory: it claims a step with a conditional update, acts only through Invoke and RequestCapability, and records the outcome. Waiting for approval or access forms a subordinate intention and blocks the parent with the reason. Expectations become verification predictions resolved from a read-only observation, so an HTTP-level success is never taken as the outcome; a miss is a prediction error that weakens the supporting belief and triggers reconsideration. Replanning creates a new revision, withdraws open requests of the old one and keeps it as history, within a replan limit. Checks never raise approval prompts. Budgets stop runaway plans. Preconditions skip actions when the world already changed. Dream plans and disabled sandbox minds never act. An interrupted non-idempotent action with no record is blocked for verification instead of repeated; recorded outcomes are adopted. Completed plans are stored as procedural memories; a completed escalation does not count as fulfilling the intention. - Executions and approvals record their origin; minds may withdraw their own pending approval requests; Preview reports a decision without side effects; service.status is allowed by default as a bounded read.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
-- Plans and plan steps (PLAN §8.2 items 7–8, docs/planning.md). A plan is a
|
||||
-- revisable DAG serving one intention; replans are new revisions that keep
|
||||
-- the old plan as history.
|
||||
|
||||
CREATE TABLE plans (
|
||||
id uuid PRIMARY KEY,
|
||||
mind_id uuid NOT NULL REFERENCES minds(id),
|
||||
intention_id uuid NOT NULL REFERENCES intentions(id),
|
||||
revision integer NOT NULL DEFAULT 1,
|
||||
supersedes uuid REFERENCES plans(id),
|
||||
superseded_by uuid,
|
||||
objective text NOT NULL,
|
||||
origin text NOT NULL CHECK (origin IN ('template','model','operator','dream','replan')),
|
||||
strategy text NOT NULL DEFAULT '',
|
||||
status text NOT NULL DEFAULT 'draft' CHECK (status IN ('draft','validated','waiting','executing','blocked','awaiting_approval','replanning','completed','failed','abandoned','superseded')),
|
||||
assumptions jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
completion_criteria text NOT NULL DEFAULT '',
|
||||
abort_conditions jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
alternatives jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
risk text NOT NULL DEFAULT '',
|
||||
estimate jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
actual jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
budget jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
validation jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
require_approval boolean NOT NULL DEFAULT false,
|
||||
max_replans integer NOT NULL DEFAULT 3,
|
||||
llm_call uuid,
|
||||
status_reason text NOT NULL DEFAULT '',
|
||||
closed_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX plans_mind_idx ON plans (mind_id, status, created_at DESC);
|
||||
CREATE INDEX plans_intention_idx ON plans (intention_id, revision);
|
||||
|
||||
CREATE TABLE plan_steps (
|
||||
id uuid PRIMARY KEY,
|
||||
plan_id uuid NOT NULL REFERENCES plans(id),
|
||||
mind_id uuid NOT NULL REFERENCES minds(id),
|
||||
key text NOT NULL,
|
||||
position integer NOT NULL,
|
||||
title text NOT NULL,
|
||||
kind text NOT NULL CHECK (kind IN ('capability','request_capability','verify','wait','monitor','internal')),
|
||||
depends_on text[] NOT NULL DEFAULT '{}',
|
||||
capability text NOT NULL DEFAULT '',
|
||||
target text NOT NULL DEFAULT '',
|
||||
params jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
require_approval boolean NOT NULL DEFAULT false,
|
||||
expectation jsonb,
|
||||
precondition jsonb,
|
||||
spec jsonb NOT NULL DEFAULT '{}'::jsonb, -- kind-specific: request, check, wait, monitor, internal action
|
||||
status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','ready','executing','awaiting_approval','awaiting_grant','waiting','completed','failed','skipped','blocked','cancelled')),
|
||||
attempts integer NOT NULL DEFAULT 0,
|
||||
max_attempts integer NOT NULL DEFAULT 1,
|
||||
lease_until timestamptz,
|
||||
next_run_at timestamptz,
|
||||
approval_id uuid,
|
||||
request_id uuid,
|
||||
execution_id uuid,
|
||||
prediction_id uuid,
|
||||
intention_id uuid, -- subordinate intention this step formed
|
||||
result jsonb,
|
||||
observation jsonb,
|
||||
error text NOT NULL DEFAULT '',
|
||||
status_reason text NOT NULL DEFAULT '',
|
||||
started_at timestamptz,
|
||||
finished_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (plan_id, key)
|
||||
);
|
||||
CREATE INDEX plan_steps_due_idx ON plan_steps (status, next_run_at) WHERE status IN ('ready','executing','awaiting_approval','awaiting_grant','waiting');
|
||||
CREATE INDEX plan_steps_plan_idx ON plan_steps (plan_id, position);
|
||||
|
||||
-- Provenance for recovery: which cognitive object asked for an execution
|
||||
-- or approval, so an interrupted step can find what already happened.
|
||||
ALTER TABLE tool_executions ADD COLUMN origin text NOT NULL DEFAULT '';
|
||||
ALTER TABLE approval_requests ADD COLUMN origin text NOT NULL DEFAULT '';
|
||||
CREATE INDEX tool_executions_origin_idx ON tool_executions (origin) WHERE origin <> '';
|
||||
CREATE INDEX approval_requests_origin_idx ON approval_requests (origin) WHERE origin <> '';
|
||||
|
||||
-- A mind may withdraw an approval request it no longer needs.
|
||||
ALTER TABLE approval_requests DROP CONSTRAINT approval_requests_status_check;
|
||||
ALTER TABLE approval_requests ADD CONSTRAINT approval_requests_status_check CHECK (status IN ('pending','approved','denied','expired','executed','failed','withdrawn'));
|
||||
Reference in New Issue
Block a user