@twelvehart/supermemory-runtime 1.0.0-next.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/.env.example +57 -0
- package/README.md +374 -0
- package/dist/index.js +189 -0
- package/dist/mcp/index.js +1132 -0
- package/docker-compose.prod.yml +91 -0
- package/docker-compose.yml +358 -0
- package/drizzle/0000_dapper_the_professor.sql +159 -0
- package/drizzle/0001_api_keys.sql +51 -0
- package/drizzle/meta/0000_snapshot.json +1532 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +20 -0
- package/package.json +114 -0
- package/scripts/add-extraction-job.ts +122 -0
- package/scripts/benchmark-pgvector.ts +122 -0
- package/scripts/bootstrap.sh +209 -0
- package/scripts/check-runtime-pack.ts +111 -0
- package/scripts/claude-mcp-config.ts +336 -0
- package/scripts/docker-entrypoint.sh +183 -0
- package/scripts/doctor.ts +377 -0
- package/scripts/init-db.sql +33 -0
- package/scripts/install.sh +1110 -0
- package/scripts/mcp-setup.ts +271 -0
- package/scripts/migrations/001_create_pgvector_extension.sql +31 -0
- package/scripts/migrations/002_create_memory_embeddings_table.sql +75 -0
- package/scripts/migrations/003_create_hnsw_index.sql +94 -0
- package/scripts/migrations/004_create_memory_embeddings_standalone.sql +70 -0
- package/scripts/migrations/005_create_chunks_table.sql +95 -0
- package/scripts/migrations/006_create_processing_queue.sql +45 -0
- package/scripts/migrations/generate_test_data.sql +42 -0
- package/scripts/migrations/phase1_comprehensive_test.sql +204 -0
- package/scripts/migrations/run_migrations.sh +286 -0
- package/scripts/migrations/test_hnsw_index.sql +255 -0
- package/scripts/pre-commit-secrets +282 -0
- package/scripts/run-extraction-worker.ts +46 -0
- package/scripts/run-phase1-tests.sh +291 -0
- package/scripts/setup.ts +222 -0
- package/scripts/smoke-install.sh +12 -0
- package/scripts/test-health-endpoint.sh +328 -0
- package/src/api/index.ts +2 -0
- package/src/api/middleware/auth.ts +80 -0
- package/src/api/middleware/csrf.ts +308 -0
- package/src/api/middleware/errorHandler.ts +166 -0
- package/src/api/middleware/rateLimit.ts +360 -0
- package/src/api/middleware/validation.ts +514 -0
- package/src/api/routes/documents.ts +286 -0
- package/src/api/routes/profiles.ts +237 -0
- package/src/api/routes/search.ts +71 -0
- package/src/api/stores/index.ts +58 -0
- package/src/config/bootstrap-env.ts +3 -0
- package/src/config/env.ts +71 -0
- package/src/config/feature-flags.ts +25 -0
- package/src/config/index.ts +140 -0
- package/src/config/secrets.config.ts +291 -0
- package/src/db/client.ts +92 -0
- package/src/db/index.ts +73 -0
- package/src/db/postgres.ts +72 -0
- package/src/db/schema/chunks.schema.ts +31 -0
- package/src/db/schema/containers.schema.ts +46 -0
- package/src/db/schema/documents.schema.ts +49 -0
- package/src/db/schema/embeddings.schema.ts +32 -0
- package/src/db/schema/index.ts +11 -0
- package/src/db/schema/memories.schema.ts +72 -0
- package/src/db/schema/profiles.schema.ts +34 -0
- package/src/db/schema/queue.schema.ts +59 -0
- package/src/db/schema/relationships.schema.ts +42 -0
- package/src/db/schema.ts +223 -0
- package/src/db/worker-connection.ts +47 -0
- package/src/index.ts +235 -0
- package/src/mcp/CLAUDE.md +1 -0
- package/src/mcp/index.ts +1380 -0
- package/src/mcp/legacyState.ts +22 -0
- package/src/mcp/rateLimit.ts +358 -0
- package/src/mcp/resources.ts +309 -0
- package/src/mcp/results.ts +104 -0
- package/src/mcp/tools.ts +401 -0
- package/src/queues/config.ts +119 -0
- package/src/queues/index.ts +289 -0
- package/src/sdk/client.ts +225 -0
- package/src/sdk/errors.ts +266 -0
- package/src/sdk/http.ts +560 -0
- package/src/sdk/index.ts +244 -0
- package/src/sdk/resources/base.ts +65 -0
- package/src/sdk/resources/connections.ts +204 -0
- package/src/sdk/resources/documents.ts +163 -0
- package/src/sdk/resources/index.ts +10 -0
- package/src/sdk/resources/memories.ts +150 -0
- package/src/sdk/resources/search.ts +60 -0
- package/src/sdk/resources/settings.ts +36 -0
- package/src/sdk/types.ts +674 -0
- package/src/services/chunking/index.ts +451 -0
- package/src/services/chunking.service.ts +650 -0
- package/src/services/csrf.service.ts +252 -0
- package/src/services/documents.repository.ts +219 -0
- package/src/services/documents.service.ts +191 -0
- package/src/services/embedding.service.ts +404 -0
- package/src/services/extraction.service.ts +300 -0
- package/src/services/extractors/code.extractor.ts +451 -0
- package/src/services/extractors/index.ts +9 -0
- package/src/services/extractors/markdown.extractor.ts +461 -0
- package/src/services/extractors/pdf.extractor.ts +315 -0
- package/src/services/extractors/text.extractor.ts +118 -0
- package/src/services/extractors/url.extractor.ts +243 -0
- package/src/services/index.ts +235 -0
- package/src/services/ingestion.service.ts +177 -0
- package/src/services/llm/anthropic.ts +400 -0
- package/src/services/llm/base.ts +460 -0
- package/src/services/llm/contradiction-detector.service.ts +526 -0
- package/src/services/llm/heuristics.ts +148 -0
- package/src/services/llm/index.ts +309 -0
- package/src/services/llm/memory-classifier.service.ts +383 -0
- package/src/services/llm/memory-extension-detector.service.ts +523 -0
- package/src/services/llm/mock.ts +470 -0
- package/src/services/llm/openai.ts +398 -0
- package/src/services/llm/prompts.ts +438 -0
- package/src/services/llm/types.ts +373 -0
- package/src/services/memory.repository.ts +1769 -0
- package/src/services/memory.service.ts +1338 -0
- package/src/services/memory.types.ts +234 -0
- package/src/services/persistence/index.ts +295 -0
- package/src/services/pipeline.service.ts +509 -0
- package/src/services/profile.repository.ts +436 -0
- package/src/services/profile.service.ts +560 -0
- package/src/services/profile.types.ts +270 -0
- package/src/services/relationships/detector.ts +1128 -0
- package/src/services/relationships/index.ts +268 -0
- package/src/services/relationships/memory-integration.ts +459 -0
- package/src/services/relationships/strategies.ts +132 -0
- package/src/services/relationships/types.ts +370 -0
- package/src/services/search.service.ts +761 -0
- package/src/services/search.types.ts +220 -0
- package/src/services/secrets.service.ts +384 -0
- package/src/services/vectorstore/base.ts +327 -0
- package/src/services/vectorstore/index.ts +444 -0
- package/src/services/vectorstore/memory.ts +286 -0
- package/src/services/vectorstore/migration.ts +295 -0
- package/src/services/vectorstore/mock.ts +403 -0
- package/src/services/vectorstore/pgvector.ts +695 -0
- package/src/services/vectorstore/types.ts +247 -0
- package/src/startup.ts +389 -0
- package/src/types/api.types.ts +193 -0
- package/src/types/document.types.ts +103 -0
- package/src/types/index.ts +241 -0
- package/src/types/profile.base.ts +133 -0
- package/src/utils/errors.ts +447 -0
- package/src/utils/id.ts +15 -0
- package/src/utils/index.ts +101 -0
- package/src/utils/logger.ts +313 -0
- package/src/utils/sanitization.ts +501 -0
- package/src/utils/secret-validation.ts +273 -0
- package/src/utils/synonyms.ts +188 -0
- package/src/utils/validation.ts +581 -0
- package/src/workers/chunking.worker.ts +242 -0
- package/src/workers/embedding.worker.ts +358 -0
- package/src/workers/extraction.worker.ts +346 -0
- package/src/workers/indexing.worker.ts +505 -0
- package/tsconfig.json +38 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { drizzle } from 'drizzle-orm/node-postgres'
|
|
2
|
+
import { migrate } from 'drizzle-orm/node-postgres/migrator'
|
|
3
|
+
import pkg from 'pg'
|
|
4
|
+
const { Pool } = pkg
|
|
5
|
+
import * as schema from './schema/index.js'
|
|
6
|
+
|
|
7
|
+
let db: ReturnType<typeof drizzle<typeof schema>> | null = null
|
|
8
|
+
let pool: pkg.Pool | null = null
|
|
9
|
+
|
|
10
|
+
function parsePoolNumberEnv(name: string, fallback: number): number {
|
|
11
|
+
const rawValue = process.env[name]
|
|
12
|
+
if (!rawValue) return fallback
|
|
13
|
+
|
|
14
|
+
const parsed = Number.parseInt(rawValue, 10)
|
|
15
|
+
return Number.isFinite(parsed) ? parsed : fallback
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getPostgresPoolConfig(): Pick<
|
|
19
|
+
pkg.PoolConfig,
|
|
20
|
+
'min' | 'max' | 'idleTimeoutMillis' | 'connectionTimeoutMillis'
|
|
21
|
+
> {
|
|
22
|
+
return {
|
|
23
|
+
min: parsePoolNumberEnv('SUPERMEMORY_PG_POOL_MIN', 10),
|
|
24
|
+
max: parsePoolNumberEnv('SUPERMEMORY_PG_POOL_MAX', 100),
|
|
25
|
+
idleTimeoutMillis: parsePoolNumberEnv('SUPERMEMORY_PG_POOL_IDLE_TIMEOUT_MS', 30000),
|
|
26
|
+
connectionTimeoutMillis: parsePoolNumberEnv('SUPERMEMORY_PG_POOL_CONNECTION_TIMEOUT_MS', 2000),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createPostgresDatabase(connectionString: string) {
|
|
31
|
+
// Create connection pool
|
|
32
|
+
pool = new Pool({
|
|
33
|
+
connectionString,
|
|
34
|
+
...getPostgresPoolConfig(),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// Enable pgvector extension on connection
|
|
38
|
+
pool.on('connect', async (client) => {
|
|
39
|
+
try {
|
|
40
|
+
await client.query('CREATE EXTENSION IF NOT EXISTS vector')
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Error enabling pgvector extension:', error)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return drizzle(pool, { schema })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getPostgresDatabase(connectionString: string) {
|
|
50
|
+
if (!db) {
|
|
51
|
+
db = createPostgresDatabase(connectionString)
|
|
52
|
+
}
|
|
53
|
+
return db
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function runPostgresMigrations(connectionString: string) {
|
|
57
|
+
const database = getPostgresDatabase(connectionString)
|
|
58
|
+
await migrate(database, { migrationsFolder: './drizzle' })
|
|
59
|
+
console.log('PostgreSQL migrations completed successfully')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function closePostgresDatabase() {
|
|
63
|
+
if (pool) {
|
|
64
|
+
await pool.end()
|
|
65
|
+
pool = null
|
|
66
|
+
db = null
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type PostgresDatabaseInstance = ReturnType<typeof createPostgresDatabase>
|
|
71
|
+
|
|
72
|
+
export { schema }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { pgTable, uuid, text, integer, jsonb, timestamp, index } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
import { memories } from './memories.schema.js'
|
|
4
|
+
|
|
5
|
+
export const chunks = pgTable(
|
|
6
|
+
'chunks',
|
|
7
|
+
{
|
|
8
|
+
id: uuid('id')
|
|
9
|
+
.primaryKey()
|
|
10
|
+
.default(sql`gen_random_uuid()`),
|
|
11
|
+
memoryId: uuid('memory_id')
|
|
12
|
+
.notNull()
|
|
13
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
14
|
+
content: text('content').notNull(),
|
|
15
|
+
chunkIndex: integer('chunk_index').notNull(),
|
|
16
|
+
startOffset: integer('start_offset'),
|
|
17
|
+
endOffset: integer('end_offset'),
|
|
18
|
+
tokenCount: integer('token_count'),
|
|
19
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
20
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
21
|
+
},
|
|
22
|
+
(table) => [
|
|
23
|
+
index('idx_chunks_memory_id').on(table.memoryId),
|
|
24
|
+
index('idx_chunks_chunk_index').on(table.memoryId, table.chunkIndex),
|
|
25
|
+
index('idx_chunks_token_count').on(table.tokenCount),
|
|
26
|
+
index('idx_chunks_metadata').using('gin', sql`${table.metadata} jsonb_path_ops`),
|
|
27
|
+
]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
export type Chunk = typeof chunks.$inferSelect
|
|
31
|
+
export type NewChunk = typeof chunks.$inferInsert
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pgTable,
|
|
3
|
+
uuid,
|
|
4
|
+
varchar,
|
|
5
|
+
text,
|
|
6
|
+
jsonb,
|
|
7
|
+
boolean,
|
|
8
|
+
timestamp,
|
|
9
|
+
index,
|
|
10
|
+
check,
|
|
11
|
+
type AnyPgColumn,
|
|
12
|
+
} from 'drizzle-orm/pg-core'
|
|
13
|
+
import { sql } from 'drizzle-orm'
|
|
14
|
+
|
|
15
|
+
export const containerTags = pgTable(
|
|
16
|
+
'container_tags',
|
|
17
|
+
{
|
|
18
|
+
id: uuid('id')
|
|
19
|
+
.primaryKey()
|
|
20
|
+
.default(sql`gen_random_uuid()`),
|
|
21
|
+
tag: varchar('tag', { length: 255 }).notNull().unique(),
|
|
22
|
+
parentTag: varchar('parent_tag', { length: 255 }).references((): AnyPgColumn => containerTags.tag, {
|
|
23
|
+
onDelete: 'set null',
|
|
24
|
+
}),
|
|
25
|
+
displayName: varchar('display_name', { length: 255 }),
|
|
26
|
+
description: text('description'),
|
|
27
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
28
|
+
settings: jsonb('settings').default(sql`'{}'::jsonb`),
|
|
29
|
+
isActive: boolean('is_active').notNull().default(true),
|
|
30
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
31
|
+
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
32
|
+
},
|
|
33
|
+
(table) => [
|
|
34
|
+
index('idx_container_tags_parent').on(table.parentTag),
|
|
35
|
+
index('idx_container_tags_active')
|
|
36
|
+
.on(table.isActive)
|
|
37
|
+
.where(sql`${table.isActive} = TRUE`),
|
|
38
|
+
index('idx_container_tags_metadata').using('gin', table.metadata),
|
|
39
|
+
index('idx_container_tags_hierarchy').on(table.tag, table.parentTag),
|
|
40
|
+
check('container_tags_no_self_parent', sql`${table.tag} != ${table.parentTag}`),
|
|
41
|
+
check('container_tags_tag_format', sql`${table.tag} ~ '^[a-zA-Z0-9_-]+$'`),
|
|
42
|
+
]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
export type ContainerTag = typeof containerTags.$inferSelect
|
|
46
|
+
export type NewContainerTag = typeof containerTags.$inferInsert
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { pgTable, uuid, varchar, text, jsonb, timestamp, index, check, integer } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
|
|
4
|
+
export const documents = pgTable(
|
|
5
|
+
'documents',
|
|
6
|
+
{
|
|
7
|
+
id: uuid('id')
|
|
8
|
+
.primaryKey()
|
|
9
|
+
.default(sql`gen_random_uuid()`),
|
|
10
|
+
customId: varchar('custom_id', { length: 255 }),
|
|
11
|
+
content: text('content').notNull(),
|
|
12
|
+
contentType: varchar('content_type', { length: 50 }).notNull().default('text/plain'),
|
|
13
|
+
status: varchar('status', { length: 20 }).notNull().default('pending'),
|
|
14
|
+
containerTag: varchar('container_tag', { length: 255 }).notNull(),
|
|
15
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
16
|
+
contentHash: varchar('content_hash', { length: 64 })
|
|
17
|
+
.generatedAlwaysAs(sql`encode(sha256(content::bytea), 'hex')`)
|
|
18
|
+
.notNull(),
|
|
19
|
+
wordCount: integer('word_count')
|
|
20
|
+
.generatedAlwaysAs(sql`array_length(regexp_split_to_array(content, '\\s+'), 1)`)
|
|
21
|
+
.notNull(),
|
|
22
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
23
|
+
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
24
|
+
},
|
|
25
|
+
(table) => [
|
|
26
|
+
index('idx_documents_container_tag').on(table.containerTag),
|
|
27
|
+
index('idx_documents_status')
|
|
28
|
+
.on(table.status)
|
|
29
|
+
.where(sql`${table.status} != 'processed'`),
|
|
30
|
+
index('idx_documents_custom_id')
|
|
31
|
+
.on(table.customId)
|
|
32
|
+
.where(sql`${table.customId} IS NOT NULL`),
|
|
33
|
+
index('idx_documents_content_hash').on(table.contentHash),
|
|
34
|
+
index('idx_documents_created_at').on(table.createdAt.desc()),
|
|
35
|
+
index('idx_documents_metadata').using('gin', sql`${table.metadata} jsonb_path_ops`),
|
|
36
|
+
index('idx_documents_container_status').on(table.containerTag, table.status, table.createdAt),
|
|
37
|
+
check(
|
|
38
|
+
'documents_status_check',
|
|
39
|
+
sql`${table.status} IN ('pending', 'processing', 'processed', 'failed', 'archived')`
|
|
40
|
+
),
|
|
41
|
+
check(
|
|
42
|
+
'documents_content_type_check',
|
|
43
|
+
sql`${table.contentType} IN ('text/plain', 'text/markdown', 'text/html', 'application/pdf', 'application/json', 'image/png', 'image/jpeg', 'audio/mp3', 'video/mp4')`
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export type Document = typeof documents.$inferSelect
|
|
49
|
+
export type NewDocument = typeof documents.$inferInsert
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { pgTable, uuid, varchar, boolean, timestamp, index, check } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
import { vector } from 'drizzle-orm/pg-core'
|
|
4
|
+
import { memories } from './memories.schema.js'
|
|
5
|
+
|
|
6
|
+
export const memoryEmbeddings = pgTable(
|
|
7
|
+
'memory_embeddings',
|
|
8
|
+
{
|
|
9
|
+
memoryId: uuid('memory_id')
|
|
10
|
+
.primaryKey()
|
|
11
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
12
|
+
embedding: vector('embedding', { dimensions: 1536 }).notNull(),
|
|
13
|
+
model: varchar('model', { length: 100 }).notNull().default('text-embedding-3-small'),
|
|
14
|
+
modelVersion: varchar('model_version', { length: 50 }),
|
|
15
|
+
normalized: boolean('normalized').default(true),
|
|
16
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
17
|
+
},
|
|
18
|
+
(table) => [
|
|
19
|
+
// HNSW index for approximate nearest neighbor search with cosine similarity
|
|
20
|
+
index('idx_memory_embeddings_hnsw')
|
|
21
|
+
.using('hnsw', table.embedding.op('vector_cosine_ops'))
|
|
22
|
+
.with({ m: 16, ef_construction: 64 }),
|
|
23
|
+
index('idx_memory_embeddings_model').on(table.model),
|
|
24
|
+
check(
|
|
25
|
+
'memory_embeddings_model_check',
|
|
26
|
+
sql`${table.model} IN ('text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002', 'voyage-large-2', 'voyage-code-2', 'cohere-embed-v3', 'bge-large-en-v1.5', 'custom')`
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
export type MemoryEmbedding = typeof memoryEmbeddings.$inferSelect
|
|
32
|
+
export type NewMemoryEmbedding = typeof memoryEmbeddings.$inferInsert
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// PostgreSQL Schema Exports
|
|
2
|
+
// This file aggregates all schema definitions for the supermemory PostgreSQL database
|
|
3
|
+
|
|
4
|
+
export * from './containers.schema.js'
|
|
5
|
+
export * from './documents.schema.js'
|
|
6
|
+
export * from './memories.schema.js'
|
|
7
|
+
export * from './chunks.schema.js'
|
|
8
|
+
export * from './embeddings.schema.js'
|
|
9
|
+
export * from './relationships.schema.js'
|
|
10
|
+
export * from './profiles.schema.js'
|
|
11
|
+
export * from './queue.schema.js'
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pgTable,
|
|
3
|
+
uuid,
|
|
4
|
+
text,
|
|
5
|
+
varchar,
|
|
6
|
+
boolean,
|
|
7
|
+
integer,
|
|
8
|
+
decimal,
|
|
9
|
+
jsonb,
|
|
10
|
+
timestamp,
|
|
11
|
+
index,
|
|
12
|
+
check,
|
|
13
|
+
type AnyPgColumn,
|
|
14
|
+
} from 'drizzle-orm/pg-core'
|
|
15
|
+
import { sql } from 'drizzle-orm'
|
|
16
|
+
import { documents } from './documents.schema.js'
|
|
17
|
+
|
|
18
|
+
export const memories = pgTable(
|
|
19
|
+
'memories',
|
|
20
|
+
{
|
|
21
|
+
id: uuid('id')
|
|
22
|
+
.primaryKey()
|
|
23
|
+
.default(sql`gen_random_uuid()`),
|
|
24
|
+
documentId: uuid('document_id').references(() => documents.id, { onDelete: 'set null' }),
|
|
25
|
+
content: text('content').notNull(),
|
|
26
|
+
memoryType: varchar('memory_type', { length: 20 }).notNull().default('fact'),
|
|
27
|
+
isLatest: boolean('is_latest').notNull().default(true),
|
|
28
|
+
similarityHash: varchar('similarity_hash', { length: 64 }).notNull(),
|
|
29
|
+
version: integer('version').notNull().default(1),
|
|
30
|
+
supersedesId: uuid('supersedes_id').references((): AnyPgColumn => memories.id, {
|
|
31
|
+
onDelete: 'set null',
|
|
32
|
+
}),
|
|
33
|
+
containerTag: varchar('container_tag', { length: 255 }).notNull(),
|
|
34
|
+
confidenceScore: decimal('confidence_score', { precision: 4, scale: 3 }).default('1.000'),
|
|
35
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
36
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
37
|
+
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
38
|
+
},
|
|
39
|
+
(table) => [
|
|
40
|
+
index('idx_memories_document_id')
|
|
41
|
+
.on(table.documentId)
|
|
42
|
+
.where(sql`${table.documentId} IS NOT NULL`),
|
|
43
|
+
index('idx_memories_container_tag').on(table.containerTag),
|
|
44
|
+
index('idx_memories_type').on(table.memoryType),
|
|
45
|
+
index('idx_memories_is_latest')
|
|
46
|
+
.on(table.isLatest)
|
|
47
|
+
.where(sql`${table.isLatest} = TRUE`),
|
|
48
|
+
index('idx_memories_similarity_hash').on(table.similarityHash),
|
|
49
|
+
index('idx_memories_supersedes')
|
|
50
|
+
.on(table.supersedesId)
|
|
51
|
+
.where(sql`${table.supersedesId} IS NOT NULL`),
|
|
52
|
+
index('idx_memories_metadata').using('gin', sql`${table.metadata} jsonb_path_ops`),
|
|
53
|
+
index('idx_memories_created_at').on(table.createdAt.desc()),
|
|
54
|
+
index('idx_memories_container_latest')
|
|
55
|
+
.on(table.containerTag, table.isLatest, table.createdAt)
|
|
56
|
+
.where(sql`${table.isLatest} = TRUE`),
|
|
57
|
+
index('idx_memories_container_type_latest')
|
|
58
|
+
.on(table.containerTag, table.memoryType, table.isLatest)
|
|
59
|
+
.where(sql`${table.isLatest} = TRUE`),
|
|
60
|
+
index('idx_memories_version_chain')
|
|
61
|
+
.on(table.supersedesId, table.version)
|
|
62
|
+
.where(sql`${table.supersedesId} IS NOT NULL`),
|
|
63
|
+
check(
|
|
64
|
+
'memories_type_check',
|
|
65
|
+
sql`${table.memoryType} IN ('fact', 'preference', 'episode', 'belief', 'skill', 'context')`
|
|
66
|
+
),
|
|
67
|
+
check('memories_confidence_check', sql`${table.confidenceScore} >= 0 AND ${table.confidenceScore} <= 1`),
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export type Memory = typeof memories.$inferSelect
|
|
72
|
+
export type NewMemory = typeof memories.$inferInsert
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { pgTable, uuid, varchar, jsonb, timestamp, integer, index } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
import { containerTags } from './containers.schema.js'
|
|
4
|
+
|
|
5
|
+
export const userProfiles = pgTable(
|
|
6
|
+
'user_profiles',
|
|
7
|
+
{
|
|
8
|
+
id: uuid('id')
|
|
9
|
+
.primaryKey()
|
|
10
|
+
.default(sql`gen_random_uuid()`),
|
|
11
|
+
containerTag: varchar('container_tag', { length: 255 })
|
|
12
|
+
.notNull()
|
|
13
|
+
.unique()
|
|
14
|
+
.references(() => containerTags.tag, { onDelete: 'cascade' }),
|
|
15
|
+
staticFacts: jsonb('static_facts').default(sql`'[]'::jsonb`),
|
|
16
|
+
dynamicFacts: jsonb('dynamic_facts').default(sql`'[]'::jsonb`),
|
|
17
|
+
preferences: jsonb('preferences').default(sql`'{}'::jsonb`),
|
|
18
|
+
computedTraits: jsonb('computed_traits').default(sql`'{}'::jsonb`),
|
|
19
|
+
lastInteractionAt: timestamp('last_interaction_at', { withTimezone: true }),
|
|
20
|
+
memoryCount: integer('memory_count').default(0),
|
|
21
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
22
|
+
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
23
|
+
},
|
|
24
|
+
(table) => [
|
|
25
|
+
index('idx_user_profiles_container').on(table.containerTag),
|
|
26
|
+
index('idx_user_profiles_static_facts').using('gin', table.staticFacts),
|
|
27
|
+
index('idx_user_profiles_dynamic_facts').using('gin', table.dynamicFacts),
|
|
28
|
+
index('idx_user_profiles_preferences').using('gin', table.preferences),
|
|
29
|
+
index('idx_user_profiles_updated').on(table.updatedAt.desc()),
|
|
30
|
+
]
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export type UserProfile = typeof userProfiles.$inferSelect
|
|
34
|
+
export type NewUserProfile = typeof userProfiles.$inferInsert
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { pgTable, uuid, varchar, text, integer, jsonb, timestamp, index, check } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
import { documents } from './documents.schema.js'
|
|
4
|
+
|
|
5
|
+
export const processingQueue = pgTable(
|
|
6
|
+
'processing_queue',
|
|
7
|
+
{
|
|
8
|
+
id: uuid('id')
|
|
9
|
+
.primaryKey()
|
|
10
|
+
.default(sql`gen_random_uuid()`),
|
|
11
|
+
documentId: uuid('document_id')
|
|
12
|
+
.notNull()
|
|
13
|
+
.references(() => documents.id, { onDelete: 'cascade' }),
|
|
14
|
+
stage: varchar('stage', { length: 30 }).notNull().default('extraction'),
|
|
15
|
+
status: varchar('status', { length: 20 }).notNull().default('pending'),
|
|
16
|
+
priority: integer('priority').default(0),
|
|
17
|
+
error: text('error'),
|
|
18
|
+
errorCode: varchar('error_code', { length: 50 }),
|
|
19
|
+
attempts: integer('attempts').default(0),
|
|
20
|
+
maxAttempts: integer('max_attempts').default(3),
|
|
21
|
+
workerId: varchar('worker_id', { length: 100 }),
|
|
22
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
23
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
24
|
+
startedAt: timestamp('started_at', { withTimezone: true }),
|
|
25
|
+
completedAt: timestamp('completed_at', { withTimezone: true }),
|
|
26
|
+
scheduledAt: timestamp('scheduled_at', { withTimezone: true }).defaultNow(),
|
|
27
|
+
},
|
|
28
|
+
(table) => [
|
|
29
|
+
index('idx_processing_queue_document').on(table.documentId),
|
|
30
|
+
index('idx_processing_queue_status')
|
|
31
|
+
.on(table.status)
|
|
32
|
+
.where(sql`${table.status} IN ('pending', 'retry')`),
|
|
33
|
+
index('idx_processing_queue_stage').on(table.stage),
|
|
34
|
+
index('idx_processing_queue_worker')
|
|
35
|
+
.on(table.workerId)
|
|
36
|
+
.where(sql`${table.workerId} IS NOT NULL`),
|
|
37
|
+
index('idx_processing_queue_priority')
|
|
38
|
+
.on(table.priority.desc(), table.scheduledAt.asc())
|
|
39
|
+
.where(sql`${table.status} IN ('pending', 'retry')`),
|
|
40
|
+
index('idx_processing_queue_stale')
|
|
41
|
+
.on(table.startedAt)
|
|
42
|
+
.where(sql`${table.status} = 'processing'`),
|
|
43
|
+
index('idx_processing_queue_worker_select')
|
|
44
|
+
.on(table.status, table.stage, table.priority, table.scheduledAt)
|
|
45
|
+
.where(sql`${table.status} IN ('pending', 'retry')`),
|
|
46
|
+
check(
|
|
47
|
+
'processing_queue_stage_check',
|
|
48
|
+
sql`${table.stage} IN ('extraction', 'embedding', 'deduplication', 'relationship', 'profile_update', 'cleanup')`
|
|
49
|
+
),
|
|
50
|
+
check(
|
|
51
|
+
'processing_queue_status_check',
|
|
52
|
+
sql`${table.status} IN ('pending', 'processing', 'completed', 'failed', 'cancelled', 'retry')`
|
|
53
|
+
),
|
|
54
|
+
check('processing_queue_attempts_check', sql`${table.attempts} <= ${table.maxAttempts}`),
|
|
55
|
+
]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export type ProcessingQueue = typeof processingQueue.$inferSelect
|
|
59
|
+
export type NewProcessingQueue = typeof processingQueue.$inferInsert
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { pgTable, uuid, varchar, decimal, boolean, jsonb, timestamp, index, check, unique } from 'drizzle-orm/pg-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
import { memories } from './memories.schema.js'
|
|
4
|
+
|
|
5
|
+
export const memoryRelationships = pgTable(
|
|
6
|
+
'memory_relationships',
|
|
7
|
+
{
|
|
8
|
+
id: uuid('id')
|
|
9
|
+
.primaryKey()
|
|
10
|
+
.default(sql`gen_random_uuid()`),
|
|
11
|
+
sourceMemoryId: uuid('source_memory_id')
|
|
12
|
+
.notNull()
|
|
13
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
14
|
+
targetMemoryId: uuid('target_memory_id')
|
|
15
|
+
.notNull()
|
|
16
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
17
|
+
relationshipType: varchar('relationship_type', { length: 30 }).notNull(),
|
|
18
|
+
weight: decimal('weight', { precision: 4, scale: 3 }).default('1.000'),
|
|
19
|
+
bidirectional: boolean('bidirectional').default(false),
|
|
20
|
+
metadata: jsonb('metadata').default(sql`'{}'::jsonb`),
|
|
21
|
+
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
22
|
+
},
|
|
23
|
+
(table) => [
|
|
24
|
+
index('idx_memory_rel_source').on(table.sourceMemoryId),
|
|
25
|
+
index('idx_memory_rel_target').on(table.targetMemoryId),
|
|
26
|
+
index('idx_memory_rel_type').on(table.relationshipType),
|
|
27
|
+
index('idx_memory_rel_bidirectional')
|
|
28
|
+
.on(table.sourceMemoryId, table.targetMemoryId)
|
|
29
|
+
.where(sql`${table.bidirectional} = TRUE`),
|
|
30
|
+
index('idx_memory_rel_graph').on(table.sourceMemoryId, table.targetMemoryId, table.relationshipType, table.weight),
|
|
31
|
+
check(
|
|
32
|
+
'memory_relationships_type_check',
|
|
33
|
+
sql`${table.relationshipType} IN ('updates', 'extends', 'derives', 'contradicts', 'supports', 'relates', 'temporal', 'causal', 'part_of', 'similar')`
|
|
34
|
+
),
|
|
35
|
+
check('memory_relationships_weight_check', sql`${table.weight} >= 0 AND ${table.weight} <= 1`),
|
|
36
|
+
check('memory_relationships_no_self_loop', sql`${table.sourceMemoryId} != ${table.targetMemoryId}`),
|
|
37
|
+
unique('memory_relationships_unique_edge').on(table.sourceMemoryId, table.targetMemoryId, table.relationshipType),
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
export type MemoryRelationship = typeof memoryRelationships.$inferSelect
|
|
42
|
+
export type NewMemoryRelationship = typeof memoryRelationships.$inferInsert
|
package/src/db/schema.ts
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { sqliteTable, text, integer, blob, index, uniqueIndex } from 'drizzle-orm/sqlite-core'
|
|
2
|
+
import { sql } from 'drizzle-orm'
|
|
3
|
+
|
|
4
|
+
// Users table
|
|
5
|
+
export const users = sqliteTable(
|
|
6
|
+
'users',
|
|
7
|
+
{
|
|
8
|
+
id: text('id').primaryKey(),
|
|
9
|
+
email: text('email').notNull().unique(),
|
|
10
|
+
name: text('name'),
|
|
11
|
+
apiKey: text('api_key').notNull().unique(),
|
|
12
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
13
|
+
.notNull()
|
|
14
|
+
.default(sql`(unixepoch())`),
|
|
15
|
+
updatedAt: integer('updated_at', { mode: 'timestamp' })
|
|
16
|
+
.notNull()
|
|
17
|
+
.default(sql`(unixepoch())`),
|
|
18
|
+
},
|
|
19
|
+
(table) => [uniqueIndex('users_email_idx').on(table.email), uniqueIndex('users_api_key_idx').on(table.apiKey)]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// Spaces (collections/folders for organizing memories)
|
|
23
|
+
export const spaces = sqliteTable(
|
|
24
|
+
'spaces',
|
|
25
|
+
{
|
|
26
|
+
id: text('id').primaryKey(),
|
|
27
|
+
userId: text('user_id')
|
|
28
|
+
.notNull()
|
|
29
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
30
|
+
name: text('name').notNull(),
|
|
31
|
+
description: text('description'),
|
|
32
|
+
isDefault: integer('is_default', { mode: 'boolean' }).notNull().default(false),
|
|
33
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
34
|
+
.notNull()
|
|
35
|
+
.default(sql`(unixepoch())`),
|
|
36
|
+
updatedAt: integer('updated_at', { mode: 'timestamp' })
|
|
37
|
+
.notNull()
|
|
38
|
+
.default(sql`(unixepoch())`),
|
|
39
|
+
},
|
|
40
|
+
(table) => [index('spaces_user_id_idx').on(table.userId)]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
// Content types enum values
|
|
44
|
+
export const contentTypes = ['note', 'url', 'pdf', 'image', 'tweet', 'document'] as const
|
|
45
|
+
export type ContentType = (typeof contentTypes)[number]
|
|
46
|
+
|
|
47
|
+
// Memories table (main content storage)
|
|
48
|
+
export const memories = sqliteTable(
|
|
49
|
+
'memories',
|
|
50
|
+
{
|
|
51
|
+
id: text('id').primaryKey(),
|
|
52
|
+
userId: text('user_id')
|
|
53
|
+
.notNull()
|
|
54
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
55
|
+
spaceId: text('space_id').references(() => spaces.id, { onDelete: 'set null' }),
|
|
56
|
+
contentType: text('content_type', { enum: contentTypes }).notNull(),
|
|
57
|
+
title: text('title'),
|
|
58
|
+
content: text('content').notNull(),
|
|
59
|
+
rawContent: text('raw_content'), // Original content before processing
|
|
60
|
+
sourceUrl: text('source_url'),
|
|
61
|
+
metadata: text('metadata', { mode: 'json' }).$type<Record<string, unknown>>(),
|
|
62
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
63
|
+
.notNull()
|
|
64
|
+
.default(sql`(unixepoch())`),
|
|
65
|
+
updatedAt: integer('updated_at', { mode: 'timestamp' })
|
|
66
|
+
.notNull()
|
|
67
|
+
.default(sql`(unixepoch())`),
|
|
68
|
+
},
|
|
69
|
+
(table) => [
|
|
70
|
+
index('memories_user_id_idx').on(table.userId),
|
|
71
|
+
index('memories_space_id_idx').on(table.spaceId),
|
|
72
|
+
index('memories_content_type_idx').on(table.contentType),
|
|
73
|
+
index('memories_created_at_idx').on(table.createdAt),
|
|
74
|
+
]
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
// Chunks table (for RAG - split content into searchable chunks)
|
|
78
|
+
export const chunks = sqliteTable(
|
|
79
|
+
'chunks',
|
|
80
|
+
{
|
|
81
|
+
id: text('id').primaryKey(),
|
|
82
|
+
memoryId: text('memory_id')
|
|
83
|
+
.notNull()
|
|
84
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
85
|
+
content: text('content').notNull(),
|
|
86
|
+
chunkIndex: integer('chunk_index').notNull(),
|
|
87
|
+
startOffset: integer('start_offset'),
|
|
88
|
+
endOffset: integer('end_offset'),
|
|
89
|
+
tokenCount: integer('token_count'),
|
|
90
|
+
metadata: text('metadata', { mode: 'json' }).$type<Record<string, unknown>>(),
|
|
91
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
92
|
+
.notNull()
|
|
93
|
+
.default(sql`(unixepoch())`),
|
|
94
|
+
},
|
|
95
|
+
(table) => [index('chunks_memory_id_idx').on(table.memoryId), index('chunks_chunk_index_idx').on(table.chunkIndex)]
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
// Embeddings table (vector storage for semantic search)
|
|
99
|
+
export const embeddings = sqliteTable(
|
|
100
|
+
'embeddings',
|
|
101
|
+
{
|
|
102
|
+
id: text('id').primaryKey(),
|
|
103
|
+
chunkId: text('chunk_id')
|
|
104
|
+
.notNull()
|
|
105
|
+
.references(() => chunks.id, { onDelete: 'cascade' }),
|
|
106
|
+
embedding: blob('embedding', { mode: 'buffer' }).notNull(), // Stored as binary for efficiency
|
|
107
|
+
model: text('model').notNull(),
|
|
108
|
+
dimensions: integer('dimensions').notNull(),
|
|
109
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
110
|
+
.notNull()
|
|
111
|
+
.default(sql`(unixepoch())`),
|
|
112
|
+
},
|
|
113
|
+
(table) => [uniqueIndex('embeddings_chunk_id_idx').on(table.chunkId)]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
// Tags table
|
|
117
|
+
export const tags = sqliteTable(
|
|
118
|
+
'tags',
|
|
119
|
+
{
|
|
120
|
+
id: text('id').primaryKey(),
|
|
121
|
+
userId: text('user_id')
|
|
122
|
+
.notNull()
|
|
123
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
124
|
+
name: text('name').notNull(),
|
|
125
|
+
color: text('color'),
|
|
126
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
127
|
+
.notNull()
|
|
128
|
+
.default(sql`(unixepoch())`),
|
|
129
|
+
},
|
|
130
|
+
(table) => [
|
|
131
|
+
index('tags_user_id_idx').on(table.userId),
|
|
132
|
+
uniqueIndex('tags_user_name_idx').on(table.userId, table.name),
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
// Memory-Tags junction table
|
|
137
|
+
export const memoryTags = sqliteTable(
|
|
138
|
+
'memory_tags',
|
|
139
|
+
{
|
|
140
|
+
memoryId: text('memory_id')
|
|
141
|
+
.notNull()
|
|
142
|
+
.references(() => memories.id, { onDelete: 'cascade' }),
|
|
143
|
+
tagId: text('tag_id')
|
|
144
|
+
.notNull()
|
|
145
|
+
.references(() => tags.id, { onDelete: 'cascade' }),
|
|
146
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
147
|
+
.notNull()
|
|
148
|
+
.default(sql`(unixepoch())`),
|
|
149
|
+
},
|
|
150
|
+
(table) => [index('memory_tags_memory_id_idx').on(table.memoryId), index('memory_tags_tag_id_idx').on(table.tagId)]
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// Search history for analytics and suggestions
|
|
154
|
+
export const searchHistory = sqliteTable(
|
|
155
|
+
'search_history',
|
|
156
|
+
{
|
|
157
|
+
id: text('id').primaryKey(),
|
|
158
|
+
userId: text('user_id')
|
|
159
|
+
.notNull()
|
|
160
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
161
|
+
query: text('query').notNull(),
|
|
162
|
+
resultCount: integer('result_count').notNull().default(0),
|
|
163
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
164
|
+
.notNull()
|
|
165
|
+
.default(sql`(unixepoch())`),
|
|
166
|
+
},
|
|
167
|
+
(table) => [
|
|
168
|
+
index('search_history_user_id_idx').on(table.userId),
|
|
169
|
+
index('search_history_created_at_idx').on(table.createdAt),
|
|
170
|
+
]
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
// API usage tracking
|
|
174
|
+
export const apiUsage = sqliteTable(
|
|
175
|
+
'api_usage',
|
|
176
|
+
{
|
|
177
|
+
id: text('id').primaryKey(),
|
|
178
|
+
userId: text('user_id')
|
|
179
|
+
.notNull()
|
|
180
|
+
.references(() => users.id, { onDelete: 'cascade' }),
|
|
181
|
+
endpoint: text('endpoint').notNull(),
|
|
182
|
+
method: text('method').notNull(),
|
|
183
|
+
statusCode: integer('status_code').notNull(),
|
|
184
|
+
responseTimeMs: integer('response_time_ms'),
|
|
185
|
+
tokensUsed: integer('tokens_used'),
|
|
186
|
+
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
187
|
+
.notNull()
|
|
188
|
+
.default(sql`(unixepoch())`),
|
|
189
|
+
},
|
|
190
|
+
(table) => [
|
|
191
|
+
index('api_usage_user_id_idx').on(table.userId),
|
|
192
|
+
index('api_usage_endpoint_idx').on(table.endpoint),
|
|
193
|
+
index('api_usage_created_at_idx').on(table.createdAt),
|
|
194
|
+
]
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
// Type exports for use in application
|
|
198
|
+
export type User = typeof users.$inferSelect
|
|
199
|
+
export type NewUser = typeof users.$inferInsert
|
|
200
|
+
|
|
201
|
+
export type Space = typeof spaces.$inferSelect
|
|
202
|
+
export type NewSpace = typeof spaces.$inferInsert
|
|
203
|
+
|
|
204
|
+
export type Memory = typeof memories.$inferSelect
|
|
205
|
+
export type NewMemory = typeof memories.$inferInsert
|
|
206
|
+
|
|
207
|
+
export type Chunk = typeof chunks.$inferSelect
|
|
208
|
+
export type NewChunk = typeof chunks.$inferInsert
|
|
209
|
+
|
|
210
|
+
export type Embedding = typeof embeddings.$inferSelect
|
|
211
|
+
export type NewEmbedding = typeof embeddings.$inferInsert
|
|
212
|
+
|
|
213
|
+
export type Tag = typeof tags.$inferSelect
|
|
214
|
+
export type NewTag = typeof tags.$inferInsert
|
|
215
|
+
|
|
216
|
+
export type MemoryTag = typeof memoryTags.$inferSelect
|
|
217
|
+
export type NewMemoryTag = typeof memoryTags.$inferInsert
|
|
218
|
+
|
|
219
|
+
export type SearchHistory = typeof searchHistory.$inferSelect
|
|
220
|
+
export type NewSearchHistory = typeof searchHistory.$inferInsert
|
|
221
|
+
|
|
222
|
+
export type ApiUsage = typeof apiUsage.$inferSelect
|
|
223
|
+
export type NewApiUsage = typeof apiUsage.$inferInsert
|