@pga-ai/adapters-storage-postgres 0.8.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/README.md +150 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +501 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
- package/sql/schema.sql +251 -0
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @pga-ai/adapters-storage-postgres
|
|
2
|
+
|
|
3
|
+
> PostgreSQL storage adapter for GSEP (Genomic Self-Evolving Prompts)
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @pga-ai/core @pga-ai/adapters-storage-postgres
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { PGA } from '@pga-ai/core';
|
|
15
|
+
import { ClaudeAdapter } from '@pga-ai/adapters-llm-anthropic';
|
|
16
|
+
import { PostgresAdapter } from '@pga-ai/adapters-storage-postgres';
|
|
17
|
+
|
|
18
|
+
const pga = new PGA({
|
|
19
|
+
llm: new ClaudeAdapter({
|
|
20
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
21
|
+
}),
|
|
22
|
+
storage: new PostgresAdapter({
|
|
23
|
+
connectionString: process.env.DATABASE_URL,
|
|
24
|
+
autoInitialize: true, // Creates tables automatically
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await pga.initialize();
|
|
29
|
+
|
|
30
|
+
const genome = await pga.createGenome({ name: 'my-assistant' });
|
|
31
|
+
const response = await genome.chat('Hello!', { userId: 'user123' });
|
|
32
|
+
|
|
33
|
+
console.log(response);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
### `PostgresAdapter(config)`
|
|
39
|
+
|
|
40
|
+
| Option | Type | Default | Description |
|
|
41
|
+
|--------|------|---------|-------------|
|
|
42
|
+
| `connectionString` | `string` | required | PostgreSQL connection string |
|
|
43
|
+
| `maxConnections` | `number` | `20` | Maximum pool size |
|
|
44
|
+
| `autoInitialize` | `boolean` | `true` | Auto-create database schema |
|
|
45
|
+
|
|
46
|
+
### Connection String Format
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
postgresql://user:password@host:port/database
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Example:**
|
|
53
|
+
```
|
|
54
|
+
postgresql://postgres:secret@localhost:5432/pga
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Database Schema
|
|
58
|
+
|
|
59
|
+
The adapter automatically creates the following tables:
|
|
60
|
+
|
|
61
|
+
- `pga_genomes` - Genome metadata
|
|
62
|
+
- `pga_alleles` - Gene alleles (Layer 0, 1, 2)
|
|
63
|
+
- `pga_user_dna` - User cognitive profiles
|
|
64
|
+
- `pga_interactions` - Interaction logs
|
|
65
|
+
- `pga_mutations` - Mutation history
|
|
66
|
+
- `pga_feedback` - User feedback signals
|
|
67
|
+
- `pga_analytics` - Pre-aggregated stats
|
|
68
|
+
|
|
69
|
+
See [`sql/schema.sql`](./sql/schema.sql) for full schema.
|
|
70
|
+
|
|
71
|
+
## Manual Schema Setup
|
|
72
|
+
|
|
73
|
+
If you prefer to manage migrations yourself:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const adapter = new PostgresAdapter({
|
|
77
|
+
connectionString: process.env.DATABASE_URL,
|
|
78
|
+
autoInitialize: false, // Don't auto-create tables
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Run your own migrations
|
|
82
|
+
await runMigrations();
|
|
83
|
+
|
|
84
|
+
// Then initialize GSEP (will skip schema creation)
|
|
85
|
+
await pga.initialize();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Performance
|
|
89
|
+
|
|
90
|
+
### Connection Pooling
|
|
91
|
+
|
|
92
|
+
The adapter uses `pg` connection pooling by default:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const adapter = new PostgresAdapter({
|
|
96
|
+
connectionString: process.env.DATABASE_URL,
|
|
97
|
+
maxConnections: 50, // Increase for high load
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Indexes
|
|
102
|
+
|
|
103
|
+
All critical queries are indexed:
|
|
104
|
+
- Genome lookups: `pga_genomes(id)`
|
|
105
|
+
- Allele selection: `pga_alleles(genome_id, layer, gene, status)`
|
|
106
|
+
- User DNA: `pga_user_dna(user_id, genome_id)`
|
|
107
|
+
- Analytics queries: All have composite indexes
|
|
108
|
+
|
|
109
|
+
## Production Checklist
|
|
110
|
+
|
|
111
|
+
✅ Use connection pooling (`maxConnections: 20+`)
|
|
112
|
+
✅ Enable SSL for remote databases
|
|
113
|
+
✅ Set up database backups
|
|
114
|
+
✅ Monitor connection pool usage
|
|
115
|
+
✅ Use read replicas for analytics queries
|
|
116
|
+
✅ Consider partitioning `pga_interactions` table for high volume
|
|
117
|
+
|
|
118
|
+
## Troubleshooting
|
|
119
|
+
|
|
120
|
+
### "relation does not exist" error
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// Ensure autoInitialize is true
|
|
124
|
+
const adapter = new PostgresAdapter({
|
|
125
|
+
connectionString: process.env.DATABASE_URL,
|
|
126
|
+
autoInitialize: true, // ← This creates tables
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await pga.initialize();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Connection timeout
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Increase max connections
|
|
136
|
+
const adapter = new PostgresAdapter({
|
|
137
|
+
connectionString: process.env.DATABASE_URL,
|
|
138
|
+
maxConnections: 50, // Default is 20
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### SSL connection required
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
postgresql://user:pass@host:5432/db?sslmode=require
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT © Luis Alfredo Velasquez Duran
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { StorageAdapter, Genome, UserDNA, Interaction, MutationLog, SemanticFact, GeneRegistryEntry } from '@pga-ai/core';
|
|
2
|
+
export interface PostgresAdapterConfig {
|
|
3
|
+
connectionString: string;
|
|
4
|
+
maxConnections?: number;
|
|
5
|
+
autoInitialize?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class PostgresAdapter implements StorageAdapter {
|
|
8
|
+
private pool;
|
|
9
|
+
private config;
|
|
10
|
+
constructor(config: PostgresAdapterConfig);
|
|
11
|
+
initialize(): Promise<void>;
|
|
12
|
+
saveGenome(genome: Genome): Promise<void>;
|
|
13
|
+
loadGenome(genomeId: string): Promise<Genome | null>;
|
|
14
|
+
listGenomes(): Promise<Genome[]>;
|
|
15
|
+
deleteGenome(genomeId: string): Promise<void>;
|
|
16
|
+
saveDNA(userId: string, genomeId: string, dna: UserDNA): Promise<void>;
|
|
17
|
+
loadDNA(userId: string, genomeId: string): Promise<UserDNA | null>;
|
|
18
|
+
recordInteraction(interaction: Interaction): Promise<void>;
|
|
19
|
+
logMutation(mutation: MutationLog): Promise<void>;
|
|
20
|
+
getMutationHistory(genomeId: string, limit?: number): Promise<MutationLog[]>;
|
|
21
|
+
getGeneMutationHistory(genomeId: string, gene: string, limit?: number): Promise<MutationLog[]>;
|
|
22
|
+
getRecentInteractions(genomeId: string, userId: string, limit?: number): Promise<unknown[]>;
|
|
23
|
+
recordFeedback(feedback: {
|
|
24
|
+
genomeId: string;
|
|
25
|
+
userId: string;
|
|
26
|
+
gene: string;
|
|
27
|
+
sentiment: 'positive' | 'negative' | 'neutral';
|
|
28
|
+
timestamp: Date;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
getAnalytics(genomeId: string): Promise<{
|
|
31
|
+
totalMutations: number;
|
|
32
|
+
totalInteractions: number;
|
|
33
|
+
avgFitnessImprovement: number;
|
|
34
|
+
userSatisfaction: number;
|
|
35
|
+
topGenes: Array<{
|
|
36
|
+
gene: string;
|
|
37
|
+
fitness: number;
|
|
38
|
+
}>;
|
|
39
|
+
}>;
|
|
40
|
+
saveFact(fact: SemanticFact, userId: string, genomeId: string): Promise<void>;
|
|
41
|
+
getFacts(userId: string, genomeId: string, includeExpired?: boolean): Promise<SemanticFact[]>;
|
|
42
|
+
getFact(factId: string): Promise<SemanticFact | null>;
|
|
43
|
+
updateFact(factId: string, updates: Partial<SemanticFact>): Promise<void>;
|
|
44
|
+
deleteFact(factId: string): Promise<void>;
|
|
45
|
+
deleteUserFacts(userId: string, genomeId: string): Promise<void>;
|
|
46
|
+
cleanExpiredFacts(userId: string, genomeId: string): Promise<number>;
|
|
47
|
+
saveToGeneRegistry(entry: {
|
|
48
|
+
id: string;
|
|
49
|
+
familyId: string;
|
|
50
|
+
gene: string;
|
|
51
|
+
variant: string;
|
|
52
|
+
content: string;
|
|
53
|
+
layer: 0 | 1 | 2;
|
|
54
|
+
fitness: number;
|
|
55
|
+
sampleCount: number;
|
|
56
|
+
successRate: number;
|
|
57
|
+
metadata: Record<string, unknown>;
|
|
58
|
+
createdAt: Date;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
queryGeneRegistry(familyId: string, gene?: string, minFitness?: number): Promise<GeneRegistryEntry[]>;
|
|
61
|
+
getBestRegistryGene(familyId: string, gene: string): Promise<GeneRegistryEntry | null>;
|
|
62
|
+
private mapRowToGeneRegistryEntry;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
export class PostgresAdapter {
|
|
8
|
+
pool;
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = {
|
|
12
|
+
connectionString: config.connectionString,
|
|
13
|
+
maxConnections: config.maxConnections ?? 20,
|
|
14
|
+
autoInitialize: config.autoInitialize ?? true,
|
|
15
|
+
};
|
|
16
|
+
const poolConfig = {
|
|
17
|
+
connectionString: this.config.connectionString,
|
|
18
|
+
max: this.config.maxConnections,
|
|
19
|
+
};
|
|
20
|
+
this.pool = new Pool(poolConfig);
|
|
21
|
+
}
|
|
22
|
+
async initialize() {
|
|
23
|
+
if (!this.config.autoInitialize) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const schemaPath = join(__dirname, '../sql/schema.sql');
|
|
28
|
+
const schema = readFileSync(schemaPath, 'utf-8');
|
|
29
|
+
await this.pool.query(schema);
|
|
30
|
+
console.log('[GSEP] PostgreSQL schema initialized');
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new Error(`Failed to initialize PostgreSQL schema: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async saveGenome(genome) {
|
|
37
|
+
const client = await this.pool.connect();
|
|
38
|
+
try {
|
|
39
|
+
await client.query('BEGIN');
|
|
40
|
+
await client.query(`INSERT INTO pga_genomes (id, name, config, created_at, updated_at)
|
|
41
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
42
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
43
|
+
name = $2,
|
|
44
|
+
config = $3,
|
|
45
|
+
updated_at = $5`, [
|
|
46
|
+
genome.id,
|
|
47
|
+
genome.name,
|
|
48
|
+
JSON.stringify(genome.config),
|
|
49
|
+
genome.createdAt,
|
|
50
|
+
genome.updatedAt,
|
|
51
|
+
]);
|
|
52
|
+
await client.query('DELETE FROM pga_alleles WHERE genome_id = $1', [genome.id]);
|
|
53
|
+
for (const layer of [0, 1, 2]) {
|
|
54
|
+
const layerKey = `layer${layer}`;
|
|
55
|
+
const alleles = genome.layers[layerKey];
|
|
56
|
+
for (const allele of alleles) {
|
|
57
|
+
await client.query(`INSERT INTO pga_alleles (
|
|
58
|
+
genome_id, layer, gene, variant, content, fitness,
|
|
59
|
+
sample_count, parent_variant, generation, status,
|
|
60
|
+
sandbox_tested, sandbox_score, recent_scores,
|
|
61
|
+
created_at, updated_at
|
|
62
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)`, [
|
|
63
|
+
genome.id,
|
|
64
|
+
layer,
|
|
65
|
+
allele.gene,
|
|
66
|
+
allele.variant,
|
|
67
|
+
allele.content,
|
|
68
|
+
allele.fitness,
|
|
69
|
+
allele.sampleCount || 0,
|
|
70
|
+
allele.parentVariant,
|
|
71
|
+
allele.generation || 0,
|
|
72
|
+
allele.status,
|
|
73
|
+
allele.sandboxTested || false,
|
|
74
|
+
allele.sandboxScore,
|
|
75
|
+
JSON.stringify(allele.recentScores || []),
|
|
76
|
+
allele.createdAt,
|
|
77
|
+
new Date(),
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
await client.query('COMMIT');
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
await client.query('ROLLBACK');
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
client.release();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async loadGenome(genomeId) {
|
|
92
|
+
const result = await this.pool.query('SELECT * FROM pga_genomes WHERE id = $1', [genomeId]);
|
|
93
|
+
if (result.rows.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const row = result.rows[0];
|
|
97
|
+
const allelesResult = await this.pool.query('SELECT * FROM pga_alleles WHERE genome_id = $1 ORDER BY layer, gene, fitness DESC', [genomeId]);
|
|
98
|
+
const layer0 = [];
|
|
99
|
+
const layer1 = [];
|
|
100
|
+
const layer2 = [];
|
|
101
|
+
for (const alleleRow of allelesResult.rows) {
|
|
102
|
+
const allele = {
|
|
103
|
+
gene: alleleRow.gene,
|
|
104
|
+
variant: alleleRow.variant,
|
|
105
|
+
content: alleleRow.content,
|
|
106
|
+
fitness: parseFloat(alleleRow.fitness),
|
|
107
|
+
sampleCount: alleleRow.sample_count,
|
|
108
|
+
parentVariant: alleleRow.parent_variant,
|
|
109
|
+
generation: alleleRow.generation,
|
|
110
|
+
status: alleleRow.status,
|
|
111
|
+
sandboxTested: alleleRow.sandbox_tested,
|
|
112
|
+
sandboxScore: alleleRow.sandbox_score ? parseFloat(alleleRow.sandbox_score) : undefined,
|
|
113
|
+
recentScores: alleleRow.recent_scores || [],
|
|
114
|
+
createdAt: alleleRow.created_at,
|
|
115
|
+
};
|
|
116
|
+
if (alleleRow.layer === 0)
|
|
117
|
+
layer0.push(allele);
|
|
118
|
+
else if (alleleRow.layer === 1)
|
|
119
|
+
layer1.push(allele);
|
|
120
|
+
else if (alleleRow.layer === 2)
|
|
121
|
+
layer2.push(allele);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
id: row.id,
|
|
125
|
+
name: row.name,
|
|
126
|
+
config: row.config,
|
|
127
|
+
layers: {
|
|
128
|
+
layer0,
|
|
129
|
+
layer1,
|
|
130
|
+
layer2,
|
|
131
|
+
},
|
|
132
|
+
createdAt: row.created_at,
|
|
133
|
+
updatedAt: row.updated_at,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async listGenomes() {
|
|
137
|
+
const result = await this.pool.query('SELECT id FROM pga_genomes ORDER BY created_at DESC');
|
|
138
|
+
const genomes = [];
|
|
139
|
+
for (const row of result.rows) {
|
|
140
|
+
const genome = await this.loadGenome(row.id);
|
|
141
|
+
if (genome) {
|
|
142
|
+
genomes.push(genome);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return genomes;
|
|
146
|
+
}
|
|
147
|
+
async deleteGenome(genomeId) {
|
|
148
|
+
await this.pool.query('DELETE FROM pga_genomes WHERE id = $1', [genomeId]);
|
|
149
|
+
}
|
|
150
|
+
async saveDNA(userId, genomeId, dna) {
|
|
151
|
+
await this.pool.query(`INSERT INTO pga_user_dna (
|
|
152
|
+
user_id, genome_id, traits, confidence, generation, last_evolved, updated_at
|
|
153
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
154
|
+
ON CONFLICT (user_id, genome_id) DO UPDATE SET
|
|
155
|
+
traits = $3,
|
|
156
|
+
confidence = $4,
|
|
157
|
+
generation = $5,
|
|
158
|
+
last_evolved = $6,
|
|
159
|
+
updated_at = $7`, [
|
|
160
|
+
userId,
|
|
161
|
+
genomeId,
|
|
162
|
+
JSON.stringify(dna.traits),
|
|
163
|
+
JSON.stringify(dna.confidence),
|
|
164
|
+
dna.generation,
|
|
165
|
+
dna.lastEvolved,
|
|
166
|
+
new Date(),
|
|
167
|
+
]);
|
|
168
|
+
}
|
|
169
|
+
async loadDNA(userId, genomeId) {
|
|
170
|
+
const result = await this.pool.query('SELECT * FROM pga_user_dna WHERE user_id = $1 AND genome_id = $2', [userId, genomeId]);
|
|
171
|
+
if (result.rows.length === 0) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const row = result.rows[0];
|
|
175
|
+
return {
|
|
176
|
+
userId: row.user_id,
|
|
177
|
+
genomeId: row.genome_id,
|
|
178
|
+
traits: row.traits,
|
|
179
|
+
confidence: row.confidence,
|
|
180
|
+
generation: row.generation,
|
|
181
|
+
lastEvolved: row.last_evolved,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
async recordInteraction(interaction) {
|
|
185
|
+
await this.pool.query(`INSERT INTO pga_interactions (
|
|
186
|
+
genome_id, user_id, user_message, assistant_response,
|
|
187
|
+
tool_calls, score, task_type, timestamp
|
|
188
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
|
|
189
|
+
interaction.genomeId,
|
|
190
|
+
interaction.userId,
|
|
191
|
+
interaction.userMessage,
|
|
192
|
+
interaction.assistantResponse,
|
|
193
|
+
JSON.stringify(interaction.toolCalls),
|
|
194
|
+
interaction.score,
|
|
195
|
+
interaction.taskType,
|
|
196
|
+
interaction.timestamp,
|
|
197
|
+
]);
|
|
198
|
+
}
|
|
199
|
+
async logMutation(mutation) {
|
|
200
|
+
await this.pool.query(`INSERT INTO pga_mutations (
|
|
201
|
+
genome_id, layer, gene, variant, mutation_type,
|
|
202
|
+
parent_variant, trigger_reason, fitness_delta,
|
|
203
|
+
deployed, details, timestamp
|
|
204
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`, [
|
|
205
|
+
mutation.genomeId,
|
|
206
|
+
mutation.layer,
|
|
207
|
+
mutation.gene,
|
|
208
|
+
mutation.variant,
|
|
209
|
+
mutation.mutationType,
|
|
210
|
+
mutation.parentVariant,
|
|
211
|
+
mutation.triggerReason,
|
|
212
|
+
mutation.fitnessDelta,
|
|
213
|
+
mutation.deployed,
|
|
214
|
+
JSON.stringify(mutation.details || {}),
|
|
215
|
+
mutation.timestamp,
|
|
216
|
+
]);
|
|
217
|
+
}
|
|
218
|
+
async getMutationHistory(genomeId, limit = 100) {
|
|
219
|
+
const result = await this.pool.query(`SELECT * FROM pga_mutations
|
|
220
|
+
WHERE genome_id = $1
|
|
221
|
+
ORDER BY timestamp DESC
|
|
222
|
+
LIMIT $2`, [genomeId, limit]);
|
|
223
|
+
return result.rows.map((row) => ({
|
|
224
|
+
genomeId: row.genome_id,
|
|
225
|
+
layer: row.layer,
|
|
226
|
+
gene: row.gene,
|
|
227
|
+
variant: row.variant,
|
|
228
|
+
mutationType: row.mutation_type,
|
|
229
|
+
parentVariant: row.parent_variant,
|
|
230
|
+
triggerReason: row.trigger_reason,
|
|
231
|
+
fitnessDelta: parseFloat(row.fitness_delta),
|
|
232
|
+
deployed: row.deployed,
|
|
233
|
+
details: row.details,
|
|
234
|
+
createdAt: row.timestamp,
|
|
235
|
+
timestamp: row.timestamp,
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
async getGeneMutationHistory(genomeId, gene, limit = 50) {
|
|
239
|
+
const result = await this.pool.query(`SELECT * FROM pga_mutations
|
|
240
|
+
WHERE genome_id = $1 AND gene = $2
|
|
241
|
+
ORDER BY timestamp DESC
|
|
242
|
+
LIMIT $3`, [genomeId, gene, limit]);
|
|
243
|
+
return result.rows.map((row) => ({
|
|
244
|
+
genomeId: row.genome_id,
|
|
245
|
+
layer: row.layer,
|
|
246
|
+
gene: row.gene,
|
|
247
|
+
variant: row.variant,
|
|
248
|
+
mutationType: row.mutation_type,
|
|
249
|
+
parentVariant: row.parent_variant,
|
|
250
|
+
triggerReason: row.trigger_reason,
|
|
251
|
+
fitnessDelta: parseFloat(row.fitness_delta),
|
|
252
|
+
deployed: row.deployed,
|
|
253
|
+
details: row.details,
|
|
254
|
+
createdAt: row.timestamp,
|
|
255
|
+
timestamp: row.timestamp,
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
async getRecentInteractions(genomeId, userId, limit = 20) {
|
|
259
|
+
const result = await this.pool.query(`SELECT * FROM pga_interactions
|
|
260
|
+
WHERE genome_id = $1 AND user_id = $2
|
|
261
|
+
ORDER BY timestamp DESC
|
|
262
|
+
LIMIT $3`, [genomeId, userId, limit]);
|
|
263
|
+
return result.rows.map((row) => ({
|
|
264
|
+
genomeId: row.genome_id,
|
|
265
|
+
userId: row.user_id,
|
|
266
|
+
userMessage: row.user_message,
|
|
267
|
+
assistantResponse: row.assistant_response,
|
|
268
|
+
toolCalls: row.tool_calls,
|
|
269
|
+
score: row.score ? parseFloat(row.score) : undefined,
|
|
270
|
+
timestamp: row.timestamp,
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
async recordFeedback(feedback) {
|
|
274
|
+
await this.pool.query(`INSERT INTO pga_feedback (
|
|
275
|
+
genome_id, user_id, gene, sentiment, timestamp
|
|
276
|
+
) VALUES ($1, $2, $3, $4, $5)`, [
|
|
277
|
+
feedback.genomeId,
|
|
278
|
+
feedback.userId,
|
|
279
|
+
feedback.gene,
|
|
280
|
+
feedback.sentiment,
|
|
281
|
+
feedback.timestamp,
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
async getAnalytics(genomeId) {
|
|
285
|
+
const [interactionsResult, mutationsResult, feedbackResult, topGenesResult,] = await Promise.all([
|
|
286
|
+
this.pool.query('SELECT COUNT(*) as count FROM pga_interactions WHERE genome_id = $1', [genomeId]),
|
|
287
|
+
this.pool.query('SELECT COUNT(*) as count, AVG(fitness_improvement) as avg_improvement FROM pga_mutations WHERE genome_id = $1 AND deployed = true', [genomeId]),
|
|
288
|
+
this.pool.query(`SELECT
|
|
289
|
+
COUNT(*) FILTER (WHERE sentiment = 'positive') as positive,
|
|
290
|
+
COUNT(*) as total
|
|
291
|
+
FROM pga_feedback WHERE genome_id = $1`, [genomeId]),
|
|
292
|
+
this.pool.query(`SELECT gene, AVG(sandbox_score) as fitness
|
|
293
|
+
FROM pga_mutations
|
|
294
|
+
WHERE genome_id = $1 AND deployed = true
|
|
295
|
+
GROUP BY gene
|
|
296
|
+
ORDER BY fitness DESC
|
|
297
|
+
LIMIT 5`, [genomeId]),
|
|
298
|
+
]);
|
|
299
|
+
const totalFeedback = parseInt(feedbackResult.rows[0]?.total || '0');
|
|
300
|
+
const positiveFeedback = parseInt(feedbackResult.rows[0]?.positive || '0');
|
|
301
|
+
return {
|
|
302
|
+
totalMutations: parseInt(mutationsResult.rows[0]?.count || '0'),
|
|
303
|
+
totalInteractions: parseInt(interactionsResult.rows[0]?.count || '0'),
|
|
304
|
+
avgFitnessImprovement: parseFloat(mutationsResult.rows[0]?.avg_improvement || '0'),
|
|
305
|
+
userSatisfaction: totalFeedback > 0 ? positiveFeedback / totalFeedback : 0,
|
|
306
|
+
topGenes: topGenesResult.rows.map((row) => ({
|
|
307
|
+
gene: row.gene,
|
|
308
|
+
fitness: parseFloat(row.fitness || '0'),
|
|
309
|
+
})),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async saveFact(fact, userId, genomeId) {
|
|
313
|
+
await this.pool.query(`INSERT INTO semantic_facts (
|
|
314
|
+
id, user_id, genome_id, fact, category, confidence,
|
|
315
|
+
source_turn, source_interaction_id, extracted_at,
|
|
316
|
+
expiry, verified
|
|
317
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
318
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
319
|
+
fact = $4,
|
|
320
|
+
category = $5,
|
|
321
|
+
confidence = $6,
|
|
322
|
+
verified = $11,
|
|
323
|
+
expiry = $10,
|
|
324
|
+
updated_at = NOW()`, [
|
|
325
|
+
fact.id,
|
|
326
|
+
userId,
|
|
327
|
+
genomeId,
|
|
328
|
+
fact.fact,
|
|
329
|
+
fact.category,
|
|
330
|
+
fact.confidence,
|
|
331
|
+
fact.sourceTurn,
|
|
332
|
+
fact.sourceInteractionId,
|
|
333
|
+
fact.extractedAt,
|
|
334
|
+
fact.expiry,
|
|
335
|
+
fact.verified,
|
|
336
|
+
]);
|
|
337
|
+
}
|
|
338
|
+
async getFacts(userId, genomeId, includeExpired = false) {
|
|
339
|
+
const query = includeExpired
|
|
340
|
+
? `SELECT * FROM semantic_facts
|
|
341
|
+
WHERE user_id = $1 AND genome_id = $2
|
|
342
|
+
ORDER BY verified DESC, confidence DESC, extracted_at DESC`
|
|
343
|
+
: `SELECT * FROM semantic_facts
|
|
344
|
+
WHERE user_id = $1 AND genome_id = $2
|
|
345
|
+
AND (expiry IS NULL OR expiry > NOW())
|
|
346
|
+
ORDER BY verified DESC, confidence DESC, extracted_at DESC`;
|
|
347
|
+
const result = await this.pool.query(query, [userId, genomeId]);
|
|
348
|
+
return result.rows.map((row) => ({
|
|
349
|
+
id: row.id,
|
|
350
|
+
fact: row.fact,
|
|
351
|
+
category: row.category,
|
|
352
|
+
confidence: parseFloat(row.confidence),
|
|
353
|
+
sourceTurn: row.source_turn,
|
|
354
|
+
sourceInteractionId: row.source_interaction_id,
|
|
355
|
+
extractedAt: row.extracted_at,
|
|
356
|
+
expiry: row.expiry,
|
|
357
|
+
verified: row.verified,
|
|
358
|
+
createdAt: row.created_at,
|
|
359
|
+
updatedAt: row.updated_at,
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
async getFact(factId) {
|
|
363
|
+
const result = await this.pool.query('SELECT * FROM semantic_facts WHERE id = $1', [factId]);
|
|
364
|
+
if (result.rows.length === 0) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
const row = result.rows[0];
|
|
368
|
+
return {
|
|
369
|
+
id: row.id,
|
|
370
|
+
fact: row.fact,
|
|
371
|
+
category: row.category,
|
|
372
|
+
confidence: parseFloat(row.confidence),
|
|
373
|
+
sourceTurn: row.source_turn,
|
|
374
|
+
sourceInteractionId: row.source_interaction_id,
|
|
375
|
+
extractedAt: row.extracted_at,
|
|
376
|
+
expiry: row.expiry,
|
|
377
|
+
verified: row.verified,
|
|
378
|
+
createdAt: row.created_at,
|
|
379
|
+
updatedAt: row.updated_at,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
async updateFact(factId, updates) {
|
|
383
|
+
const setClauses = [];
|
|
384
|
+
const values = [];
|
|
385
|
+
let paramIndex = 1;
|
|
386
|
+
if (updates.fact !== undefined) {
|
|
387
|
+
setClauses.push(`fact = $${paramIndex++}`);
|
|
388
|
+
values.push(updates.fact);
|
|
389
|
+
}
|
|
390
|
+
if (updates.category !== undefined) {
|
|
391
|
+
setClauses.push(`category = $${paramIndex++}`);
|
|
392
|
+
values.push(updates.category);
|
|
393
|
+
}
|
|
394
|
+
if (updates.confidence !== undefined) {
|
|
395
|
+
setClauses.push(`confidence = $${paramIndex++}`);
|
|
396
|
+
values.push(updates.confidence);
|
|
397
|
+
}
|
|
398
|
+
if (updates.verified !== undefined) {
|
|
399
|
+
setClauses.push(`verified = $${paramIndex++}`);
|
|
400
|
+
values.push(updates.verified);
|
|
401
|
+
}
|
|
402
|
+
if (updates.expiry !== undefined) {
|
|
403
|
+
setClauses.push(`expiry = $${paramIndex++}`);
|
|
404
|
+
values.push(updates.expiry);
|
|
405
|
+
}
|
|
406
|
+
if (setClauses.length === 0) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
setClauses.push(`updated_at = NOW()`);
|
|
410
|
+
values.push(factId);
|
|
411
|
+
const query = `UPDATE semantic_facts SET ${setClauses.join(', ')} WHERE id = $${paramIndex}`;
|
|
412
|
+
await this.pool.query(query, values);
|
|
413
|
+
}
|
|
414
|
+
async deleteFact(factId) {
|
|
415
|
+
await this.pool.query('DELETE FROM semantic_facts WHERE id = $1', [factId]);
|
|
416
|
+
}
|
|
417
|
+
async deleteUserFacts(userId, genomeId) {
|
|
418
|
+
await this.pool.query('DELETE FROM semantic_facts WHERE user_id = $1 AND genome_id = $2', [userId, genomeId]);
|
|
419
|
+
}
|
|
420
|
+
async cleanExpiredFacts(userId, genomeId) {
|
|
421
|
+
const result = await this.pool.query(`DELETE FROM semantic_facts
|
|
422
|
+
WHERE user_id = $1 AND genome_id = $2
|
|
423
|
+
AND expiry IS NOT NULL AND expiry <= NOW()
|
|
424
|
+
RETURNING id`, [userId, genomeId]);
|
|
425
|
+
return result.rowCount || 0;
|
|
426
|
+
}
|
|
427
|
+
async saveToGeneRegistry(entry) {
|
|
428
|
+
await this.pool.query(`INSERT INTO pga_gene_registry (id, family_id, gene, variant, content, layer, fitness, sample_count, success_rate, metadata, created_at)
|
|
429
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
430
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
431
|
+
fitness = EXCLUDED.fitness,
|
|
432
|
+
sample_count = EXCLUDED.sample_count,
|
|
433
|
+
success_rate = EXCLUDED.success_rate,
|
|
434
|
+
metadata = EXCLUDED.metadata`, [
|
|
435
|
+
entry.id,
|
|
436
|
+
entry.familyId,
|
|
437
|
+
entry.gene,
|
|
438
|
+
entry.variant,
|
|
439
|
+
entry.content,
|
|
440
|
+
entry.layer,
|
|
441
|
+
entry.fitness,
|
|
442
|
+
entry.sampleCount,
|
|
443
|
+
entry.successRate,
|
|
444
|
+
JSON.stringify(entry.metadata),
|
|
445
|
+
entry.createdAt,
|
|
446
|
+
]);
|
|
447
|
+
}
|
|
448
|
+
async queryGeneRegistry(familyId, gene, minFitness) {
|
|
449
|
+
let query = 'SELECT * FROM pga_gene_registry WHERE family_id = $1';
|
|
450
|
+
const params = [familyId];
|
|
451
|
+
let paramIndex = 2;
|
|
452
|
+
if (gene) {
|
|
453
|
+
query += ` AND gene = $${paramIndex++}`;
|
|
454
|
+
params.push(gene);
|
|
455
|
+
}
|
|
456
|
+
if (minFitness !== undefined) {
|
|
457
|
+
query += ` AND fitness >= $${paramIndex++}`;
|
|
458
|
+
params.push(minFitness);
|
|
459
|
+
}
|
|
460
|
+
query += ' ORDER BY fitness DESC';
|
|
461
|
+
const result = await this.pool.query(query, params);
|
|
462
|
+
return result.rows.map((row) => this.mapRowToGeneRegistryEntry(row));
|
|
463
|
+
}
|
|
464
|
+
async getBestRegistryGene(familyId, gene) {
|
|
465
|
+
const result = await this.pool.query(`SELECT * FROM pga_gene_registry
|
|
466
|
+
WHERE family_id = $1 AND gene = $2
|
|
467
|
+
ORDER BY fitness DESC
|
|
468
|
+
LIMIT 1`, [familyId, gene]);
|
|
469
|
+
if (result.rows.length === 0)
|
|
470
|
+
return null;
|
|
471
|
+
return this.mapRowToGeneRegistryEntry(result.rows[0]);
|
|
472
|
+
}
|
|
473
|
+
mapRowToGeneRegistryEntry(row) {
|
|
474
|
+
const rawMetadata = typeof row.metadata === 'string'
|
|
475
|
+
? JSON.parse(row.metadata)
|
|
476
|
+
: row.metadata || {};
|
|
477
|
+
return {
|
|
478
|
+
id: row.id,
|
|
479
|
+
familyId: row.family_id,
|
|
480
|
+
gene: row.gene,
|
|
481
|
+
variant: row.variant,
|
|
482
|
+
content: row.content,
|
|
483
|
+
layer: row.layer,
|
|
484
|
+
fitness: parseFloat(row.fitness),
|
|
485
|
+
sampleCount: row.sample_count,
|
|
486
|
+
successRate: parseFloat(row.success_rate),
|
|
487
|
+
metadata: {
|
|
488
|
+
sourceGenomeId: rawMetadata.sourceGenomeId || '',
|
|
489
|
+
sourceVersion: rawMetadata.sourceVersion || 0,
|
|
490
|
+
publishedBy: rawMetadata.publishedBy || '',
|
|
491
|
+
description: rawMetadata.description,
|
|
492
|
+
tags: rawMetadata.tags,
|
|
493
|
+
},
|
|
494
|
+
createdAt: new Date(row.created_at),
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async close() {
|
|
498
|
+
await this.pool.end();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pga-ai/adapters-storage-postgres",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "PostgreSQL storage adapter for GSEP",
|
|
5
|
+
"author": "Luis Alfredo Velasquez Duran <contact@gsepcore.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://gsepcore.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/LuisvelMarketer/pga-platform",
|
|
11
|
+
"directory": "packages/adapters-storage/postgres"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/LuisvelMarketer/pga-platform/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"sql"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc --build",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"dev": "tsc --watch"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"pg": "^8.13.1",
|
|
36
|
+
"@pga-ai/core": "*"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/pg": "^8.11.10",
|
|
40
|
+
"typescript": "^5.6.0"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/sql/schema.sql
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
-- PGA PostgreSQL Schema
|
|
2
|
+
-- Created by Luis Alfredo Velasquez Duran (Germany, 2025)
|
|
3
|
+
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
-- GENOMES
|
|
6
|
+
-- ═══════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS pga_genomes (
|
|
9
|
+
id TEXT PRIMARY KEY,
|
|
10
|
+
name TEXT NOT NULL,
|
|
11
|
+
config JSONB NOT NULL DEFAULT '{}',
|
|
12
|
+
-- Living OS v1.0: Lineage tracking
|
|
13
|
+
family_id TEXT,
|
|
14
|
+
version INTEGER DEFAULT 1,
|
|
15
|
+
lineage JSONB DEFAULT '{}',
|
|
16
|
+
c0_hash TEXT,
|
|
17
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
18
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_genomes_name ON pga_genomes(name);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_genomes_family ON pga_genomes(family_id, version DESC);
|
|
23
|
+
|
|
24
|
+
-- ═══════════════════════════════════════════════════════════
|
|
25
|
+
-- LAYERS (Three-Layer Architecture)
|
|
26
|
+
-- ═══════════════════════════════════════════════════════════
|
|
27
|
+
|
|
28
|
+
CREATE TABLE IF NOT EXISTS pga_alleles (
|
|
29
|
+
id BIGSERIAL PRIMARY KEY,
|
|
30
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
31
|
+
layer INTEGER NOT NULL CHECK (layer IN (0, 1, 2)),
|
|
32
|
+
gene TEXT NOT NULL,
|
|
33
|
+
variant TEXT NOT NULL,
|
|
34
|
+
content TEXT NOT NULL,
|
|
35
|
+
fitness NUMERIC(5,4) DEFAULT 0.5000,
|
|
36
|
+
sample_count INTEGER DEFAULT 0,
|
|
37
|
+
parent_variant TEXT,
|
|
38
|
+
generation INTEGER DEFAULT 0,
|
|
39
|
+
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'retired')),
|
|
40
|
+
sandbox_tested BOOLEAN DEFAULT FALSE,
|
|
41
|
+
sandbox_score NUMERIC(5,4),
|
|
42
|
+
recent_scores JSONB DEFAULT '[]',
|
|
43
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
44
|
+
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
45
|
+
UNIQUE(genome_id, layer, gene, variant)
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_alleles_genome ON pga_alleles(genome_id);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_alleles_active ON pga_alleles(genome_id, layer, gene, status) WHERE status = 'active';
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_alleles_fitness ON pga_alleles(genome_id, layer, gene, fitness DESC);
|
|
51
|
+
|
|
52
|
+
-- ═══════════════════════════════════════════════════════════
|
|
53
|
+
-- USER DNA (Cognitive Profiles)
|
|
54
|
+
-- ═══════════════════════════════════════════════════════════
|
|
55
|
+
|
|
56
|
+
CREATE TABLE IF NOT EXISTS pga_user_dna (
|
|
57
|
+
user_id TEXT NOT NULL,
|
|
58
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
59
|
+
traits JSONB NOT NULL DEFAULT '{}',
|
|
60
|
+
confidence JSONB NOT NULL DEFAULT '{}',
|
|
61
|
+
generation INTEGER DEFAULT 0,
|
|
62
|
+
last_evolved TIMESTAMPTZ DEFAULT NOW(),
|
|
63
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
64
|
+
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
65
|
+
PRIMARY KEY (user_id, genome_id)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE INDEX IF NOT EXISTS idx_user_dna_genome ON pga_user_dna(genome_id);
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_user_dna_evolved ON pga_user_dna(genome_id, last_evolved DESC);
|
|
70
|
+
|
|
71
|
+
-- ═══════════════════════════════════════════════════════════
|
|
72
|
+
-- INTERACTIONS (Learning Data)
|
|
73
|
+
-- ═══════════════════════════════════════════════════════════
|
|
74
|
+
|
|
75
|
+
CREATE TABLE IF NOT EXISTS pga_interactions (
|
|
76
|
+
id BIGSERIAL PRIMARY KEY,
|
|
77
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
78
|
+
user_id TEXT NOT NULL,
|
|
79
|
+
user_message TEXT NOT NULL,
|
|
80
|
+
assistant_response TEXT NOT NULL,
|
|
81
|
+
tool_calls JSONB DEFAULT '[]',
|
|
82
|
+
score NUMERIC(5,4),
|
|
83
|
+
user_satisfied BOOLEAN,
|
|
84
|
+
task_type TEXT,
|
|
85
|
+
timestamp TIMESTAMPTZ DEFAULT NOW()
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_interactions_genome ON pga_interactions(genome_id, timestamp DESC);
|
|
89
|
+
CREATE INDEX IF NOT EXISTS idx_interactions_user ON pga_interactions(genome_id, user_id, timestamp DESC);
|
|
90
|
+
|
|
91
|
+
-- ═══════════════════════════════════════════════════════════
|
|
92
|
+
-- MUTATIONS (Evolution Log)
|
|
93
|
+
-- ═══════════════════════════════════════════════════════════
|
|
94
|
+
|
|
95
|
+
CREATE TABLE IF NOT EXISTS pga_mutations (
|
|
96
|
+
id BIGSERIAL PRIMARY KEY,
|
|
97
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
98
|
+
layer INTEGER NOT NULL,
|
|
99
|
+
gene TEXT NOT NULL,
|
|
100
|
+
variant TEXT NOT NULL,
|
|
101
|
+
mutation_type TEXT NOT NULL,
|
|
102
|
+
parent_variant TEXT,
|
|
103
|
+
trigger_reason TEXT,
|
|
104
|
+
fitness_delta NUMERIC(5,4),
|
|
105
|
+
deployed BOOLEAN DEFAULT FALSE,
|
|
106
|
+
details JSONB DEFAULT '{}',
|
|
107
|
+
timestamp TIMESTAMPTZ DEFAULT NOW()
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_mutations_genome ON pga_mutations(genome_id, timestamp DESC);
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_mutations_gene ON pga_mutations(genome_id, gene, timestamp DESC);
|
|
112
|
+
CREATE INDEX IF NOT EXISTS idx_mutations_deployed ON pga_mutations(genome_id, deployed, timestamp DESC);
|
|
113
|
+
|
|
114
|
+
-- ═══════════════════════════════════════════════════════════
|
|
115
|
+
-- FEEDBACK (User Feedback Signals)
|
|
116
|
+
-- ═══════════════════════════════════════════════════════════
|
|
117
|
+
|
|
118
|
+
CREATE TABLE IF NOT EXISTS pga_feedback (
|
|
119
|
+
id BIGSERIAL PRIMARY KEY,
|
|
120
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
121
|
+
user_id TEXT NOT NULL,
|
|
122
|
+
gene TEXT,
|
|
123
|
+
sentiment TEXT NOT NULL CHECK (sentiment IN ('positive', 'negative', 'neutral')),
|
|
124
|
+
timestamp TIMESTAMPTZ DEFAULT NOW()
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
CREATE INDEX IF NOT EXISTS idx_feedback_genome ON pga_feedback(genome_id, timestamp DESC);
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_feedback_user ON pga_feedback(genome_id, user_id, timestamp DESC);
|
|
129
|
+
|
|
130
|
+
-- ═══════════════════════════════════════════════════════════
|
|
131
|
+
-- ANALYTICS (Pre-aggregated Stats)
|
|
132
|
+
-- ═══════════════════════════════════════════════════════════
|
|
133
|
+
|
|
134
|
+
CREATE TABLE IF NOT EXISTS pga_analytics (
|
|
135
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
136
|
+
metric TEXT NOT NULL,
|
|
137
|
+
value JSONB NOT NULL,
|
|
138
|
+
snapshot_at TIMESTAMPTZ DEFAULT NOW(),
|
|
139
|
+
PRIMARY KEY (genome_id, metric, snapshot_at)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
CREATE INDEX IF NOT EXISTS idx_analytics_genome ON pga_analytics(genome_id, snapshot_at DESC);
|
|
143
|
+
|
|
144
|
+
-- ═══════════════════════════════════════════════════════════
|
|
145
|
+
-- GENE REGISTRY (Cross-Genome Knowledge Inheritance)
|
|
146
|
+
-- ═══════════════════════════════════════════════════════════
|
|
147
|
+
|
|
148
|
+
CREATE TABLE IF NOT EXISTS pga_gene_registry (
|
|
149
|
+
id TEXT PRIMARY KEY,
|
|
150
|
+
family_id TEXT NOT NULL,
|
|
151
|
+
gene TEXT NOT NULL,
|
|
152
|
+
variant TEXT NOT NULL,
|
|
153
|
+
content TEXT NOT NULL,
|
|
154
|
+
layer INTEGER NOT NULL CHECK (layer IN (0, 1, 2)),
|
|
155
|
+
fitness NUMERIC(5,4) NOT NULL,
|
|
156
|
+
sample_count INTEGER NOT NULL,
|
|
157
|
+
success_rate NUMERIC(5,4) NOT NULL,
|
|
158
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
159
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
160
|
+
UNIQUE(family_id, gene, variant)
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
CREATE INDEX IF NOT EXISTS idx_gene_registry_family ON pga_gene_registry(family_id, fitness DESC);
|
|
164
|
+
CREATE INDEX IF NOT EXISTS idx_gene_registry_gene ON pga_gene_registry(family_id, gene, fitness DESC);
|
|
165
|
+
|
|
166
|
+
-- ═══════════════════════════════════════════════════════════
|
|
167
|
+
-- CALIBRATION HISTORY (Dynamic Threshold Tuning)
|
|
168
|
+
-- Living OS v1.0 Final 10/10
|
|
169
|
+
-- ═══════════════════════════════════════════════════════════
|
|
170
|
+
|
|
171
|
+
CREATE TABLE IF NOT EXISTS pga_calibration_history (
|
|
172
|
+
id BIGSERIAL PRIMARY KEY,
|
|
173
|
+
context_key TEXT NOT NULL,
|
|
174
|
+
layer INTEGER CHECK (layer IN (0, 1, 2)),
|
|
175
|
+
operator TEXT,
|
|
176
|
+
task_type TEXT,
|
|
177
|
+
threshold NUMERIC(5,4) NOT NULL,
|
|
178
|
+
total_candidates INTEGER NOT NULL,
|
|
179
|
+
passed_sandbox INTEGER NOT NULL,
|
|
180
|
+
deployed_successfully INTEGER NOT NULL,
|
|
181
|
+
rolled_back INTEGER NOT NULL,
|
|
182
|
+
false_positive_rate NUMERIC(5,4) NOT NULL,
|
|
183
|
+
false_negative_rate NUMERIC(5,4) NOT NULL,
|
|
184
|
+
optimal_threshold NUMERIC(5,4) NOT NULL,
|
|
185
|
+
timestamp TIMESTAMPTZ DEFAULT NOW()
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_calibration_context ON pga_calibration_history(context_key, timestamp DESC);
|
|
189
|
+
CREATE INDEX IF NOT EXISTS idx_calibration_layer ON pga_calibration_history(layer, timestamp DESC);
|
|
190
|
+
|
|
191
|
+
-- ═══════════════════════════════════════════════════════════
|
|
192
|
+
-- SEMANTIC FACTS (Layered Memory - Long Term Storage)
|
|
193
|
+
-- v0.3.0 - Production-Ready Persistence
|
|
194
|
+
-- ═══════════════════════════════════════════════════════════
|
|
195
|
+
|
|
196
|
+
CREATE TABLE IF NOT EXISTS semantic_facts (
|
|
197
|
+
id TEXT PRIMARY KEY,
|
|
198
|
+
user_id TEXT NOT NULL,
|
|
199
|
+
genome_id TEXT NOT NULL REFERENCES pga_genomes(id) ON DELETE CASCADE,
|
|
200
|
+
|
|
201
|
+
-- Fact content
|
|
202
|
+
fact TEXT NOT NULL,
|
|
203
|
+
category TEXT NOT NULL CHECK (category IN ('profile', 'preference', 'constraint', 'knowledge')),
|
|
204
|
+
|
|
205
|
+
-- Metadata
|
|
206
|
+
confidence NUMERIC(5,4) NOT NULL CHECK (confidence >= 0.0 AND confidence <= 1.0),
|
|
207
|
+
source_turn INTEGER NOT NULL,
|
|
208
|
+
source_interaction_id TEXT,
|
|
209
|
+
|
|
210
|
+
-- Lifecycle
|
|
211
|
+
extracted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
212
|
+
expiry TIMESTAMPTZ, -- NULL = never expires
|
|
213
|
+
verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
214
|
+
|
|
215
|
+
-- Timestamps
|
|
216
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
217
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
-- Indexes for performance
|
|
221
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_facts_user_genome
|
|
222
|
+
ON semantic_facts(user_id, genome_id);
|
|
223
|
+
|
|
224
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_facts_expiry
|
|
225
|
+
ON semantic_facts(expiry)
|
|
226
|
+
WHERE expiry IS NOT NULL;
|
|
227
|
+
|
|
228
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_facts_category
|
|
229
|
+
ON semantic_facts(genome_id, category);
|
|
230
|
+
|
|
231
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_facts_verified
|
|
232
|
+
ON semantic_facts(genome_id, verified)
|
|
233
|
+
WHERE verified = TRUE;
|
|
234
|
+
|
|
235
|
+
CREATE INDEX IF NOT EXISTS idx_semantic_facts_active
|
|
236
|
+
ON semantic_facts(user_id, genome_id, expiry)
|
|
237
|
+
WHERE expiry IS NULL OR expiry > NOW();
|
|
238
|
+
|
|
239
|
+
-- Auto-update updated_at trigger
|
|
240
|
+
CREATE OR REPLACE FUNCTION update_semantic_facts_updated_at()
|
|
241
|
+
RETURNS TRIGGER AS $$
|
|
242
|
+
BEGIN
|
|
243
|
+
NEW.updated_at = NOW();
|
|
244
|
+
RETURN NEW;
|
|
245
|
+
END;
|
|
246
|
+
$$ LANGUAGE plpgsql;
|
|
247
|
+
|
|
248
|
+
CREATE TRIGGER trigger_semantic_facts_updated_at
|
|
249
|
+
BEFORE UPDATE ON semantic_facts
|
|
250
|
+
FOR EACH ROW
|
|
251
|
+
EXECUTE FUNCTION update_semantic_facts_updated_at();
|