mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-17 16:12:21 -06:00
cd0a1235a3
* feat(gateway): add identity preferences and project recents * feat(ui): sync new-session identity state * docs: explain identity-scoped session state * test: track preference temp directories * fix(gateway): preserve identity preference boundaries * chore(protocol): refresh identity preference bindings * test: refresh historical schema hashes * style(gateway): format method order assertion * fix(protocol): emit project recent Swift models * test(gateway): track preference RPC release train * fix(gateway): harden identity preference state * fix(state): keep preference errors internal * chore: refresh split plugin SDK baseline * fix(gateway): use core session store loader * refactor(state): fold additive migration checks * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * test(ui): relocate identity recents e2e * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline * chore: regenerate plugin SDK baseline
632 lines
22 KiB
SQL
632 lines
22 KiB
SQL
-- Session storage doctrine: session_nodes.entry_json is the canonical logical-session
|
|
-- record. Promoted session_nodes columns are query indexes projected only by the
|
|
-- session entry writer; session_windows and their children own transcript generations.
|
|
|
|
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
meta_key TEXT NOT NULL PRIMARY KEY,
|
|
role TEXT NOT NULL,
|
|
schema_version INTEGER NOT NULL,
|
|
agent_id TEXT,
|
|
app_version TEXT,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS session_nodes (
|
|
session_key TEXT NOT NULL PRIMARY KEY,
|
|
current_session_id TEXT NOT NULL,
|
|
entry_json TEXT NOT NULL,
|
|
entry_valid INTEGER NOT NULL DEFAULT 0 CHECK (entry_valid IN (-1, 0, 1)),
|
|
updated_at INTEGER NOT NULL,
|
|
status TEXT CHECK (status IS NULL OR status IN ('running', 'done', 'failed', 'killed', 'timeout')),
|
|
created_at INTEGER,
|
|
created_via TEXT CHECK (created_via IS NULL OR created_via IN ('operator', 'spawn', 'channel', 'cron', 'talk', 'run', 'plugin', 'internal')),
|
|
created_actor_type TEXT CHECK (created_actor_type IS NULL OR created_actor_type IN ('human', 'agent', 'system')),
|
|
created_actor_id TEXT,
|
|
project_id TEXT,
|
|
parent_session_key TEXT,
|
|
spawned_by TEXT,
|
|
fork_source_session_key TEXT,
|
|
fork_source_session_id TEXT,
|
|
fork_source_entry_id TEXT,
|
|
label TEXT,
|
|
display_name TEXT,
|
|
category TEXT,
|
|
icon TEXT,
|
|
pinned_at INTEGER,
|
|
archived_at INTEGER,
|
|
last_read_at INTEGER,
|
|
last_interaction_at INTEGER,
|
|
last_activity_at INTEGER
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_updated_at
|
|
ON session_nodes(updated_at DESC, session_key);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_last_interaction_at
|
|
ON session_nodes(last_interaction_at DESC, session_key);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_parent_session_key
|
|
ON session_nodes(parent_session_key, session_key);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_spawned_by
|
|
ON session_nodes(spawned_by, session_key);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_status
|
|
ON session_nodes(status, session_key)
|
|
WHERE status IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_archived_at
|
|
ON session_nodes(archived_at, session_key)
|
|
WHERE archived_at IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_current_session_id
|
|
ON session_nodes(current_session_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_nodes_entry_valid_pending
|
|
ON session_nodes(session_key)
|
|
WHERE entry_valid = 0;
|
|
|
|
CREATE TABLE IF NOT EXISTS session_key_contract (
|
|
id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1),
|
|
main_key TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
INSERT OR IGNORE INTO session_key_contract (id, main_key, updated_at) VALUES (1, 'main', 0);
|
|
|
|
CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_insert
|
|
AFTER INSERT ON session_nodes
|
|
BEGIN
|
|
UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_entry_update
|
|
AFTER UPDATE OF entry_json ON session_nodes
|
|
BEGIN
|
|
UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS session_nodes_entry_valid_after_identity_update
|
|
AFTER UPDATE OF current_session_id, updated_at ON session_nodes
|
|
BEGIN
|
|
UPDATE session_nodes SET entry_valid = 0 WHERE session_key = NEW.session_key;
|
|
END;
|
|
|
|
CREATE TABLE IF NOT EXISTS session_windows (
|
|
session_id TEXT NOT NULL PRIMARY KEY,
|
|
session_key TEXT NOT NULL,
|
|
previous_session_id TEXT,
|
|
reason TEXT CHECK (reason IS NULL OR reason IN ('initial', 'reset', 'rollover', 'fork', 'rewind', 'switch', 'recovery', 'compaction')),
|
|
session_scope TEXT NOT NULL DEFAULT 'conversation' CHECK (session_scope IN ('conversation', 'shared-main', 'group', 'channel')),
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
transcript_updated_at INTEGER DEFAULT NULL,
|
|
transcript_observed_at INTEGER DEFAULT NULL,
|
|
session_entry_provenance INTEGER NOT NULL DEFAULT 0 CHECK (session_entry_provenance IN (0, 1)),
|
|
acp_owned INTEGER NOT NULL DEFAULT 0 CHECK (acp_owned IN (0, 1)),
|
|
plugin_owner_id TEXT,
|
|
hook_external_content_source TEXT CHECK (hook_external_content_source IS NULL OR hook_external_content_source IN ('gmail', 'webhook')),
|
|
started_at INTEGER,
|
|
ended_at INTEGER,
|
|
status TEXT CHECK (status IS NULL OR status IN ('running', 'done', 'failed', 'killed', 'timeout')),
|
|
chat_type TEXT CHECK (chat_type IS NULL OR chat_type IN ('direct', 'group', 'channel')),
|
|
channel TEXT,
|
|
account_id TEXT,
|
|
primary_conversation_id TEXT,
|
|
model_provider TEXT,
|
|
model TEXT,
|
|
agent_harness_id TEXT,
|
|
parent_session_key TEXT,
|
|
spawned_by TEXT,
|
|
display_name TEXT,
|
|
FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE,
|
|
FOREIGN KEY (primary_conversation_id) REFERENCES conversations(conversation_id) ON DELETE SET NULL
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_windows_updated_at
|
|
ON session_windows(updated_at DESC, session_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_windows_created_at
|
|
ON session_windows(created_at DESC, session_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_windows_conversation
|
|
ON session_windows(primary_conversation_id, updated_at DESC, session_id)
|
|
WHERE primary_conversation_id IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
conversation_id TEXT NOT NULL PRIMARY KEY,
|
|
channel TEXT NOT NULL,
|
|
account_id TEXT NOT NULL,
|
|
kind TEXT NOT NULL CHECK (kind IN ('direct', 'group', 'channel')),
|
|
peer_id TEXT NOT NULL,
|
|
delivery_target TEXT NOT NULL,
|
|
parent_conversation_id TEXT,
|
|
thread_id TEXT,
|
|
native_channel_id TEXT,
|
|
native_direct_user_id TEXT,
|
|
label TEXT,
|
|
metadata_json TEXT,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_conversations_lookup
|
|
ON conversations(channel, account_id, kind, peer_id, thread_id);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_conversations_identity
|
|
ON conversations(
|
|
channel,
|
|
account_id,
|
|
kind,
|
|
peer_id,
|
|
IFNULL(parent_conversation_id, ''),
|
|
IFNULL(thread_id, '')
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_conversations_updated
|
|
ON conversations(updated_at DESC, conversation_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS conversation_deliveries (
|
|
operation_id TEXT NOT NULL PRIMARY KEY,
|
|
operation_kind TEXT NOT NULL CHECK (operation_kind IN ('send', 'turn')),
|
|
conversation_id TEXT NOT NULL,
|
|
source_session_key TEXT,
|
|
message_hash TEXT NOT NULL,
|
|
status TEXT NOT NULL CHECK (status IN ('created', 'queued', 'sent', 'suppressed', 'rejected', 'unknown', 'replied')),
|
|
prepared_message_id TEXT,
|
|
platform_message_id TEXT,
|
|
queue_id TEXT,
|
|
rejection_error TEXT,
|
|
reply_message_id TEXT,
|
|
reply_to_id TEXT,
|
|
reply_thread_id TEXT,
|
|
reply_text TEXT,
|
|
reply_timestamp INTEGER,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
CHECK (
|
|
(status = 'rejected' AND rejection_error IS NOT NULL) OR
|
|
(status != 'rejected' AND rejection_error IS NULL)
|
|
),
|
|
FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_conversation_deliveries_reply
|
|
ON conversation_deliveries(conversation_id, platform_message_id, prepared_message_id)
|
|
WHERE status IN ('queued', 'sent', 'replied');
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_conversation_deliveries_updated
|
|
ON conversation_deliveries(updated_at DESC, operation_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS session_conversations (
|
|
session_id TEXT NOT NULL,
|
|
conversation_id TEXT NOT NULL,
|
|
role TEXT NOT NULL DEFAULT 'primary' CHECK (role IN ('primary', 'participant', 'related')),
|
|
first_seen_at INTEGER NOT NULL,
|
|
last_seen_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_id, conversation_id, role),
|
|
FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE,
|
|
FOREIGN KEY (conversation_id) REFERENCES conversations(conversation_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_conversations_conversation
|
|
ON session_conversations(conversation_id, last_seen_at DESC, session_id);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_session_conversations_primary
|
|
ON session_conversations(session_id)
|
|
WHERE role = 'primary';
|
|
|
|
CREATE TABLE IF NOT EXISTS session_members (
|
|
session_key TEXT NOT NULL,
|
|
identity_id TEXT NOT NULL,
|
|
added_by TEXT NOT NULL,
|
|
added_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_key, identity_id),
|
|
FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_members_identity
|
|
ON session_members(identity_id, session_key);
|
|
|
|
CREATE TABLE IF NOT EXISTS session_suggestions (
|
|
id TEXT PRIMARY KEY,
|
|
session_key TEXT NOT NULL,
|
|
author_id TEXT NOT NULL,
|
|
author_label TEXT,
|
|
text TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
state TEXT NOT NULL CHECK (state IN ('pending', 'accepted', 'dismissed')),
|
|
dispatch_token TEXT,
|
|
dispatch_started_at INTEGER,
|
|
dispatch_resolution TEXT CHECK (dispatch_resolution IN ('send', 'queue', 'edit', 'dismiss')),
|
|
CHECK (
|
|
(dispatch_token IS NULL AND dispatch_started_at IS NULL AND dispatch_resolution IS NULL)
|
|
OR (dispatch_token IS NOT NULL AND dispatch_started_at IS NOT NULL AND dispatch_resolution IS NOT NULL)
|
|
),
|
|
FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_suggestions_session_state_created
|
|
ON session_suggestions(session_key, state, created_at, id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_session_suggestions_author_created
|
|
ON session_suggestions(author_id, created_at, id);
|
|
|
|
CREATE TABLE IF NOT EXISTS board_tabs (
|
|
session_key TEXT NOT NULL,
|
|
tab_id TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
position INTEGER NOT NULL CHECK (position >= 0),
|
|
chat_dock TEXT NOT NULL DEFAULT 'right' CHECK (chat_dock IN ('left', 'right', 'bottom', 'hidden')),
|
|
created_by TEXT NOT NULL CHECK (created_by IN ('user', 'agent')),
|
|
revision INTEGER NOT NULL CHECK (revision >= 0),
|
|
PRIMARY KEY (session_key, tab_id),
|
|
FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS board_widgets (
|
|
session_key TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
tab_id TEXT NOT NULL,
|
|
title TEXT,
|
|
content_kind TEXT NOT NULL CHECK (content_kind IN ('html', 'mcp-app', 'plugin')),
|
|
html BLOB,
|
|
descriptor_json TEXT,
|
|
sha256 TEXT NOT NULL,
|
|
view_generation TEXT,
|
|
revision INTEGER NOT NULL CHECK (revision >= 1),
|
|
size_w INTEGER NOT NULL CHECK (size_w BETWEEN 1 AND 12),
|
|
size_h INTEGER NOT NULL CHECK (size_h BETWEEN 1 AND 20),
|
|
position INTEGER NOT NULL CHECK (position >= 0),
|
|
manifest TEXT NOT NULL DEFAULT '{}',
|
|
grant_state TEXT NOT NULL DEFAULT 'none' CHECK (grant_state IN ('none', 'pending', 'granted', 'rejected')),
|
|
granted_sha TEXT,
|
|
created_by TEXT NOT NULL CHECK (created_by IN ('user', 'agent')),
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_key, name),
|
|
FOREIGN KEY (session_key, tab_id) REFERENCES board_tabs(session_key, tab_id) ON DELETE CASCADE,
|
|
CHECK (
|
|
(content_kind = 'html' AND html IS NOT NULL AND descriptor_json IS NULL AND view_generation IS NOT NULL) OR
|
|
(content_kind = 'mcp-app' AND html IS NULL AND descriptor_json IS NOT NULL AND view_generation IS NULL) OR
|
|
(content_kind = 'plugin' AND html IS NULL AND descriptor_json IS NOT NULL AND view_generation IS NULL)
|
|
)
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_board_widgets_tab_position
|
|
ON board_widgets(session_key, tab_id, position);
|
|
|
|
CREATE TABLE IF NOT EXISTS heartbeat_outcomes (
|
|
session_key TEXT NOT NULL PRIMARY KEY,
|
|
run_session_key TEXT NOT NULL,
|
|
outcome TEXT NOT NULL CHECK (outcome IN ('progress', 'done', 'blocked', 'needs_attention')),
|
|
summary TEXT NOT NULL,
|
|
response_reason TEXT,
|
|
priority TEXT CHECK (priority IS NULL OR priority IN ('low', 'normal', 'high')),
|
|
next_check TEXT,
|
|
task_names_json TEXT,
|
|
wake_source TEXT,
|
|
wake_reason TEXT,
|
|
occurred_at INTEGER NOT NULL,
|
|
context_run_id TEXT,
|
|
context_claimed_at INTEGER,
|
|
updated_at INTEGER NOT NULL,
|
|
FOREIGN KEY (session_key) REFERENCES session_nodes(session_key) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS transcript_events (
|
|
session_id TEXT NOT NULL,
|
|
seq INTEGER NOT NULL,
|
|
event_json TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_id, seq),
|
|
FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS transcript_rewrite_watermarks (
|
|
session_id TEXT NOT NULL PRIMARY KEY,
|
|
generation TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS trajectory_runtime_events (
|
|
session_id TEXT NOT NULL,
|
|
seq INTEGER NOT NULL,
|
|
run_id TEXT,
|
|
event_json TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_id, seq),
|
|
FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_trajectory_runtime_run
|
|
ON trajectory_runtime_events(session_id, run_id, seq)
|
|
WHERE run_id IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS acp_parent_stream_events (
|
|
session_id TEXT NOT NULL,
|
|
run_id TEXT NOT NULL,
|
|
seq INTEGER NOT NULL,
|
|
event_json TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_id, run_id, seq),
|
|
FOREIGN KEY (session_id) REFERENCES "session_windows"(session_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_acp_parent_stream_run
|
|
ON acp_parent_stream_events(run_id, seq);
|
|
|
|
CREATE TABLE IF NOT EXISTS transcript_event_identities (
|
|
session_id TEXT NOT NULL,
|
|
event_id TEXT NOT NULL,
|
|
seq INTEGER NOT NULL,
|
|
event_type TEXT,
|
|
parent_id TEXT,
|
|
message_idempotency_key TEXT,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (session_id, event_id),
|
|
FOREIGN KEY (session_id, seq) REFERENCES transcript_events(session_id, seq) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_message_idempotency
|
|
ON transcript_event_identities(session_id, message_idempotency_key)
|
|
WHERE message_idempotency_key IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_transcript_event_parent
|
|
ON transcript_event_identities(session_id, parent_id)
|
|
WHERE parent_id IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_transcript_event_sequence
|
|
ON transcript_event_identities(session_id, event_type, seq DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS context_engine_turn_outbox (
|
|
advancement_key TEXT NOT NULL PRIMARY KEY,
|
|
engine_id TEXT NOT NULL,
|
|
owner_plugin_id TEXT,
|
|
session_id TEXT NOT NULL,
|
|
payload_json TEXT NOT NULL,
|
|
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
last_attempt_at INTEGER,
|
|
last_error TEXT,
|
|
created_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_context_engine_turn_outbox_engine
|
|
ON context_engine_turn_outbox(engine_id, created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS cache_entries (
|
|
scope TEXT NOT NULL,
|
|
key TEXT NOT NULL,
|
|
value_json TEXT,
|
|
blob BLOB,
|
|
expires_at INTEGER,
|
|
updated_at INTEGER NOT NULL,
|
|
PRIMARY KEY (scope, key)
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_cache_expiry
|
|
ON cache_entries(scope, expires_at, key)
|
|
WHERE expires_at IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_cache_updated
|
|
ON cache_entries(scope, updated_at DESC, key);
|
|
|
|
CREATE TABLE IF NOT EXISTS auth_profile_store (
|
|
store_key TEXT NOT NULL PRIMARY KEY,
|
|
store_json TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS auth_profile_state (
|
|
state_key TEXT NOT NULL PRIMARY KEY,
|
|
state_json TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_meta (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_sources (
|
|
id INTEGER PRIMARY KEY,
|
|
path TEXT NOT NULL,
|
|
source TEXT NOT NULL DEFAULT 'memory',
|
|
hash TEXT NOT NULL,
|
|
mtime REAL NOT NULL,
|
|
size INTEGER NOT NULL,
|
|
UNIQUE (path, source)
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_chunks (
|
|
id TEXT PRIMARY KEY,
|
|
path TEXT NOT NULL,
|
|
source TEXT NOT NULL DEFAULT 'memory',
|
|
start_line INTEGER NOT NULL,
|
|
end_line INTEGER NOT NULL,
|
|
hash TEXT NOT NULL,
|
|
model TEXT NOT NULL,
|
|
text TEXT NOT NULL,
|
|
embedding TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_chunk_recall_metadata (
|
|
chunk_id TEXT PRIMARY KEY,
|
|
importance INTEGER CHECK (importance IS NULL OR importance BETWEEN 1 AND 10),
|
|
triggers TEXT,
|
|
project_key TEXT,
|
|
FOREIGN KEY (chunk_id) REFERENCES memory_index_chunks(id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_chunk_provenance (
|
|
chunk_id TEXT PRIMARY KEY,
|
|
origin_class TEXT NOT NULL CHECK (origin_class IN ('owner', 'agent', 'untrusted', 'system')),
|
|
session_kind TEXT NOT NULL CHECK (session_kind IN ('interactive', 'cron', 'heartbeat', 'subagent', 'unknown')),
|
|
observed_at INTEGER NOT NULL,
|
|
supersedes_key TEXT,
|
|
FOREIGN KEY (chunk_id) REFERENCES memory_index_chunks(id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_embedding_cache (
|
|
provider TEXT NOT NULL,
|
|
model TEXT NOT NULL,
|
|
provider_key TEXT NOT NULL,
|
|
hash TEXT NOT NULL,
|
|
embedding TEXT NOT NULL,
|
|
dims INTEGER,
|
|
updated_at INTEGER NOT NULL,
|
|
PRIMARY KEY (provider, model, provider_key, hash)
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS memory_index_state (
|
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
revision INTEGER NOT NULL
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS standing_intents (
|
|
intent_key INTEGER PRIMARY KEY,
|
|
id TEXT NOT NULL UNIQUE,
|
|
description TEXT NOT NULL,
|
|
trigger_keywords TEXT NOT NULL,
|
|
trigger_embedding TEXT,
|
|
channel_scope TEXT,
|
|
sender_scope TEXT,
|
|
creator_sender TEXT CHECK (creator_sender IS NULL OR length(trim(creator_sender)) > 0),
|
|
status TEXT NOT NULL CHECK (status IN ('pending', 'armed', 'fired', 'done', 'cancelled', 'expired')),
|
|
expires_at INTEGER NOT NULL,
|
|
max_fires INTEGER NOT NULL CHECK (max_fires > 0),
|
|
fire_count INTEGER NOT NULL DEFAULT 0 CHECK (fire_count >= 0),
|
|
cooldown_seconds INTEGER NOT NULL DEFAULT 86400 CHECK (cooldown_seconds >= 0),
|
|
last_fired_at INTEGER,
|
|
created_at INTEGER NOT NULL,
|
|
source_session_id TEXT
|
|
) STRICT;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_standing_intents_lifecycle
|
|
ON standing_intents(status, expires_at, last_fired_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_standing_intents_scope
|
|
ON standing_intents(status, channel_scope, sender_scope);
|
|
|
|
CREATE VIRTUAL TABLE IF NOT EXISTS standing_intents_fts USING fts5(
|
|
trigger_keywords,
|
|
content = 'standing_intents',
|
|
content_rowid = 'intent_key',
|
|
tokenize = 'unicode61 remove_diacritics 2'
|
|
);
|
|
|
|
CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_insert
|
|
AFTER INSERT ON standing_intents
|
|
BEGIN
|
|
INSERT INTO standing_intents_fts(rowid, trigger_keywords)
|
|
VALUES (new.intent_key, new.trigger_keywords);
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_delete
|
|
AFTER DELETE ON standing_intents
|
|
BEGIN
|
|
INSERT INTO standing_intents_fts(standing_intents_fts, rowid, trigger_keywords)
|
|
VALUES ('delete', old.intent_key, old.trigger_keywords);
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS standing_intents_fts_after_update
|
|
AFTER UPDATE OF trigger_keywords ON standing_intents
|
|
BEGIN
|
|
INSERT INTO standing_intents_fts(standing_intents_fts, rowid, trigger_keywords)
|
|
VALUES ('delete', old.intent_key, old.trigger_keywords);
|
|
INSERT INTO standing_intents_fts(rowid, trigger_keywords)
|
|
VALUES (new.intent_key, new.trigger_keywords);
|
|
END;
|
|
|
|
CREATE TABLE IF NOT EXISTS session_transcript_index_state (
|
|
session_id TEXT NOT NULL PRIMARY KEY,
|
|
indexed_seq INTEGER NOT NULL,
|
|
leaf_event_id TEXT,
|
|
needs_rebuild INTEGER NOT NULL DEFAULT 0,
|
|
active_event_count INTEGER NOT NULL DEFAULT 0,
|
|
active_message_count INTEGER NOT NULL DEFAULT 0,
|
|
updated_at INTEGER NOT NULL,
|
|
FOREIGN KEY (session_id) REFERENCES session_windows(session_id) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE TABLE IF NOT EXISTS session_transcript_active_events (
|
|
session_id TEXT NOT NULL,
|
|
active_position INTEGER NOT NULL CHECK (active_position >= 0),
|
|
event_seq INTEGER NOT NULL,
|
|
message_position INTEGER CHECK (message_position IS NULL OR message_position >= 0),
|
|
PRIMARY KEY (session_id, active_position),
|
|
FOREIGN KEY (session_id, event_seq) REFERENCES transcript_events(session_id, seq) ON DELETE CASCADE
|
|
) STRICT;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_active_event_seq
|
|
ON session_transcript_active_events(session_id, event_seq);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_transcript_active_messages
|
|
ON session_transcript_active_events(session_id, message_position)
|
|
WHERE message_position IS NOT NULL;
|
|
|
|
CREATE VIRTUAL TABLE IF NOT EXISTS session_transcript_fts USING fts5(
|
|
text,
|
|
session_id UNINDEXED,
|
|
message_id UNINDEXED,
|
|
role UNINDEXED,
|
|
timestamp UNINDEXED,
|
|
tokenize = 'unicode61 remove_diacritics 2'
|
|
);
|
|
|
|
INSERT OR IGNORE INTO memory_index_state (id, revision) VALUES (1, 0);
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_insert
|
|
AFTER INSERT ON memory_index_sources
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_update
|
|
AFTER UPDATE ON memory_index_sources
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_sources_revision_after_delete
|
|
AFTER DELETE ON memory_index_sources
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_insert
|
|
AFTER INSERT ON memory_index_chunks
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_update
|
|
AFTER UPDATE ON memory_index_chunks
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE TRIGGER IF NOT EXISTS memory_index_chunks_revision_after_delete
|
|
AFTER DELETE ON memory_index_chunks
|
|
BEGIN
|
|
UPDATE memory_index_state SET revision = revision + 1 WHERE id = 1;
|
|
END;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_memory_embedding_cache_updated_at
|
|
ON memory_embedding_cache(updated_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_memory_index_sources_source
|
|
ON memory_index_sources(source);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_path_source
|
|
ON memory_index_chunks(path, source);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_path
|
|
ON memory_index_chunks(path);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_memory_index_chunks_source
|
|
ON memory_index_chunks(source);
|