feat(nomos): session-review improvements (P0/P1/P2 from 2026-07-20 audit)
Classifier now unwraps pct exec / qm guest exec / bash -c / sh -c / sudo
and env-var assignments before classification, so read-only inspection
wrapped in pct exec no longer escalates to config_mutation. curl GET
(default method, no -d/-F/-T/-o/>) is read-only. Eliminates the three
duplicate rclone sessions (a51e2086, 8acea2e3, cb8c8a4a) that bounced
off the classifier for the same goal.
New classify_command MCP tool: command-scoped preflight that returns the
exact risk class run would assign. Documented in SOUL.md with guidance
to pre-classify before run when the verdict is uncertain.
set_goal surfaces prior partial/failed sessions from the last 24h so the
agent picks up the thread instead of rediscovering it.
completeTask auto-closes in-flight plan steps (pending/running -> done
on success, skipped on partial/failure), so one-step plans no longer
need the per-step running->done dance right before completion.
Migration 021 adds blocker + closed_at to agent_sessions. completeTask
sets closed_at once and derives a structured blocker reason
(approval_timeout, user_abandoned, classifier_overreach, model_refusal,
tool_error, ...) from the last assistant message.
/sessions list now carries message_count, tool_call_count,
duration_seconds (server-side aggregates — no more N+1 transcript
fetches to audit a fleet). GET /sessions/{id} returns both metadata
and messages. New query params filter + paginate: outcome, status,
entity_id, blocker, since (RFC3339 or Go duration), cursor, limit.
Titles now prefer the goal when set; sessions without a goal fall back
to the first assistant text.
New GET /sessions/{id}/tool_calls flat view for audit scripts.
Plan: plans/2026-07-20-session-review-ten-sessions.md. VERSION 0.7.12 -> 0.7.13.
This commit is contained in:
35
migrations/021_session_blocker_and_closed_at.up.sql
Normal file
35
migrations/021_session_blocker_and_closed_at.up.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
-- 021_session_blocker_and_closed_at.up.sql
|
||||
-- Track why a session ended partial/failed and when it actually closed.
|
||||
-- See plans/2026-07-20-session-review-ten-sessions.md P1.5.
|
||||
--
|
||||
-- `blocker` is a short structured reason: "approval_timeout",
|
||||
-- "classifier_overreach", "user_abandoned", "tool_error", "model_refusal",
|
||||
-- etc. Set by complete_task when outcome is partial/failed, derived from the
|
||||
-- last assistant message's text. Empty for success outcomes.
|
||||
--
|
||||
-- `closed_at` is when the session reached its terminal state. Distinct from
|
||||
-- `last_active_at`, which is touched on any access (including the operator
|
||||
-- just opening the transcript) — `closed_at` is set ONCE at completion.
|
||||
-- Without it, "session duration" can only be computed as
|
||||
-- `last_active - created`, which lies for reopened sessions (a51e2086
|
||||
-- reported 4-day duration because the operator reopened it to close it).
|
||||
|
||||
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS blocker TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS closed_at TIMESTAMPTZ;
|
||||
|
||||
-- Backfill closed_at for already-terminal sessions so the new column isn't
|
||||
-- NULL forever on existing rows. Use last_active_at as the best proxy — it's
|
||||
-- the most recent touch, which is the closest we have to "when it ended"
|
||||
-- for historical sessions. New sessions set closed_at explicitly on
|
||||
-- complete_task.
|
||||
UPDATE agent_sessions
|
||||
SET closed_at = last_active_at
|
||||
WHERE closed_at IS NULL
|
||||
AND status IN ('done', 'failed');
|
||||
|
||||
-- Index for "show me partial sessions in the last N days" — the common
|
||||
-- audit query. Covers the blocker column too so the planner can answer
|
||||
-- "blocker breakdown over the last week" with an index-only scan.
|
||||
CREATE INDEX IF NOT EXISTS idx_agent_sessions_closed
|
||||
ON agent_sessions (closed_at DESC)
|
||||
WHERE status IN ('done', 'failed');
|
||||
Reference in New Issue
Block a user