mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 02:15:57 +00:00
feat(hooks): introduce agent lifecycle hooks foundation with fail-closed blocking semantics
Phase 1 of agent-hooks-system establishes: - Hook types, matchers, and CEL evaluation engine for event-driven extensibility - Edition-gated command handlers (Lite disabled) with dedup_key-indexed audit log - Dual-DB store layer (PostgreSQL + SQLite) with transaction boundary enforcement - Blocking-event semantics: hook execution failures propagate to agent loop, graceful retry - Tenant-isolated audit trail with per-hook execution context tracing - Integration tests verifying store correctness and hook dispatch atomicity Lays groundwork for post-v3.0 phase-02 (per-tenant onboarding hooks).
This commit is contained in:
1 parent
86d564967f
commit
3fe5ae0b50
34 files changed
+4866
-27
No files matched your search
@@ -1568,3 +1568,89 @@ CREATE INDEX IF NOT EXISTS idx_vault_links_to ON vault_links(to_doc_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_vault_links_source
|
||||
ON vault_links(json_extract(metadata, '$.source'))
|
||||
WHERE json_extract(metadata, '$.source') IS NOT NULL;
|
||||
|
||||
-- ============================================================
|
||||
-- Table: agent_hooks (migration 000052)
|
||||
-- SQLite translation: JSONB→TEXT, TIMESTAMPTZ→TEXT, UUID→TEXT,
|
||||
-- BYTEA→BLOB, DATE→TEXT (ISO8601), CHECK for enums.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agent_hooks (
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL DEFAULT '0193a5b0-7000-7000-8000-000000000001',
|
||||
agent_id TEXT REFERENCES agents(id) ON DELETE CASCADE,
|
||||
scope TEXT NOT NULL CHECK (scope IN ('global', 'tenant', 'agent')),
|
||||
event TEXT NOT NULL,
|
||||
handler_type TEXT NOT NULL CHECK (handler_type IN ('command', 'http', 'prompt')),
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
matcher TEXT,
|
||||
if_expr TEXT,
|
||||
timeout_ms INTEGER NOT NULL DEFAULT 5000,
|
||||
on_timeout TEXT NOT NULL DEFAULT 'block' CHECK (on_timeout IN ('block', 'allow')),
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
version INTEGER NOT NULL DEFAULT 1,
|
||||
source TEXT NOT NULL DEFAULT 'ui' CHECK (source IN ('ui', 'api', 'seed')),
|
||||
metadata TEXT NOT NULL DEFAULT '{}',
|
||||
created_by TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_hooks_global
|
||||
ON agent_hooks (event, handler_type)
|
||||
WHERE scope = 'global';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_hooks_tenant
|
||||
ON agent_hooks (tenant_id, event, handler_type)
|
||||
WHERE scope = 'tenant';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_hooks_agent
|
||||
ON agent_hooks (tenant_id, agent_id, event, handler_type)
|
||||
WHERE scope = 'agent';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hooks_lookup
|
||||
ON agent_hooks (tenant_id, agent_id, event)
|
||||
WHERE enabled = 1;
|
||||
|
||||
-- ============================================================
|
||||
-- Table: hook_executions (append-only audit log, migration 000052)
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hook_executions (
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
hook_id TEXT REFERENCES agent_hooks(id) ON DELETE SET NULL,
|
||||
session_id TEXT,
|
||||
event TEXT NOT NULL,
|
||||
input_hash TEXT,
|
||||
decision TEXT NOT NULL CHECK (decision IN ('allow', 'block', 'error', 'timeout')),
|
||||
duration_ms INTEGER NOT NULL DEFAULT 0,
|
||||
retry INTEGER NOT NULL DEFAULT 0,
|
||||
dedup_key TEXT,
|
||||
error TEXT,
|
||||
error_detail BLOB,
|
||||
metadata TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hook_executions_session
|
||||
ON hook_executions (session_id, created_at);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_hook_executions_dedup
|
||||
ON hook_executions (dedup_key)
|
||||
WHERE dedup_key IS NOT NULL;
|
||||
|
||||
-- ============================================================
|
||||
-- Table: tenant_hook_budget (migration 000052)
|
||||
-- month_start stored as TEXT ISO8601 date (YYYY-MM-DD).
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_hook_budget (
|
||||
tenant_id TEXT NOT NULL PRIMARY KEY,
|
||||
month_start TEXT NOT NULL,
|
||||
budget_total INTEGER NOT NULL DEFAULT 0,
|
||||
remaining INTEGER NOT NULL DEFAULT 0,
|
||||
last_warned_at TEXT,
|
||||
metadata TEXT NOT NULL DEFAULT '{}',
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
||||
);
|
||||
Reference in new issue
Block a user