@withone/mem 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/bin/mem +36 -0
- package/dist/cli.d.ts +28 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +656 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +94 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +461 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +14 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +514 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
- package/skills/context/SKILL.md +168 -0
- package/skills/remember/SKILL.md +144 -0
- package/skills/search/SKILL.md +137 -0
- package/skills/setup/SKILL.md +162 -0
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mem Database Schema
|
|
3
|
+
* https://mem.now
|
|
4
|
+
*
|
|
5
|
+
* Two tables:
|
|
6
|
+
* - mem_records: All memories
|
|
7
|
+
* - mem_links: Relationships between records
|
|
8
|
+
*/
|
|
9
|
+
export declare const SCHEMA_VERSION = "1.0.0";
|
|
10
|
+
export declare const SCHEMA_SQL = "\n-- =============================================================================\n-- Mem: Memory for AI Agents\n-- https://mem.now\n-- Version: 1.0.0\n-- =============================================================================\n\n-- Enable required extensions\nCREATE EXTENSION IF NOT EXISTS vector;\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\n\n-- =============================================================================\n-- RECORDS: All memories\n-- =============================================================================\n\nCREATE TABLE IF NOT EXISTS mem_records (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n type TEXT NOT NULL, -- user-defined (note, decision, preference, etc.)\n data JSONB NOT NULL, -- flexible structure\n tags TEXT[],\n embedding vector(1536),\n searchable_text TEXT,\n searchable tsvector GENERATED ALWAYS AS (\n to_tsvector('english', COALESCE(searchable_text, ''))\n ) STORED,\n\n -- Relevance scoring\n weight INTEGER NOT NULL DEFAULT 5 CHECK (weight BETWEEN 1 AND 10),\n access_count INTEGER NOT NULL DEFAULT 0,\n last_accessed_at TIMESTAMPTZ,\n status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),\n\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\n-- =============================================================================\n-- LINKS: Relationships between records\n-- =============================================================================\n\nCREATE TABLE IF NOT EXISTS mem_links (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n from_id UUID NOT NULL REFERENCES mem_records(id) ON DELETE CASCADE,\n to_id UUID NOT NULL REFERENCES mem_records(id) ON DELETE CASCADE,\n relation TEXT NOT NULL,\n bidirectional BOOLEAN NOT NULL DEFAULT false, -- true = traversable both ways\n metadata JSONB,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n UNIQUE(from_id, to_id, relation)\n);\n\n-- =============================================================================\n-- INDEXES\n-- =============================================================================\n\nCREATE INDEX IF NOT EXISTS idx_mem_records_type ON mem_records(type);\nCREATE INDEX IF NOT EXISTS idx_mem_records_tags ON mem_records USING GIN(tags);\nCREATE INDEX IF NOT EXISTS idx_mem_records_data ON mem_records USING GIN(data);\nCREATE INDEX IF NOT EXISTS idx_mem_records_searchable ON mem_records USING GIN(searchable);\nCREATE INDEX IF NOT EXISTS idx_mem_records_status ON mem_records(status);\nCREATE INDEX IF NOT EXISTS idx_mem_records_relevance ON mem_records(\n status, weight DESC, access_count DESC, last_accessed_at DESC NULLS LAST\n);\n\nCREATE INDEX IF NOT EXISTS idx_mem_links_from ON mem_links(from_id);\nCREATE INDEX IF NOT EXISTS idx_mem_links_to ON mem_links(to_id);\nCREATE INDEX IF NOT EXISTS idx_mem_links_relation ON mem_links(relation);\nCREATE INDEX IF NOT EXISTS idx_mem_links_from_relation ON mem_links(from_id, relation);\nCREATE INDEX IF NOT EXISTS idx_mem_links_to_relation ON mem_links(to_id, relation);\nCREATE INDEX IF NOT EXISTS idx_mem_links_bidirectional ON mem_links(bidirectional) WHERE bidirectional = true;\n\n-- =============================================================================\n-- SCHEMA METADATA\n-- =============================================================================\n\nCREATE TABLE IF NOT EXISTS mem_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nINSERT INTO mem_meta (key, value) VALUES ('version', '1.0.0')\nON CONFLICT (key) DO UPDATE SET value = '1.0.0', updated_at = NOW();\n";
|
|
11
|
+
export declare const VECTOR_INDEX_SQL = "\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_mem_records_embedding') THEN\n CREATE INDEX idx_mem_records_embedding ON mem_records USING hnsw(embedding vector_cosine_ops);\n END IF;\nEND $$;\n";
|
|
12
|
+
export declare const FUNCTIONS_SQL = "\n-- =============================================================================\n-- HYBRID SEARCH\n-- Combines semantic similarity with full-text search using RRF\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_hybrid_search(\n query_text TEXT,\n query_embedding vector(1536),\n match_count INT DEFAULT 10,\n filter_type TEXT DEFAULT NULL,\n full_text_weight FLOAT DEFAULT 0.3,\n semantic_weight FLOAT DEFAULT 0.7,\n rrf_k INT DEFAULT 50,\n include_archived BOOLEAN DEFAULT FALSE\n)\nRETURNS TABLE (\n id UUID,\n type TEXT,\n data JSONB,\n tags TEXT[],\n fts_rank FLOAT,\n semantic_rank FLOAT,\n combined_score FLOAT\n)\nLANGUAGE plpgsql\nAS $$\nBEGIN\n RETURN QUERY\n WITH fts_results AS (\n SELECT\n r.id,\n ROW_NUMBER() OVER (ORDER BY ts_rank_cd(r.searchable, websearch_to_tsquery('english', query_text)) DESC) AS rank\n FROM mem_records r\n WHERE r.searchable @@ websearch_to_tsquery('english', query_text)\n AND (filter_type IS NULL OR r.type = filter_type)\n AND (include_archived OR r.status = 'active')\n LIMIT match_count * 2\n ),\n semantic_results AS (\n SELECT\n r.id,\n ROW_NUMBER() OVER (ORDER BY r.embedding <=> query_embedding) AS rank\n FROM mem_records r\n WHERE r.embedding IS NOT NULL\n AND (filter_type IS NULL OR r.type = filter_type)\n AND (include_archived OR r.status = 'active')\n ORDER BY r.embedding <=> query_embedding\n LIMIT match_count * 2\n ),\n combined AS (\n SELECT\n COALESCE(fts.id, sem.id) AS id,\n COALESCE(1.0 / (rrf_k + fts.rank), 0.0) AS fts_score,\n COALESCE(1.0 / (rrf_k + sem.rank), 0.0) AS sem_score\n FROM fts_results fts\n FULL OUTER JOIN semantic_results sem ON fts.id = sem.id\n )\n SELECT\n r.id,\n r.type,\n r.data,\n r.tags,\n c.fts_score::FLOAT AS fts_rank,\n c.sem_score::FLOAT AS semantic_rank,\n (c.fts_score * full_text_weight + c.sem_score * semantic_weight)::FLOAT AS combined_score\n FROM combined c\n JOIN mem_records r ON r.id = c.id\n ORDER BY (c.fts_score * full_text_weight + c.sem_score * semantic_weight) DESC\n LIMIT match_count;\nEND;\n$$;\n\n-- =============================================================================\n-- RELEVANCE SCORING\n-- Combines: weight (40%), access frequency (30%), recency (30%)\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_calculate_relevance(\n p_weight INTEGER,\n p_access_count INTEGER,\n p_last_accessed_at TIMESTAMPTZ,\n p_created_at TIMESTAMPTZ,\n max_access_count INTEGER DEFAULT 100\n)\nRETURNS FLOAT\nLANGUAGE plpgsql\nAS $$\nDECLARE\n weight_score FLOAT;\n access_score FLOAT;\n recency_score FLOAT;\n days_since_access FLOAT;\nBEGIN\n -- Normalize weight to 0-1 (weight is 1-10)\n weight_score := (p_weight - 1) / 9.0;\n\n -- Normalize access count to 0-1 (capped at max_access_count)\n access_score := LEAST(p_access_count::FLOAT / max_access_count, 1.0);\n\n -- Calculate recency score (1.0 for today, decays over 30 days to 0.1)\n IF p_last_accessed_at IS NOT NULL THEN\n days_since_access := EXTRACT(EPOCH FROM (NOW() - p_last_accessed_at)) / 86400.0;\n recency_score := GREATEST(1.0 - (days_since_access / 30.0) * 0.9, 0.1);\n ELSE\n -- Never accessed, use created_at with lower base score\n days_since_access := EXTRACT(EPOCH FROM (NOW() - p_created_at)) / 86400.0;\n recency_score := GREATEST(0.5 - (days_since_access / 60.0) * 0.4, 0.1);\n END IF;\n\n -- Combine scores: weight 40%, access 30%, recency 30%\n RETURN (weight_score * 0.4) + (access_score * 0.3) + (recency_score * 0.3);\nEND;\n$$;\n\n-- =============================================================================\n-- CONTEXT: Get most relevant records for startup\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_get_context(\n match_count INT DEFAULT 20,\n filter_types TEXT[] DEFAULT NULL\n)\nRETURNS TABLE (\n id UUID,\n type TEXT,\n data JSONB,\n tags TEXT[],\n weight INTEGER,\n access_count INTEGER,\n relevance_score FLOAT\n)\nLANGUAGE plpgsql\nAS $$\nBEGIN\n RETURN QUERY\n SELECT\n r.id,\n r.type,\n r.data,\n r.tags,\n r.weight,\n r.access_count,\n mem_calculate_relevance(r.weight, r.access_count, r.last_accessed_at, r.created_at)::FLOAT AS relevance_score\n FROM mem_records r\n WHERE r.status = 'active'\n AND (filter_types IS NULL OR r.type = ANY(filter_types))\n ORDER BY mem_calculate_relevance(r.weight, r.access_count, r.last_accessed_at, r.created_at) DESC\n LIMIT match_count;\nEND;\n$$;\n\n-- =============================================================================\n-- ACCESS TRACKING\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_increment_access(record_ids UUID[])\nRETURNS VOID\nLANGUAGE plpgsql\nAS $$\nBEGIN\n UPDATE mem_records\n SET\n access_count = access_count + 1,\n last_accessed_at = NOW()\n WHERE id = ANY(record_ids);\nEND;\n$$;\n\n-- =============================================================================\n-- ARCHIVE / UNARCHIVE\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_archive(record_ids UUID[])\nRETURNS INTEGER\nLANGUAGE plpgsql\nAS $$\nDECLARE\n affected INTEGER;\nBEGIN\n UPDATE mem_records\n SET status = 'archived', updated_at = NOW()\n WHERE id = ANY(record_ids) AND status = 'active';\n GET DIAGNOSTICS affected = ROW_COUNT;\n RETURN affected;\nEND;\n$$;\n\nCREATE OR REPLACE FUNCTION mem_unarchive(record_ids UUID[])\nRETURNS INTEGER\nLANGUAGE plpgsql\nAS $$\nDECLARE\n affected INTEGER;\nBEGIN\n UPDATE mem_records\n SET status = 'active', updated_at = NOW()\n WHERE id = ANY(record_ids) AND status = 'archived';\n GET DIAGNOSTICS affected = ROW_COUNT;\n RETURN affected;\nEND;\n$$;\n\n-- =============================================================================\n-- FLUSH: Reset access count\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_flush(record_ids UUID[])\nRETURNS INTEGER\nLANGUAGE plpgsql\nAS $$\nDECLARE\n affected INTEGER;\nBEGIN\n UPDATE mem_records\n SET\n access_count = 0,\n last_accessed_at = NULL,\n updated_at = NOW()\n WHERE id = ANY(record_ids);\n GET DIAGNOSTICS affected = ROW_COUNT;\n RETURN affected;\nEND;\n$$;\n\n-- =============================================================================\n-- GRAPH TRAVERSAL\n-- Respects bidirectional flag\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_get_record_with_links(record_id UUID)\nRETURNS JSONB\nLANGUAGE sql\nAS $$\n SELECT jsonb_build_object(\n 'id', r.id,\n 'type', r.type,\n 'data', r.data,\n 'tags', r.tags,\n 'weight', r.weight,\n 'access_count', r.access_count,\n 'status', r.status,\n 'created_at', r.created_at,\n 'updated_at', r.updated_at,\n 'outgoing', COALESCE((\n SELECT jsonb_agg(jsonb_build_object(\n 'relation', l.relation,\n 'bidirectional', l.bidirectional,\n 'metadata', l.metadata,\n 'record', jsonb_build_object(\n 'id', linked.id,\n 'type', linked.type,\n 'data', linked.data\n )\n ))\n FROM mem_links l\n JOIN mem_records linked ON linked.id = l.to_id\n WHERE l.from_id = r.id\n ), '[]'::jsonb),\n 'incoming', COALESCE((\n SELECT jsonb_agg(jsonb_build_object(\n 'relation', l.relation,\n 'bidirectional', l.bidirectional,\n 'metadata', l.metadata,\n 'record', jsonb_build_object(\n 'id', linked.id,\n 'type', linked.type,\n 'data', linked.data\n )\n ))\n FROM mem_links l\n JOIN mem_records linked ON linked.id = l.from_id\n WHERE l.to_id = r.id\n ), '[]'::jsonb)\n )\n FROM mem_records r\n WHERE r.id = record_id;\n$$;\n\nCREATE OR REPLACE FUNCTION mem_get_linked(\n record_id UUID,\n relation_type TEXT DEFAULT NULL,\n direction TEXT DEFAULT 'outgoing'\n)\nRETURNS TABLE (\n id UUID,\n type TEXT,\n data JSONB,\n relation TEXT,\n bidirectional BOOLEAN,\n link_metadata JSONB\n)\nLANGUAGE sql\nAS $$\n -- Outgoing links (from this record to others)\n SELECT\n r.id,\n r.type,\n r.data,\n l.relation,\n l.bidirectional,\n l.metadata\n FROM mem_links l\n JOIN mem_records r ON r.id = l.to_id\n WHERE l.from_id = record_id\n AND (relation_type IS NULL OR l.relation = relation_type)\n AND (direction = 'outgoing' OR direction = 'both')\n\n UNION ALL\n\n -- Incoming links (from others to this record)\n -- Only include if bidirectional=true OR direction includes incoming\n SELECT\n r.id,\n r.type,\n r.data,\n l.relation,\n l.bidirectional,\n l.metadata\n FROM mem_links l\n JOIN mem_records r ON r.id = l.from_id\n WHERE l.to_id = record_id\n AND (relation_type IS NULL OR l.relation = relation_type)\n AND (\n direction = 'incoming'\n OR direction = 'both'\n OR l.bidirectional = true\n );\n$$;\n\n-- =============================================================================\n-- LINK OPERATIONS\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_create_link(\n from_record_id UUID,\n to_record_id UUID,\n relation_type TEXT,\n is_bidirectional BOOLEAN DEFAULT false,\n link_metadata JSONB DEFAULT NULL\n)\nRETURNS UUID\nLANGUAGE plpgsql\nAS $$\nDECLARE\n link_id UUID;\nBEGIN\n INSERT INTO mem_links (from_id, to_id, relation, bidirectional, metadata)\n VALUES (from_record_id, to_record_id, relation_type, is_bidirectional, link_metadata)\n ON CONFLICT (from_id, to_id, relation) DO UPDATE\n SET bidirectional = is_bidirectional,\n metadata = COALESCE(link_metadata, mem_links.metadata)\n RETURNING id INTO link_id;\n RETURN link_id;\nEND;\n$$;\n\nCREATE OR REPLACE FUNCTION mem_remove_link(\n from_record_id UUID,\n to_record_id UUID,\n relation_type TEXT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $$\nBEGIN\n DELETE FROM mem_links\n WHERE from_id = from_record_id\n AND to_id = to_record_id\n AND relation = relation_type;\n RETURN FOUND;\nEND;\n$$;\n\n-- =============================================================================\n-- TRIGGERS\n-- =============================================================================\n\nCREATE OR REPLACE FUNCTION mem_extract_searchable_text(record_type TEXT, record_data JSONB)\nRETURNS TEXT\nLANGUAGE plpgsql\nAS $$\nBEGIN\n -- Generic extraction: concatenate all string values\n RETURN (SELECT string_agg(value::TEXT, ' ')\n FROM jsonb_each_text(record_data)\n WHERE value IS NOT NULL AND value != '');\nEND;\n$$;\n\nCREATE OR REPLACE FUNCTION mem_records_trigger()\nRETURNS TRIGGER\nLANGUAGE plpgsql\nAS $$\nBEGIN\n NEW.searchable_text := mem_extract_searchable_text(NEW.type, NEW.data);\n NEW.updated_at := NOW();\n RETURN NEW;\nEND;\n$$;\n\nDROP TRIGGER IF EXISTS mem_records_before_upsert ON mem_records;\nCREATE TRIGGER mem_records_before_upsert\nBEFORE INSERT OR UPDATE ON mem_records\nFOR EACH ROW\nEXECUTE FUNCTION mem_records_trigger();\n";
|
|
13
|
+
export declare function getMigrationSQL(): string;
|
|
14
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,eAAO,MAAM,UAAU,0qHAmFtB,CAAC;AAGF,eAAO,MAAM,gBAAgB,oPAO5B,CAAC;AAEF,eAAO,MAAM,aAAa,k6XAsZzB,CAAC;AAGF,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mem Database Schema
|
|
3
|
+
* https://mem.now
|
|
4
|
+
*
|
|
5
|
+
* Two tables:
|
|
6
|
+
* - mem_records: All memories
|
|
7
|
+
* - mem_links: Relationships between records
|
|
8
|
+
*/
|
|
9
|
+
export const SCHEMA_VERSION = "1.0.0";
|
|
10
|
+
export const SCHEMA_SQL = `
|
|
11
|
+
-- =============================================================================
|
|
12
|
+
-- Mem: Memory for AI Agents
|
|
13
|
+
-- https://mem.now
|
|
14
|
+
-- Version: ${SCHEMA_VERSION}
|
|
15
|
+
-- =============================================================================
|
|
16
|
+
|
|
17
|
+
-- Enable required extensions
|
|
18
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
19
|
+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
20
|
+
|
|
21
|
+
-- =============================================================================
|
|
22
|
+
-- RECORDS: All memories
|
|
23
|
+
-- =============================================================================
|
|
24
|
+
|
|
25
|
+
CREATE TABLE IF NOT EXISTS mem_records (
|
|
26
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
27
|
+
type TEXT NOT NULL, -- user-defined (note, decision, preference, etc.)
|
|
28
|
+
data JSONB NOT NULL, -- flexible structure
|
|
29
|
+
tags TEXT[],
|
|
30
|
+
embedding vector(1536),
|
|
31
|
+
searchable_text TEXT,
|
|
32
|
+
searchable tsvector GENERATED ALWAYS AS (
|
|
33
|
+
to_tsvector('english', COALESCE(searchable_text, ''))
|
|
34
|
+
) STORED,
|
|
35
|
+
|
|
36
|
+
-- Relevance scoring
|
|
37
|
+
weight INTEGER NOT NULL DEFAULT 5 CHECK (weight BETWEEN 1 AND 10),
|
|
38
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
last_accessed_at TIMESTAMPTZ,
|
|
40
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),
|
|
41
|
+
|
|
42
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
43
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
-- =============================================================================
|
|
47
|
+
-- LINKS: Relationships between records
|
|
48
|
+
-- =============================================================================
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS mem_links (
|
|
51
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
52
|
+
from_id UUID NOT NULL REFERENCES mem_records(id) ON DELETE CASCADE,
|
|
53
|
+
to_id UUID NOT NULL REFERENCES mem_records(id) ON DELETE CASCADE,
|
|
54
|
+
relation TEXT NOT NULL,
|
|
55
|
+
bidirectional BOOLEAN NOT NULL DEFAULT false, -- true = traversable both ways
|
|
56
|
+
metadata JSONB,
|
|
57
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
58
|
+
UNIQUE(from_id, to_id, relation)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
-- =============================================================================
|
|
62
|
+
-- INDEXES
|
|
63
|
+
-- =============================================================================
|
|
64
|
+
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_type ON mem_records(type);
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_tags ON mem_records USING GIN(tags);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_data ON mem_records USING GIN(data);
|
|
68
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_searchable ON mem_records USING GIN(searchable);
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_status ON mem_records(status);
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_mem_records_relevance ON mem_records(
|
|
71
|
+
status, weight DESC, access_count DESC, last_accessed_at DESC NULLS LAST
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_from ON mem_links(from_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_to ON mem_links(to_id);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_relation ON mem_links(relation);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_from_relation ON mem_links(from_id, relation);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_to_relation ON mem_links(to_id, relation);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_mem_links_bidirectional ON mem_links(bidirectional) WHERE bidirectional = true;
|
|
80
|
+
|
|
81
|
+
-- =============================================================================
|
|
82
|
+
-- SCHEMA METADATA
|
|
83
|
+
-- =============================================================================
|
|
84
|
+
|
|
85
|
+
CREATE TABLE IF NOT EXISTS mem_meta (
|
|
86
|
+
key TEXT PRIMARY KEY,
|
|
87
|
+
value TEXT NOT NULL,
|
|
88
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
INSERT INTO mem_meta (key, value) VALUES ('version', '${SCHEMA_VERSION}')
|
|
92
|
+
ON CONFLICT (key) DO UPDATE SET value = '${SCHEMA_VERSION}', updated_at = NOW();
|
|
93
|
+
`;
|
|
94
|
+
// Vector index (created separately)
|
|
95
|
+
export const VECTOR_INDEX_SQL = `
|
|
96
|
+
DO $$
|
|
97
|
+
BEGIN
|
|
98
|
+
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_mem_records_embedding') THEN
|
|
99
|
+
CREATE INDEX idx_mem_records_embedding ON mem_records USING hnsw(embedding vector_cosine_ops);
|
|
100
|
+
END IF;
|
|
101
|
+
END $$;
|
|
102
|
+
`;
|
|
103
|
+
export const FUNCTIONS_SQL = `
|
|
104
|
+
-- =============================================================================
|
|
105
|
+
-- HYBRID SEARCH
|
|
106
|
+
-- Combines semantic similarity with full-text search using RRF
|
|
107
|
+
-- =============================================================================
|
|
108
|
+
|
|
109
|
+
CREATE OR REPLACE FUNCTION mem_hybrid_search(
|
|
110
|
+
query_text TEXT,
|
|
111
|
+
query_embedding vector(1536),
|
|
112
|
+
match_count INT DEFAULT 10,
|
|
113
|
+
filter_type TEXT DEFAULT NULL,
|
|
114
|
+
full_text_weight FLOAT DEFAULT 0.3,
|
|
115
|
+
semantic_weight FLOAT DEFAULT 0.7,
|
|
116
|
+
rrf_k INT DEFAULT 50,
|
|
117
|
+
include_archived BOOLEAN DEFAULT FALSE
|
|
118
|
+
)
|
|
119
|
+
RETURNS TABLE (
|
|
120
|
+
id UUID,
|
|
121
|
+
type TEXT,
|
|
122
|
+
data JSONB,
|
|
123
|
+
tags TEXT[],
|
|
124
|
+
fts_rank FLOAT,
|
|
125
|
+
semantic_rank FLOAT,
|
|
126
|
+
combined_score FLOAT
|
|
127
|
+
)
|
|
128
|
+
LANGUAGE plpgsql
|
|
129
|
+
AS $$
|
|
130
|
+
BEGIN
|
|
131
|
+
RETURN QUERY
|
|
132
|
+
WITH fts_results AS (
|
|
133
|
+
SELECT
|
|
134
|
+
r.id,
|
|
135
|
+
ROW_NUMBER() OVER (ORDER BY ts_rank_cd(r.searchable, websearch_to_tsquery('english', query_text)) DESC) AS rank
|
|
136
|
+
FROM mem_records r
|
|
137
|
+
WHERE r.searchable @@ websearch_to_tsquery('english', query_text)
|
|
138
|
+
AND (filter_type IS NULL OR r.type = filter_type)
|
|
139
|
+
AND (include_archived OR r.status = 'active')
|
|
140
|
+
LIMIT match_count * 2
|
|
141
|
+
),
|
|
142
|
+
semantic_results AS (
|
|
143
|
+
SELECT
|
|
144
|
+
r.id,
|
|
145
|
+
ROW_NUMBER() OVER (ORDER BY r.embedding <=> query_embedding) AS rank
|
|
146
|
+
FROM mem_records r
|
|
147
|
+
WHERE r.embedding IS NOT NULL
|
|
148
|
+
AND (filter_type IS NULL OR r.type = filter_type)
|
|
149
|
+
AND (include_archived OR r.status = 'active')
|
|
150
|
+
ORDER BY r.embedding <=> query_embedding
|
|
151
|
+
LIMIT match_count * 2
|
|
152
|
+
),
|
|
153
|
+
combined AS (
|
|
154
|
+
SELECT
|
|
155
|
+
COALESCE(fts.id, sem.id) AS id,
|
|
156
|
+
COALESCE(1.0 / (rrf_k + fts.rank), 0.0) AS fts_score,
|
|
157
|
+
COALESCE(1.0 / (rrf_k + sem.rank), 0.0) AS sem_score
|
|
158
|
+
FROM fts_results fts
|
|
159
|
+
FULL OUTER JOIN semantic_results sem ON fts.id = sem.id
|
|
160
|
+
)
|
|
161
|
+
SELECT
|
|
162
|
+
r.id,
|
|
163
|
+
r.type,
|
|
164
|
+
r.data,
|
|
165
|
+
r.tags,
|
|
166
|
+
c.fts_score::FLOAT AS fts_rank,
|
|
167
|
+
c.sem_score::FLOAT AS semantic_rank,
|
|
168
|
+
(c.fts_score * full_text_weight + c.sem_score * semantic_weight)::FLOAT AS combined_score
|
|
169
|
+
FROM combined c
|
|
170
|
+
JOIN mem_records r ON r.id = c.id
|
|
171
|
+
ORDER BY (c.fts_score * full_text_weight + c.sem_score * semantic_weight) DESC
|
|
172
|
+
LIMIT match_count;
|
|
173
|
+
END;
|
|
174
|
+
$$;
|
|
175
|
+
|
|
176
|
+
-- =============================================================================
|
|
177
|
+
-- RELEVANCE SCORING
|
|
178
|
+
-- Combines: weight (40%), access frequency (30%), recency (30%)
|
|
179
|
+
-- =============================================================================
|
|
180
|
+
|
|
181
|
+
CREATE OR REPLACE FUNCTION mem_calculate_relevance(
|
|
182
|
+
p_weight INTEGER,
|
|
183
|
+
p_access_count INTEGER,
|
|
184
|
+
p_last_accessed_at TIMESTAMPTZ,
|
|
185
|
+
p_created_at TIMESTAMPTZ,
|
|
186
|
+
max_access_count INTEGER DEFAULT 100
|
|
187
|
+
)
|
|
188
|
+
RETURNS FLOAT
|
|
189
|
+
LANGUAGE plpgsql
|
|
190
|
+
AS $$
|
|
191
|
+
DECLARE
|
|
192
|
+
weight_score FLOAT;
|
|
193
|
+
access_score FLOAT;
|
|
194
|
+
recency_score FLOAT;
|
|
195
|
+
days_since_access FLOAT;
|
|
196
|
+
BEGIN
|
|
197
|
+
-- Normalize weight to 0-1 (weight is 1-10)
|
|
198
|
+
weight_score := (p_weight - 1) / 9.0;
|
|
199
|
+
|
|
200
|
+
-- Normalize access count to 0-1 (capped at max_access_count)
|
|
201
|
+
access_score := LEAST(p_access_count::FLOAT / max_access_count, 1.0);
|
|
202
|
+
|
|
203
|
+
-- Calculate recency score (1.0 for today, decays over 30 days to 0.1)
|
|
204
|
+
IF p_last_accessed_at IS NOT NULL THEN
|
|
205
|
+
days_since_access := EXTRACT(EPOCH FROM (NOW() - p_last_accessed_at)) / 86400.0;
|
|
206
|
+
recency_score := GREATEST(1.0 - (days_since_access / 30.0) * 0.9, 0.1);
|
|
207
|
+
ELSE
|
|
208
|
+
-- Never accessed, use created_at with lower base score
|
|
209
|
+
days_since_access := EXTRACT(EPOCH FROM (NOW() - p_created_at)) / 86400.0;
|
|
210
|
+
recency_score := GREATEST(0.5 - (days_since_access / 60.0) * 0.4, 0.1);
|
|
211
|
+
END IF;
|
|
212
|
+
|
|
213
|
+
-- Combine scores: weight 40%, access 30%, recency 30%
|
|
214
|
+
RETURN (weight_score * 0.4) + (access_score * 0.3) + (recency_score * 0.3);
|
|
215
|
+
END;
|
|
216
|
+
$$;
|
|
217
|
+
|
|
218
|
+
-- =============================================================================
|
|
219
|
+
-- CONTEXT: Get most relevant records for startup
|
|
220
|
+
-- =============================================================================
|
|
221
|
+
|
|
222
|
+
CREATE OR REPLACE FUNCTION mem_get_context(
|
|
223
|
+
match_count INT DEFAULT 20,
|
|
224
|
+
filter_types TEXT[] DEFAULT NULL
|
|
225
|
+
)
|
|
226
|
+
RETURNS TABLE (
|
|
227
|
+
id UUID,
|
|
228
|
+
type TEXT,
|
|
229
|
+
data JSONB,
|
|
230
|
+
tags TEXT[],
|
|
231
|
+
weight INTEGER,
|
|
232
|
+
access_count INTEGER,
|
|
233
|
+
relevance_score FLOAT
|
|
234
|
+
)
|
|
235
|
+
LANGUAGE plpgsql
|
|
236
|
+
AS $$
|
|
237
|
+
BEGIN
|
|
238
|
+
RETURN QUERY
|
|
239
|
+
SELECT
|
|
240
|
+
r.id,
|
|
241
|
+
r.type,
|
|
242
|
+
r.data,
|
|
243
|
+
r.tags,
|
|
244
|
+
r.weight,
|
|
245
|
+
r.access_count,
|
|
246
|
+
mem_calculate_relevance(r.weight, r.access_count, r.last_accessed_at, r.created_at)::FLOAT AS relevance_score
|
|
247
|
+
FROM mem_records r
|
|
248
|
+
WHERE r.status = 'active'
|
|
249
|
+
AND (filter_types IS NULL OR r.type = ANY(filter_types))
|
|
250
|
+
ORDER BY mem_calculate_relevance(r.weight, r.access_count, r.last_accessed_at, r.created_at) DESC
|
|
251
|
+
LIMIT match_count;
|
|
252
|
+
END;
|
|
253
|
+
$$;
|
|
254
|
+
|
|
255
|
+
-- =============================================================================
|
|
256
|
+
-- ACCESS TRACKING
|
|
257
|
+
-- =============================================================================
|
|
258
|
+
|
|
259
|
+
CREATE OR REPLACE FUNCTION mem_increment_access(record_ids UUID[])
|
|
260
|
+
RETURNS VOID
|
|
261
|
+
LANGUAGE plpgsql
|
|
262
|
+
AS $$
|
|
263
|
+
BEGIN
|
|
264
|
+
UPDATE mem_records
|
|
265
|
+
SET
|
|
266
|
+
access_count = access_count + 1,
|
|
267
|
+
last_accessed_at = NOW()
|
|
268
|
+
WHERE id = ANY(record_ids);
|
|
269
|
+
END;
|
|
270
|
+
$$;
|
|
271
|
+
|
|
272
|
+
-- =============================================================================
|
|
273
|
+
-- ARCHIVE / UNARCHIVE
|
|
274
|
+
-- =============================================================================
|
|
275
|
+
|
|
276
|
+
CREATE OR REPLACE FUNCTION mem_archive(record_ids UUID[])
|
|
277
|
+
RETURNS INTEGER
|
|
278
|
+
LANGUAGE plpgsql
|
|
279
|
+
AS $$
|
|
280
|
+
DECLARE
|
|
281
|
+
affected INTEGER;
|
|
282
|
+
BEGIN
|
|
283
|
+
UPDATE mem_records
|
|
284
|
+
SET status = 'archived', updated_at = NOW()
|
|
285
|
+
WHERE id = ANY(record_ids) AND status = 'active';
|
|
286
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
287
|
+
RETURN affected;
|
|
288
|
+
END;
|
|
289
|
+
$$;
|
|
290
|
+
|
|
291
|
+
CREATE OR REPLACE FUNCTION mem_unarchive(record_ids UUID[])
|
|
292
|
+
RETURNS INTEGER
|
|
293
|
+
LANGUAGE plpgsql
|
|
294
|
+
AS $$
|
|
295
|
+
DECLARE
|
|
296
|
+
affected INTEGER;
|
|
297
|
+
BEGIN
|
|
298
|
+
UPDATE mem_records
|
|
299
|
+
SET status = 'active', updated_at = NOW()
|
|
300
|
+
WHERE id = ANY(record_ids) AND status = 'archived';
|
|
301
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
302
|
+
RETURN affected;
|
|
303
|
+
END;
|
|
304
|
+
$$;
|
|
305
|
+
|
|
306
|
+
-- =============================================================================
|
|
307
|
+
-- FLUSH: Reset access count
|
|
308
|
+
-- =============================================================================
|
|
309
|
+
|
|
310
|
+
CREATE OR REPLACE FUNCTION mem_flush(record_ids UUID[])
|
|
311
|
+
RETURNS INTEGER
|
|
312
|
+
LANGUAGE plpgsql
|
|
313
|
+
AS $$
|
|
314
|
+
DECLARE
|
|
315
|
+
affected INTEGER;
|
|
316
|
+
BEGIN
|
|
317
|
+
UPDATE mem_records
|
|
318
|
+
SET
|
|
319
|
+
access_count = 0,
|
|
320
|
+
last_accessed_at = NULL,
|
|
321
|
+
updated_at = NOW()
|
|
322
|
+
WHERE id = ANY(record_ids);
|
|
323
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
324
|
+
RETURN affected;
|
|
325
|
+
END;
|
|
326
|
+
$$;
|
|
327
|
+
|
|
328
|
+
-- =============================================================================
|
|
329
|
+
-- GRAPH TRAVERSAL
|
|
330
|
+
-- Respects bidirectional flag
|
|
331
|
+
-- =============================================================================
|
|
332
|
+
|
|
333
|
+
CREATE OR REPLACE FUNCTION mem_get_record_with_links(record_id UUID)
|
|
334
|
+
RETURNS JSONB
|
|
335
|
+
LANGUAGE sql
|
|
336
|
+
AS $$
|
|
337
|
+
SELECT jsonb_build_object(
|
|
338
|
+
'id', r.id,
|
|
339
|
+
'type', r.type,
|
|
340
|
+
'data', r.data,
|
|
341
|
+
'tags', r.tags,
|
|
342
|
+
'weight', r.weight,
|
|
343
|
+
'access_count', r.access_count,
|
|
344
|
+
'status', r.status,
|
|
345
|
+
'created_at', r.created_at,
|
|
346
|
+
'updated_at', r.updated_at,
|
|
347
|
+
'outgoing', COALESCE((
|
|
348
|
+
SELECT jsonb_agg(jsonb_build_object(
|
|
349
|
+
'relation', l.relation,
|
|
350
|
+
'bidirectional', l.bidirectional,
|
|
351
|
+
'metadata', l.metadata,
|
|
352
|
+
'record', jsonb_build_object(
|
|
353
|
+
'id', linked.id,
|
|
354
|
+
'type', linked.type,
|
|
355
|
+
'data', linked.data
|
|
356
|
+
)
|
|
357
|
+
))
|
|
358
|
+
FROM mem_links l
|
|
359
|
+
JOIN mem_records linked ON linked.id = l.to_id
|
|
360
|
+
WHERE l.from_id = r.id
|
|
361
|
+
), '[]'::jsonb),
|
|
362
|
+
'incoming', COALESCE((
|
|
363
|
+
SELECT jsonb_agg(jsonb_build_object(
|
|
364
|
+
'relation', l.relation,
|
|
365
|
+
'bidirectional', l.bidirectional,
|
|
366
|
+
'metadata', l.metadata,
|
|
367
|
+
'record', jsonb_build_object(
|
|
368
|
+
'id', linked.id,
|
|
369
|
+
'type', linked.type,
|
|
370
|
+
'data', linked.data
|
|
371
|
+
)
|
|
372
|
+
))
|
|
373
|
+
FROM mem_links l
|
|
374
|
+
JOIN mem_records linked ON linked.id = l.from_id
|
|
375
|
+
WHERE l.to_id = r.id
|
|
376
|
+
), '[]'::jsonb)
|
|
377
|
+
)
|
|
378
|
+
FROM mem_records r
|
|
379
|
+
WHERE r.id = record_id;
|
|
380
|
+
$$;
|
|
381
|
+
|
|
382
|
+
CREATE OR REPLACE FUNCTION mem_get_linked(
|
|
383
|
+
record_id UUID,
|
|
384
|
+
relation_type TEXT DEFAULT NULL,
|
|
385
|
+
direction TEXT DEFAULT 'outgoing'
|
|
386
|
+
)
|
|
387
|
+
RETURNS TABLE (
|
|
388
|
+
id UUID,
|
|
389
|
+
type TEXT,
|
|
390
|
+
data JSONB,
|
|
391
|
+
relation TEXT,
|
|
392
|
+
bidirectional BOOLEAN,
|
|
393
|
+
link_metadata JSONB
|
|
394
|
+
)
|
|
395
|
+
LANGUAGE sql
|
|
396
|
+
AS $$
|
|
397
|
+
-- Outgoing links (from this record to others)
|
|
398
|
+
SELECT
|
|
399
|
+
r.id,
|
|
400
|
+
r.type,
|
|
401
|
+
r.data,
|
|
402
|
+
l.relation,
|
|
403
|
+
l.bidirectional,
|
|
404
|
+
l.metadata
|
|
405
|
+
FROM mem_links l
|
|
406
|
+
JOIN mem_records r ON r.id = l.to_id
|
|
407
|
+
WHERE l.from_id = record_id
|
|
408
|
+
AND (relation_type IS NULL OR l.relation = relation_type)
|
|
409
|
+
AND (direction = 'outgoing' OR direction = 'both')
|
|
410
|
+
|
|
411
|
+
UNION ALL
|
|
412
|
+
|
|
413
|
+
-- Incoming links (from others to this record)
|
|
414
|
+
-- Only include if bidirectional=true OR direction includes incoming
|
|
415
|
+
SELECT
|
|
416
|
+
r.id,
|
|
417
|
+
r.type,
|
|
418
|
+
r.data,
|
|
419
|
+
l.relation,
|
|
420
|
+
l.bidirectional,
|
|
421
|
+
l.metadata
|
|
422
|
+
FROM mem_links l
|
|
423
|
+
JOIN mem_records r ON r.id = l.from_id
|
|
424
|
+
WHERE l.to_id = record_id
|
|
425
|
+
AND (relation_type IS NULL OR l.relation = relation_type)
|
|
426
|
+
AND (
|
|
427
|
+
direction = 'incoming'
|
|
428
|
+
OR direction = 'both'
|
|
429
|
+
OR l.bidirectional = true
|
|
430
|
+
);
|
|
431
|
+
$$;
|
|
432
|
+
|
|
433
|
+
-- =============================================================================
|
|
434
|
+
-- LINK OPERATIONS
|
|
435
|
+
-- =============================================================================
|
|
436
|
+
|
|
437
|
+
CREATE OR REPLACE FUNCTION mem_create_link(
|
|
438
|
+
from_record_id UUID,
|
|
439
|
+
to_record_id UUID,
|
|
440
|
+
relation_type TEXT,
|
|
441
|
+
is_bidirectional BOOLEAN DEFAULT false,
|
|
442
|
+
link_metadata JSONB DEFAULT NULL
|
|
443
|
+
)
|
|
444
|
+
RETURNS UUID
|
|
445
|
+
LANGUAGE plpgsql
|
|
446
|
+
AS $$
|
|
447
|
+
DECLARE
|
|
448
|
+
link_id UUID;
|
|
449
|
+
BEGIN
|
|
450
|
+
INSERT INTO mem_links (from_id, to_id, relation, bidirectional, metadata)
|
|
451
|
+
VALUES (from_record_id, to_record_id, relation_type, is_bidirectional, link_metadata)
|
|
452
|
+
ON CONFLICT (from_id, to_id, relation) DO UPDATE
|
|
453
|
+
SET bidirectional = is_bidirectional,
|
|
454
|
+
metadata = COALESCE(link_metadata, mem_links.metadata)
|
|
455
|
+
RETURNING id INTO link_id;
|
|
456
|
+
RETURN link_id;
|
|
457
|
+
END;
|
|
458
|
+
$$;
|
|
459
|
+
|
|
460
|
+
CREATE OR REPLACE FUNCTION mem_remove_link(
|
|
461
|
+
from_record_id UUID,
|
|
462
|
+
to_record_id UUID,
|
|
463
|
+
relation_type TEXT
|
|
464
|
+
)
|
|
465
|
+
RETURNS BOOLEAN
|
|
466
|
+
LANGUAGE plpgsql
|
|
467
|
+
AS $$
|
|
468
|
+
BEGIN
|
|
469
|
+
DELETE FROM mem_links
|
|
470
|
+
WHERE from_id = from_record_id
|
|
471
|
+
AND to_id = to_record_id
|
|
472
|
+
AND relation = relation_type;
|
|
473
|
+
RETURN FOUND;
|
|
474
|
+
END;
|
|
475
|
+
$$;
|
|
476
|
+
|
|
477
|
+
-- =============================================================================
|
|
478
|
+
-- TRIGGERS
|
|
479
|
+
-- =============================================================================
|
|
480
|
+
|
|
481
|
+
CREATE OR REPLACE FUNCTION mem_extract_searchable_text(record_type TEXT, record_data JSONB)
|
|
482
|
+
RETURNS TEXT
|
|
483
|
+
LANGUAGE plpgsql
|
|
484
|
+
AS $$
|
|
485
|
+
BEGIN
|
|
486
|
+
-- Generic extraction: concatenate all string values
|
|
487
|
+
RETURN (SELECT string_agg(value::TEXT, ' ')
|
|
488
|
+
FROM jsonb_each_text(record_data)
|
|
489
|
+
WHERE value IS NOT NULL AND value != '');
|
|
490
|
+
END;
|
|
491
|
+
$$;
|
|
492
|
+
|
|
493
|
+
CREATE OR REPLACE FUNCTION mem_records_trigger()
|
|
494
|
+
RETURNS TRIGGER
|
|
495
|
+
LANGUAGE plpgsql
|
|
496
|
+
AS $$
|
|
497
|
+
BEGIN
|
|
498
|
+
NEW.searchable_text := mem_extract_searchable_text(NEW.type, NEW.data);
|
|
499
|
+
NEW.updated_at := NOW();
|
|
500
|
+
RETURN NEW;
|
|
501
|
+
END;
|
|
502
|
+
$$;
|
|
503
|
+
|
|
504
|
+
DROP TRIGGER IF EXISTS mem_records_before_upsert ON mem_records;
|
|
505
|
+
CREATE TRIGGER mem_records_before_upsert
|
|
506
|
+
BEFORE INSERT OR UPDATE ON mem_records
|
|
507
|
+
FOR EACH ROW
|
|
508
|
+
EXECUTE FUNCTION mem_records_trigger();
|
|
509
|
+
`;
|
|
510
|
+
// Full migration SQL (combines schema + vector index + functions)
|
|
511
|
+
export function getMigrationSQL() {
|
|
512
|
+
return `${SCHEMA_SQL}\n\n${VECTOR_INDEX_SQL}\n\n${FUNCTIONS_SQL}`;
|
|
513
|
+
}
|
|
514
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;cAIZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDA6E4B,cAAc;2CAC3B,cAAc;CACxD,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;CAO/B,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsZ5B,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,eAAe;IAC7B,OAAO,GAAG,UAAU,OAAO,gBAAgB,OAAO,aAAa,EAAE,CAAC;AACpE,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mem Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
export interface MemRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
data: Record<string, unknown>;
|
|
8
|
+
tags?: string[];
|
|
9
|
+
embedding?: number[];
|
|
10
|
+
searchable_text?: string;
|
|
11
|
+
weight: number;
|
|
12
|
+
access_count: number;
|
|
13
|
+
last_accessed_at?: string;
|
|
14
|
+
status: "active" | "archived";
|
|
15
|
+
created_at: string;
|
|
16
|
+
updated_at: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MemLink {
|
|
19
|
+
id: string;
|
|
20
|
+
from_id: string;
|
|
21
|
+
to_id: string;
|
|
22
|
+
relation: string;
|
|
23
|
+
bidirectional: boolean;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
created_at: string;
|
|
26
|
+
}
|
|
27
|
+
export interface MemRecordWithLinks extends MemRecord {
|
|
28
|
+
outgoing: Array<{
|
|
29
|
+
relation: string;
|
|
30
|
+
bidirectional: boolean;
|
|
31
|
+
metadata?: Record<string, unknown>;
|
|
32
|
+
record: {
|
|
33
|
+
id: string;
|
|
34
|
+
type: string;
|
|
35
|
+
data: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
38
|
+
incoming: Array<{
|
|
39
|
+
relation: string;
|
|
40
|
+
bidirectional: boolean;
|
|
41
|
+
metadata?: Record<string, unknown>;
|
|
42
|
+
record: {
|
|
43
|
+
id: string;
|
|
44
|
+
type: string;
|
|
45
|
+
data: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export interface SearchResult {
|
|
50
|
+
id: string;
|
|
51
|
+
type: string;
|
|
52
|
+
data: Record<string, unknown>;
|
|
53
|
+
tags?: string[];
|
|
54
|
+
fts_rank: number;
|
|
55
|
+
semantic_rank: number;
|
|
56
|
+
combined_score: number;
|
|
57
|
+
}
|
|
58
|
+
export interface ContextResult {
|
|
59
|
+
id: string;
|
|
60
|
+
type: string;
|
|
61
|
+
data: Record<string, unknown>;
|
|
62
|
+
tags?: string[];
|
|
63
|
+
weight: number;
|
|
64
|
+
access_count: number;
|
|
65
|
+
relevance_score: number;
|
|
66
|
+
}
|
|
67
|
+
export interface AddRecordOptions {
|
|
68
|
+
tags?: string[];
|
|
69
|
+
weight?: number;
|
|
70
|
+
generateEmbedding?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface UpdateRecordOptions {
|
|
73
|
+
tags?: string[];
|
|
74
|
+
regenerateEmbedding?: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface SearchOptions {
|
|
77
|
+
limit?: number;
|
|
78
|
+
type?: string;
|
|
79
|
+
ftsWeight?: number;
|
|
80
|
+
semanticWeight?: number;
|
|
81
|
+
includeArchived?: boolean;
|
|
82
|
+
trackAccess?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export interface ContextOptions {
|
|
85
|
+
limit?: number;
|
|
86
|
+
types?: string[];
|
|
87
|
+
}
|
|
88
|
+
export interface LinkedOptions {
|
|
89
|
+
relation?: string;
|
|
90
|
+
direction?: "outgoing" | "incoming" | "both";
|
|
91
|
+
}
|
|
92
|
+
export interface LinkedRecord {
|
|
93
|
+
id: string;
|
|
94
|
+
type: string;
|
|
95
|
+
data: Record<string, unknown>;
|
|
96
|
+
relation: string;
|
|
97
|
+
bidirectional: boolean;
|
|
98
|
+
link_metadata?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|