Spaces:
Paused
Paused
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- AGENTE AI — Schema Supabase completo | |
| -- Incolla questo file nel SQL Editor: Dashboard → SQL Editor → New query → Run | |
| -- Tutti gli statement sono idempotenti (IF NOT EXISTS / CREATE OR REPLACE). | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- ── 0. Estensioni ───────────────────────────────────────────────────────────── | |
| CREATE EXTENSION IF NOT EXISTS vector; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 1. MEMORIA EPISODICA — tabella episodes | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.episodes ( | |
| id BIGSERIAL PRIMARY KEY, | |
| type TEXT NOT NULL, | |
| task TEXT NOT NULL, | |
| output TEXT, | |
| success INTEGER DEFAULT 1, | |
| ts TEXT NOT NULL, | |
| tags TEXT DEFAULT '[]' | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_episodes_type ON public.episodes (type); | |
| CREATE INDEX IF NOT EXISTS idx_episodes_ts ON public.episodes (ts); | |
| ALTER TABLE public.episodes ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='episodes' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.episodes FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 2. MEMORIA SEMANTICA — tabella semantic_memory + pgvector | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.semantic_memory ( | |
| id TEXT PRIMARY KEY, | |
| content TEXT NOT NULL, | |
| metadata JSONB DEFAULT '{}' | |
| ); | |
| ALTER TABLE public.semantic_memory | |
| ADD COLUMN IF NOT EXISTS embedding vector(384); | |
| ALTER TABLE public.semantic_memory ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='semantic_memory' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.semantic_memory FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| CREATE OR REPLACE FUNCTION match_semantic_memory( | |
| query_embedding vector(384), | |
| match_count int DEFAULT 5, | |
| match_threshold float DEFAULT 0.2 | |
| ) | |
| RETURNS TABLE (id text, content text, metadata jsonb, similarity float) | |
| LANGUAGE sql STABLE AS $$ | |
| SELECT id, content, metadata, | |
| (1 - (embedding <=> query_embedding))::float AS similarity | |
| FROM public.semantic_memory | |
| WHERE embedding IS NOT NULL | |
| AND (1 - (embedding <=> query_embedding)) > match_threshold | |
| ORDER BY embedding <=> query_embedding | |
| LIMIT match_count; | |
| $$; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 3. MEMORIA AGENTE — tabella agent_memory (incident registry + decision memory) | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.agent_memory ( | |
| key TEXT PRIMARY KEY, | |
| value TEXT NOT NULL DEFAULT '{}', | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT now() | |
| ); | |
| ALTER TABLE public.agent_memory ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='agent_memory' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.agent_memory FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 4. TASK AGENTE — tabelle agent_tasks + agent_task_events | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.agent_tasks ( | |
| task_id TEXT PRIMARY KEY, | |
| goal TEXT NOT NULL, | |
| status TEXT NOT NULL DEFAULT 'QUEUED', | |
| max_steps INTEGER NOT NULL DEFAULT 8, | |
| context TEXT NOT NULL DEFAULT '[]', | |
| created_at BIGINT NOT NULL DEFAULT 0, | |
| updated_at BIGINT NOT NULL DEFAULT 0 | |
| ); | |
| CREATE TABLE IF NOT EXISTS public.agent_task_events ( | |
| id BIGSERIAL PRIMARY KEY, | |
| task_id TEXT NOT NULL REFERENCES public.agent_tasks(task_id) ON DELETE CASCADE, | |
| event_index INTEGER NOT NULL, | |
| event_data TEXT NOT NULL, | |
| created_at BIGINT NOT NULL DEFAULT 0, | |
| UNIQUE (task_id, event_index) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_agent_task_events_lookup | |
| ON public.agent_task_events (task_id, event_index ASC); | |
| ALTER TABLE public.agent_tasks ENABLE ROW LEVEL SECURITY; | |
| ALTER TABLE public.agent_task_events ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='agent_tasks' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.agent_tasks FOR ALL TO anon USING (true) WITH CHECK (true); | |
| CREATE POLICY "anon full access" ON public.agent_task_events FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| CREATE OR REPLACE FUNCTION purge_old_agent_tasks() RETURNS void | |
| LANGUAGE plpgsql AS $$ | |
| DECLARE cutoff BIGINT := (EXTRACT(EPOCH FROM NOW()) * 1000 - 7 * 86400000)::BIGINT; | |
| BEGIN DELETE FROM public.agent_tasks WHERE updated_at < cutoff; END; | |
| $$; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 5. SKILL TRACKER — tabelle skill_stats + skill_patterns | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE OR REPLACE FUNCTION _touch_updated_at() | |
| RETURNS TRIGGER LANGUAGE plpgsql AS $$ | |
| BEGIN NEW.updated_at = now(); RETURN NEW; END; | |
| $$; | |
| CREATE TABLE IF NOT EXISTS public.skill_stats ( | |
| session_id TEXT NOT NULL, | |
| tool_name TEXT NOT NULL, | |
| success_count INTEGER NOT NULL DEFAULT 0, | |
| fail_count INTEGER NOT NULL DEFAULT 0, | |
| last_used DOUBLE PRECISION NOT NULL DEFAULT 0, | |
| total_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0, | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), | |
| PRIMARY KEY (session_id, tool_name) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_skill_stats_session ON public.skill_stats (session_id); | |
| ALTER TABLE public.skill_stats ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='skill_stats' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.skill_stats FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| DROP TRIGGER IF EXISTS trg_skill_stats_updated_at ON public.skill_stats; | |
| CREATE TRIGGER trg_skill_stats_updated_at BEFORE UPDATE ON public.skill_stats | |
| FOR EACH ROW EXECUTE FUNCTION _touch_updated_at(); | |
| CREATE TABLE IF NOT EXISTS public.skill_patterns ( | |
| id TEXT PRIMARY KEY, | |
| task_signature TEXT NOT NULL, | |
| tool_sequence TEXT[] NOT NULL, | |
| success_count INTEGER NOT NULL DEFAULT 0, | |
| total_count INTEGER NOT NULL DEFAULT 0, | |
| last_used BIGINT NOT NULL DEFAULT 0, | |
| confidence DOUBLE PRECISION NOT NULL DEFAULT 0, | |
| updated_at TIMESTAMPTZ NOT NULL DEFAULT now() | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_skill_patterns_confidence ON public.skill_patterns (confidence DESC); | |
| CREATE INDEX IF NOT EXISTS idx_skill_patterns_last_used ON public.skill_patterns (last_used DESC); | |
| ALTER TABLE public.skill_patterns ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='skill_patterns' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.skill_patterns FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| DROP TRIGGER IF EXISTS trg_skill_patterns_updated_at ON public.skill_patterns; | |
| CREATE TRIGGER trg_skill_patterns_updated_at BEFORE UPDATE ON public.skill_patterns | |
| FOR EACH ROW EXECUTE FUNCTION _touch_updated_at(); | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 6. FILE SYSTEM VIRTUALE — tabella vfs_files | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.vfs_files ( | |
| id TEXT PRIMARY KEY, | |
| path TEXT NOT NULL, | |
| content TEXT NOT NULL DEFAULT '', | |
| mime_type TEXT NOT NULL DEFAULT 'text/plain', | |
| size BIGINT NOT NULL DEFAULT 0, | |
| created_at BIGINT NOT NULL DEFAULT 0, | |
| updated_at BIGINT NOT NULL DEFAULT 0 | |
| ); | |
| ALTER TABLE public.vfs_files ADD COLUMN IF NOT EXISTS version BIGINT NOT NULL DEFAULT 0; | |
| CREATE INDEX IF NOT EXISTS idx_vfs_files_path ON public.vfs_files (path); | |
| CREATE INDEX IF NOT EXISTS vfs_files_version_idx ON public.vfs_files (id, version); | |
| ALTER TABLE public.vfs_files ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='vfs_files' AND policyname='anon full access') THEN | |
| CREATE POLICY "anon full access" ON public.vfs_files FOR ALL TO anon USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| CREATE OR REPLACE FUNCTION public._vfs_bump_version() | |
| RETURNS TRIGGER LANGUAGE plpgsql AS $$ | |
| BEGIN NEW.version = OLD.version + 1; RETURN NEW; END; | |
| $$; | |
| DROP TRIGGER IF EXISTS trg_vfs_version ON public.vfs_files; | |
| CREATE TRIGGER trg_vfs_version BEFORE UPDATE ON public.vfs_files | |
| FOR EACH ROW EXECUTE FUNCTION public._vfs_bump_version(); | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- 7. TOKEN OAUTH — tabelle managed_tokens + oauth_states | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| CREATE TABLE IF NOT EXISTS public.managed_tokens ( | |
| user_id TEXT NOT NULL DEFAULT 'default', | |
| provider TEXT NOT NULL, | |
| access_token TEXT NOT NULL DEFAULT '', | |
| refresh_token TEXT NOT NULL DEFAULT '', | |
| expires_at BIGINT NOT NULL DEFAULT 0, | |
| scope TEXT NOT NULL DEFAULT '', | |
| raw_meta TEXT NOT NULL DEFAULT '{}', | |
| created_at BIGINT NOT NULL DEFAULT 0, | |
| updated_at BIGINT NOT NULL DEFAULT 0, | |
| UNIQUE (user_id, provider) | |
| ); | |
| CREATE INDEX IF NOT EXISTS managed_tokens_user_idx ON public.managed_tokens (user_id, provider); | |
| ALTER TABLE public.managed_tokens ENABLE ROW LEVEL SECURITY; | |
| DO $$ BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='managed_tokens' AND policyname='service only') THEN | |
| CREATE POLICY "service only" ON public.managed_tokens FOR ALL TO service_role USING (true) WITH CHECK (true); | |
| END IF; | |
| END $$; | |
| CREATE TABLE IF NOT EXISTS public.oauth_states ( | |
| state TEXT PRIMARY KEY, | |
| provider TEXT NOT NULL, | |
| user_id TEXT NOT NULL DEFAULT 'default', | |
| created_at BIGINT NOT NULL DEFAULT 0 | |
| ); | |
| CREATE OR REPLACE FUNCTION public._purge_oauth_states() RETURNS void | |
| LANGUAGE plpgsql AS $$ | |
| BEGIN | |
| DELETE FROM public.oauth_states | |
| WHERE created_at < (EXTRACT(EPOCH FROM NOW()) * 1000 - 600000)::BIGINT; | |
| END; | |
| $$; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |
| -- FINE — Verifica eseguendo: | |
| -- SELECT table_name FROM information_schema.tables | |
| -- WHERE table_schema = 'public' ORDER BY table_name; | |
| -- ══════════════════════════════════════════════════════════════════════════════ | |