@anvia/memory-postgres 0.2.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 +15 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +331 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Indra Zulfi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @anvia/memory-postgres
|
|
2
|
+
|
|
3
|
+
Postgres-backed durable session memory store for Anvia.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createPostgresMemoryStore } from "@anvia/memory-postgres";
|
|
7
|
+
|
|
8
|
+
const memory = await createPostgresMemoryStore({
|
|
9
|
+
connectionString: process.env.DATABASE_URL,
|
|
10
|
+
});
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The package creates the Anvia memory tables by default and writes ordered
|
|
14
|
+
messages transactionally. Pass `createIfMissing: false` when your own migrations
|
|
15
|
+
create the schema.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { MemoryStore, Message } from '@anvia/core';
|
|
2
|
+
import { MemoryAppendInput, MemoryContext, MemoryErrorInput } from '@anvia/core/memory';
|
|
3
|
+
|
|
4
|
+
type PostgresMemoryErrorMode = "store" | "ignore";
|
|
5
|
+
type PostgresMemoryLockMode = "advisory" | "none";
|
|
6
|
+
type PostgresMemoryQueryResult = {
|
|
7
|
+
rows: Record<string, unknown>[];
|
|
8
|
+
};
|
|
9
|
+
type PostgresMemoryClientLike = {
|
|
10
|
+
query(text: string, values?: readonly unknown[]): Promise<PostgresMemoryQueryResult>;
|
|
11
|
+
};
|
|
12
|
+
type PostgresMemoryTransactionClientLike = PostgresMemoryClientLike & {
|
|
13
|
+
release(): void;
|
|
14
|
+
};
|
|
15
|
+
type PostgresMemoryPoolLike = PostgresMemoryClientLike & {
|
|
16
|
+
connect(): Promise<PostgresMemoryTransactionClientLike>;
|
|
17
|
+
};
|
|
18
|
+
type PostgresMemoryScopeOptions = {
|
|
19
|
+
includeUserId?: boolean | undefined;
|
|
20
|
+
metadataKeys?: string[] | undefined;
|
|
21
|
+
};
|
|
22
|
+
type PostgresMemoryTableNames = {
|
|
23
|
+
sessions?: string | undefined;
|
|
24
|
+
messages?: string | undefined;
|
|
25
|
+
errors?: string | undefined;
|
|
26
|
+
};
|
|
27
|
+
type PostgresMemorySchemaOptions = {
|
|
28
|
+
tablePrefix?: string | undefined;
|
|
29
|
+
tableNames?: PostgresMemoryTableNames | undefined;
|
|
30
|
+
};
|
|
31
|
+
type PostgresMemoryStoreOptions = PostgresMemorySchemaOptions & {
|
|
32
|
+
client?: PostgresMemoryClientLike | undefined;
|
|
33
|
+
connectionString?: string | undefined;
|
|
34
|
+
createIfMissing?: boolean | undefined;
|
|
35
|
+
scope?: PostgresMemoryScopeOptions | ((context: MemoryContext) => string) | undefined;
|
|
36
|
+
errors?: PostgresMemoryErrorMode | undefined;
|
|
37
|
+
validateMessages?: boolean | undefined;
|
|
38
|
+
lock?: PostgresMemoryLockMode | undefined;
|
|
39
|
+
};
|
|
40
|
+
type PostgresMemoryAppendInput = MemoryAppendInput;
|
|
41
|
+
type PostgresMemoryContext = MemoryContext;
|
|
42
|
+
type PostgresMemoryErrorInput = MemoryErrorInput;
|
|
43
|
+
|
|
44
|
+
declare function createPostgresMemoryStore(options?: PostgresMemoryStoreOptions): Promise<PostgresMemoryStore>;
|
|
45
|
+
declare function createPostgresMemoryScopeKey(context: MemoryContext, options?: PostgresMemoryScopeOptions): string;
|
|
46
|
+
declare function createPostgresMemorySchemaSql(options?: PostgresMemorySchemaOptions): string;
|
|
47
|
+
declare class PostgresMemoryStore implements MemoryStore {
|
|
48
|
+
private readonly client;
|
|
49
|
+
private readonly tables;
|
|
50
|
+
private readonly options;
|
|
51
|
+
readonly kind = "postgres";
|
|
52
|
+
private constructor();
|
|
53
|
+
static connect(options?: PostgresMemoryStoreOptions): Promise<PostgresMemoryStore>;
|
|
54
|
+
load(context: MemoryContext): Promise<Message[]>;
|
|
55
|
+
append(input: MemoryAppendInput): Promise<void>;
|
|
56
|
+
clear(context: MemoryContext): Promise<void>;
|
|
57
|
+
recordError(input: MemoryErrorInput): Promise<void>;
|
|
58
|
+
private transaction;
|
|
59
|
+
private upsertSession;
|
|
60
|
+
private insertMessages;
|
|
61
|
+
private messageFromValue;
|
|
62
|
+
private scopeKey;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { type PostgresMemoryAppendInput, type PostgresMemoryClientLike, type PostgresMemoryContext, type PostgresMemoryErrorInput, type PostgresMemoryErrorMode, type PostgresMemoryLockMode, type PostgresMemoryPoolLike, type PostgresMemoryQueryResult, type PostgresMemorySchemaOptions, type PostgresMemoryScopeOptions, PostgresMemoryStore, type PostgresMemoryStoreOptions, type PostgresMemoryTableNames, type PostgresMemoryTransactionClientLike, createPostgresMemorySchemaSql, createPostgresMemoryScopeKey, createPostgresMemoryStore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
// src/message.ts
|
|
2
|
+
function parseMemoryMessage(value) {
|
|
3
|
+
if (!isMemoryMessage(value)) {
|
|
4
|
+
throw new TypeError("Stored Postgres memory row does not contain a valid Anvia Message.");
|
|
5
|
+
}
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function isMemoryMessage(value) {
|
|
9
|
+
if (!isRecord(value) || typeof value.role !== "string") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (value.role === "system") {
|
|
13
|
+
return typeof value.content === "string";
|
|
14
|
+
}
|
|
15
|
+
if (value.role === "user" || value.role === "assistant" || value.role === "tool") {
|
|
16
|
+
return Array.isArray(value.content);
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
function serializeUnknownError(error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
return {
|
|
23
|
+
name: error.name,
|
|
24
|
+
message: error.message,
|
|
25
|
+
...error.stack === void 0 ? {} : { stack: error.stack }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (isJsonValue(error)) {
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
message: String(error)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function isJsonValue(value) {
|
|
36
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
37
|
+
return Number.isFinite(value) || typeof value !== "number";
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
return value.every(isJsonValue);
|
|
41
|
+
}
|
|
42
|
+
return isRecord(value) && Object.values(value).every((item) => item === void 0 || isJsonValue(item));
|
|
43
|
+
}
|
|
44
|
+
function isRecord(value) {
|
|
45
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/store.ts
|
|
49
|
+
var defaultScopeOptions = {
|
|
50
|
+
includeUserId: true,
|
|
51
|
+
metadataKeys: []
|
|
52
|
+
};
|
|
53
|
+
async function createPostgresMemoryStore(options = {}) {
|
|
54
|
+
return PostgresMemoryStore.connect(options);
|
|
55
|
+
}
|
|
56
|
+
function createPostgresMemoryScopeKey(context, options = {}) {
|
|
57
|
+
const includeUserId = options.includeUserId ?? defaultScopeOptions.includeUserId;
|
|
58
|
+
const metadataKeys = options.metadataKeys ?? defaultScopeOptions.metadataKeys;
|
|
59
|
+
const values = [context.sessionId];
|
|
60
|
+
if (includeUserId) {
|
|
61
|
+
values.push(context.userId ?? null);
|
|
62
|
+
}
|
|
63
|
+
for (const key of metadataKeys) {
|
|
64
|
+
values.push(metadataValue(context.metadata, key) ?? null);
|
|
65
|
+
}
|
|
66
|
+
return JSON.stringify(values);
|
|
67
|
+
}
|
|
68
|
+
function createPostgresMemorySchemaSql(options = {}) {
|
|
69
|
+
const tables = resolveTables(options);
|
|
70
|
+
return `CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
71
|
+
|
|
72
|
+
CREATE TABLE IF NOT EXISTS ${tables.sessions} (
|
|
73
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
74
|
+
scope_key text NOT NULL UNIQUE,
|
|
75
|
+
session_id text NOT NULL,
|
|
76
|
+
user_id text,
|
|
77
|
+
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
78
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
79
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
CREATE TABLE IF NOT EXISTS ${tables.messages} (
|
|
83
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
84
|
+
memory_session_id uuid NOT NULL REFERENCES ${tables.sessions}(id) ON DELETE CASCADE,
|
|
85
|
+
run_id text NOT NULL,
|
|
86
|
+
turn integer NOT NULL,
|
|
87
|
+
position integer NOT NULL,
|
|
88
|
+
role text NOT NULL,
|
|
89
|
+
message jsonb NOT NULL,
|
|
90
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ${tables.messagesPositionIndex}
|
|
94
|
+
ON ${tables.messages}(memory_session_id, position);
|
|
95
|
+
|
|
96
|
+
CREATE TABLE IF NOT EXISTS ${tables.errors} (
|
|
97
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
98
|
+
memory_session_id uuid NOT NULL REFERENCES ${tables.sessions}(id) ON DELETE CASCADE,
|
|
99
|
+
run_id text NOT NULL,
|
|
100
|
+
error jsonb NOT NULL,
|
|
101
|
+
messages jsonb NOT NULL,
|
|
102
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
103
|
+
);`;
|
|
104
|
+
}
|
|
105
|
+
var PostgresMemoryStore = class _PostgresMemoryStore {
|
|
106
|
+
constructor(client, tables, options) {
|
|
107
|
+
this.client = client;
|
|
108
|
+
this.tables = tables;
|
|
109
|
+
this.options = options;
|
|
110
|
+
}
|
|
111
|
+
client;
|
|
112
|
+
tables;
|
|
113
|
+
options;
|
|
114
|
+
kind = "postgres";
|
|
115
|
+
static async connect(options = {}) {
|
|
116
|
+
const client = options.client ?? await defaultPgClient(options.connectionString);
|
|
117
|
+
const tables = resolveTables(options);
|
|
118
|
+
const resolved = resolveOptions(options);
|
|
119
|
+
if (resolved.createIfMissing) {
|
|
120
|
+
await client.query(createPostgresMemorySchemaSql(options));
|
|
121
|
+
}
|
|
122
|
+
return new _PostgresMemoryStore(client, tables, resolved);
|
|
123
|
+
}
|
|
124
|
+
async load(context) {
|
|
125
|
+
const result = await this.client.query(
|
|
126
|
+
`SELECT m.message
|
|
127
|
+
FROM ${this.tables.messages} m
|
|
128
|
+
INNER JOIN ${this.tables.sessions} s ON s.id = m.memory_session_id
|
|
129
|
+
WHERE s.scope_key = $1
|
|
130
|
+
ORDER BY m.position ASC`,
|
|
131
|
+
[this.scopeKey(context)]
|
|
132
|
+
);
|
|
133
|
+
return result.rows.map((row) => this.messageFromValue(row.message));
|
|
134
|
+
}
|
|
135
|
+
async append(input) {
|
|
136
|
+
if (input.messages.length === 0) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const scopeKey = this.scopeKey(input.context);
|
|
140
|
+
await this.transaction(async (tx) => {
|
|
141
|
+
if (this.options.lock === "advisory") {
|
|
142
|
+
await tx.query("SELECT pg_advisory_xact_lock(hashtext($1))", [scopeKey]);
|
|
143
|
+
}
|
|
144
|
+
const session = await this.upsertSession(tx, input.context, scopeKey);
|
|
145
|
+
const last = await tx.query(
|
|
146
|
+
`SELECT position
|
|
147
|
+
FROM ${this.tables.messages}
|
|
148
|
+
WHERE memory_session_id = $1
|
|
149
|
+
ORDER BY position DESC
|
|
150
|
+
LIMIT 1`,
|
|
151
|
+
[session.id]
|
|
152
|
+
);
|
|
153
|
+
const start = Number(last.rows[0]?.position ?? -1);
|
|
154
|
+
await this.insertMessages(tx, session.id, input, start + 1);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async clear(context) {
|
|
158
|
+
await this.client.query(`DELETE FROM ${this.tables.sessions} WHERE scope_key = $1`, [
|
|
159
|
+
this.scopeKey(context)
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
async recordError(input) {
|
|
163
|
+
if (this.options.errors === "ignore") {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const scopeKey = this.scopeKey(input.context);
|
|
167
|
+
await this.transaction(async (tx) => {
|
|
168
|
+
if (this.options.lock === "advisory") {
|
|
169
|
+
await tx.query("SELECT pg_advisory_xact_lock(hashtext($1))", [scopeKey]);
|
|
170
|
+
}
|
|
171
|
+
const session = await this.upsertSession(tx, input.context, scopeKey);
|
|
172
|
+
await tx.query(
|
|
173
|
+
`INSERT INTO ${this.tables.errors} (
|
|
174
|
+
memory_session_id,
|
|
175
|
+
run_id,
|
|
176
|
+
error,
|
|
177
|
+
messages
|
|
178
|
+
) VALUES ($1, $2, $3::jsonb, $4::jsonb)`,
|
|
179
|
+
[
|
|
180
|
+
session.id,
|
|
181
|
+
input.runId,
|
|
182
|
+
JSON.stringify(serializeUnknownError(input.error)),
|
|
183
|
+
JSON.stringify(input.messages)
|
|
184
|
+
]
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async transaction(operation) {
|
|
189
|
+
const tx = await transactionClient(this.client);
|
|
190
|
+
try {
|
|
191
|
+
await tx.query("BEGIN");
|
|
192
|
+
const result = await operation(tx);
|
|
193
|
+
await tx.query("COMMIT");
|
|
194
|
+
return result;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
await tx.query("ROLLBACK");
|
|
197
|
+
throw error;
|
|
198
|
+
} finally {
|
|
199
|
+
if (isTransactionClient(tx)) {
|
|
200
|
+
tx.release();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async upsertSession(client, context, scopeKey) {
|
|
205
|
+
const result = await client.query(
|
|
206
|
+
`INSERT INTO ${this.tables.sessions} (
|
|
207
|
+
scope_key,
|
|
208
|
+
session_id,
|
|
209
|
+
user_id,
|
|
210
|
+
metadata
|
|
211
|
+
) VALUES ($1, $2, $3, $4::jsonb)
|
|
212
|
+
ON CONFLICT (scope_key) DO UPDATE SET
|
|
213
|
+
session_id = EXCLUDED.session_id,
|
|
214
|
+
user_id = EXCLUDED.user_id,
|
|
215
|
+
metadata = EXCLUDED.metadata,
|
|
216
|
+
updated_at = now()
|
|
217
|
+
RETURNING id`,
|
|
218
|
+
[scopeKey, context.sessionId, context.userId ?? null, JSON.stringify(metadata(context))]
|
|
219
|
+
);
|
|
220
|
+
const session = result.rows[0];
|
|
221
|
+
if (session === void 0) {
|
|
222
|
+
throw new Error("PostgresMemoryStore failed to upsert memory session.");
|
|
223
|
+
}
|
|
224
|
+
return session;
|
|
225
|
+
}
|
|
226
|
+
async insertMessages(client, memorySessionId, input, start) {
|
|
227
|
+
const values = input.messages.flatMap((message, index) => [
|
|
228
|
+
memorySessionId,
|
|
229
|
+
input.runId,
|
|
230
|
+
input.turn,
|
|
231
|
+
start + index,
|
|
232
|
+
message.role,
|
|
233
|
+
JSON.stringify(message)
|
|
234
|
+
]);
|
|
235
|
+
const placeholders = input.messages.map((_, index) => {
|
|
236
|
+
const offset = index * 6;
|
|
237
|
+
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}, $${offset + 6}::jsonb)`;
|
|
238
|
+
});
|
|
239
|
+
await client.query(
|
|
240
|
+
`INSERT INTO ${this.tables.messages} (
|
|
241
|
+
memory_session_id,
|
|
242
|
+
run_id,
|
|
243
|
+
turn,
|
|
244
|
+
position,
|
|
245
|
+
role,
|
|
246
|
+
message
|
|
247
|
+
) VALUES ${placeholders.join(", ")}`,
|
|
248
|
+
values
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
messageFromValue(value) {
|
|
252
|
+
const parsed = typeof value === "string" ? JSON.parse(value) : value;
|
|
253
|
+
return this.options.validateMessages ? parseMemoryMessage(parsed) : parsed;
|
|
254
|
+
}
|
|
255
|
+
scopeKey(context) {
|
|
256
|
+
if (typeof this.options.scope === "function") {
|
|
257
|
+
return this.options.scope(context);
|
|
258
|
+
}
|
|
259
|
+
return createPostgresMemoryScopeKey(context, this.options.scope);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
function resolveOptions(options) {
|
|
263
|
+
return {
|
|
264
|
+
scope: options.scope,
|
|
265
|
+
errors: options.errors ?? "store",
|
|
266
|
+
validateMessages: options.validateMessages ?? true,
|
|
267
|
+
createIfMissing: options.createIfMissing ?? true,
|
|
268
|
+
lock: options.lock ?? "advisory"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function resolveTables(options) {
|
|
272
|
+
const prefix = options.tablePrefix ?? "anvia_";
|
|
273
|
+
return {
|
|
274
|
+
sessions: quoteQualifiedIdentifier(options.tableNames?.sessions ?? `${prefix}memory_sessions`),
|
|
275
|
+
messages: quoteQualifiedIdentifier(options.tableNames?.messages ?? `${prefix}memory_messages`),
|
|
276
|
+
errors: quoteQualifiedIdentifier(options.tableNames?.errors ?? `${prefix}memory_errors`),
|
|
277
|
+
messagesPositionIndex: quoteIdentifier(`${prefix}memory_messages_session_position_idx`)
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function quoteQualifiedIdentifier(identifier) {
|
|
281
|
+
const parts = identifier.split(".");
|
|
282
|
+
if (parts.length === 0 || parts.some((part) => part.length === 0)) {
|
|
283
|
+
throw new Error(`Invalid Postgres identifier: ${identifier}`);
|
|
284
|
+
}
|
|
285
|
+
return parts.map(quoteIdentifier).join(".");
|
|
286
|
+
}
|
|
287
|
+
function quoteIdentifier(identifier) {
|
|
288
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {
|
|
289
|
+
throw new Error(`Invalid Postgres identifier: ${identifier}`);
|
|
290
|
+
}
|
|
291
|
+
return `"${identifier.replaceAll('"', '""')}"`;
|
|
292
|
+
}
|
|
293
|
+
async function transactionClient(client) {
|
|
294
|
+
if (isPool(client)) {
|
|
295
|
+
return client.connect();
|
|
296
|
+
}
|
|
297
|
+
return client;
|
|
298
|
+
}
|
|
299
|
+
function isPool(client) {
|
|
300
|
+
return "connect" in client && typeof client.connect === "function";
|
|
301
|
+
}
|
|
302
|
+
function isTransactionClient(client) {
|
|
303
|
+
return "release" in client && typeof client.release === "function";
|
|
304
|
+
}
|
|
305
|
+
async function defaultPgClient(connectionString) {
|
|
306
|
+
const pg = await import("pg");
|
|
307
|
+
return new pg.Pool(connectionString === void 0 ? {} : { connectionString });
|
|
308
|
+
}
|
|
309
|
+
function metadata(context) {
|
|
310
|
+
return context.metadata ?? {};
|
|
311
|
+
}
|
|
312
|
+
function metadataValue(metadata2, path) {
|
|
313
|
+
let current = metadata2;
|
|
314
|
+
for (const part of path.split(".")) {
|
|
315
|
+
if (!isJsonObject(current)) {
|
|
316
|
+
return void 0;
|
|
317
|
+
}
|
|
318
|
+
current = current[part];
|
|
319
|
+
}
|
|
320
|
+
return current;
|
|
321
|
+
}
|
|
322
|
+
function isJsonObject(value) {
|
|
323
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
324
|
+
}
|
|
325
|
+
export {
|
|
326
|
+
PostgresMemoryStore,
|
|
327
|
+
createPostgresMemorySchemaSql,
|
|
328
|
+
createPostgresMemoryScopeKey,
|
|
329
|
+
createPostgresMemoryStore
|
|
330
|
+
};
|
|
331
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/message.ts","../src/store.ts"],"sourcesContent":["import type { JsonValue, Message } from \"@anvia/core\";\n\nexport function parseMemoryMessage(value: unknown): Message {\n if (!isMemoryMessage(value)) {\n throw new TypeError(\"Stored Postgres memory row does not contain a valid Anvia Message.\");\n }\n return value;\n}\n\nexport function isMemoryMessage(value: unknown): value is Message {\n if (!isRecord(value) || typeof value.role !== \"string\") {\n return false;\n }\n\n if (value.role === \"system\") {\n return typeof value.content === \"string\";\n }\n\n if (value.role === \"user\" || value.role === \"assistant\" || value.role === \"tool\") {\n return Array.isArray(value.content);\n }\n\n return false;\n}\n\nexport function serializeUnknownError(error: unknown): JsonValue {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n ...(error.stack === undefined ? {} : { stack: error.stack }),\n };\n }\n\n if (isJsonValue(error)) {\n return error;\n }\n\n return {\n message: String(error),\n };\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return Number.isFinite(value) || typeof value !== \"number\";\n }\n\n if (Array.isArray(value)) {\n return value.every(isJsonValue);\n }\n\n return (\n isRecord(value) && Object.values(value).every((item) => item === undefined || isJsonValue(item))\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import type { JsonObject, JsonValue, MemoryStore, Message } from \"@anvia/core\";\nimport type { MemoryAppendInput, MemoryContext, MemoryErrorInput } from \"@anvia/core/memory\";\nimport { parseMemoryMessage, serializeUnknownError } from \"./message.js\";\nimport type {\n PostgresMemoryClientLike,\n PostgresMemoryPoolLike,\n PostgresMemorySchemaOptions,\n PostgresMemoryScopeOptions,\n PostgresMemoryStoreOptions,\n PostgresMemoryTransactionClientLike,\n} from \"./types.js\";\n\nconst defaultScopeOptions: { includeUserId: boolean; metadataKeys: string[] } = {\n includeUserId: true,\n metadataKeys: [],\n};\n\ntype ResolvedPostgresMemoryStoreOptions = Required<\n Pick<PostgresMemoryStoreOptions, \"createIfMissing\" | \"errors\" | \"lock\" | \"validateMessages\">\n> &\n Pick<PostgresMemoryStoreOptions, \"scope\">;\n\ntype ResolvedPostgresMemoryTables = {\n sessions: string;\n messages: string;\n errors: string;\n messagesPositionIndex: string;\n};\n\ntype SessionRow = {\n id: string;\n};\n\ntype PositionRow = {\n position: number | string | null;\n};\n\ntype MessageRow = {\n message: unknown;\n};\n\nexport async function createPostgresMemoryStore(\n options: PostgresMemoryStoreOptions = {},\n): Promise<PostgresMemoryStore> {\n return PostgresMemoryStore.connect(options);\n}\n\nexport function createPostgresMemoryScopeKey(\n context: MemoryContext,\n options: PostgresMemoryScopeOptions = {},\n): string {\n const includeUserId = options.includeUserId ?? defaultScopeOptions.includeUserId;\n const metadataKeys = options.metadataKeys ?? defaultScopeOptions.metadataKeys;\n const values: JsonValue[] = [context.sessionId];\n\n if (includeUserId) {\n values.push(context.userId ?? null);\n }\n\n for (const key of metadataKeys) {\n values.push(metadataValue(context.metadata, key) ?? null);\n }\n\n return JSON.stringify(values);\n}\n\nexport function createPostgresMemorySchemaSql(options: PostgresMemorySchemaOptions = {}): string {\n const tables = resolveTables(options);\n return `CREATE EXTENSION IF NOT EXISTS pgcrypto;\n\nCREATE TABLE IF NOT EXISTS ${tables.sessions} (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n scope_key text NOT NULL UNIQUE,\n session_id text NOT NULL,\n user_id text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE TABLE IF NOT EXISTS ${tables.messages} (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n memory_session_id uuid NOT NULL REFERENCES ${tables.sessions}(id) ON DELETE CASCADE,\n run_id text NOT NULL,\n turn integer NOT NULL,\n position integer NOT NULL,\n role text NOT NULL,\n message jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS ${tables.messagesPositionIndex}\n ON ${tables.messages}(memory_session_id, position);\n\nCREATE TABLE IF NOT EXISTS ${tables.errors} (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n memory_session_id uuid NOT NULL REFERENCES ${tables.sessions}(id) ON DELETE CASCADE,\n run_id text NOT NULL,\n error jsonb NOT NULL,\n messages jsonb NOT NULL,\n created_at timestamptz NOT NULL DEFAULT now()\n);`;\n}\n\nexport class PostgresMemoryStore implements MemoryStore {\n readonly kind = \"postgres\";\n\n private constructor(\n private readonly client: PostgresMemoryClientLike,\n private readonly tables: ResolvedPostgresMemoryTables,\n private readonly options: ResolvedPostgresMemoryStoreOptions,\n ) {}\n\n static async connect(options: PostgresMemoryStoreOptions = {}): Promise<PostgresMemoryStore> {\n const client = options.client ?? (await defaultPgClient(options.connectionString));\n const tables = resolveTables(options);\n const resolved = resolveOptions(options);\n\n if (resolved.createIfMissing) {\n await client.query(createPostgresMemorySchemaSql(options));\n }\n\n return new PostgresMemoryStore(client, tables, resolved);\n }\n\n async load(context: MemoryContext): Promise<Message[]> {\n const result = await this.client.query(\n `SELECT m.message\n FROM ${this.tables.messages} m\n INNER JOIN ${this.tables.sessions} s ON s.id = m.memory_session_id\n WHERE s.scope_key = $1\n ORDER BY m.position ASC`,\n [this.scopeKey(context)],\n );\n\n return result.rows.map((row) => this.messageFromValue((row as MessageRow).message));\n }\n\n async append(input: MemoryAppendInput): Promise<void> {\n if (input.messages.length === 0) {\n return;\n }\n\n const scopeKey = this.scopeKey(input.context);\n\n await this.transaction(async (tx) => {\n if (this.options.lock === \"advisory\") {\n await tx.query(\"SELECT pg_advisory_xact_lock(hashtext($1))\", [scopeKey]);\n }\n\n const session = await this.upsertSession(tx, input.context, scopeKey);\n const last = await tx.query(\n `SELECT position\n FROM ${this.tables.messages}\n WHERE memory_session_id = $1\n ORDER BY position DESC\n LIMIT 1`,\n [session.id],\n );\n const start = Number(((last.rows[0] as PositionRow | undefined)?.position ?? -1) as number);\n await this.insertMessages(tx, session.id, input, start + 1);\n });\n }\n\n async clear(context: MemoryContext): Promise<void> {\n await this.client.query(`DELETE FROM ${this.tables.sessions} WHERE scope_key = $1`, [\n this.scopeKey(context),\n ]);\n }\n\n async recordError(input: MemoryErrorInput): Promise<void> {\n if (this.options.errors === \"ignore\") {\n return;\n }\n\n const scopeKey = this.scopeKey(input.context);\n\n await this.transaction(async (tx) => {\n if (this.options.lock === \"advisory\") {\n await tx.query(\"SELECT pg_advisory_xact_lock(hashtext($1))\", [scopeKey]);\n }\n\n const session = await this.upsertSession(tx, input.context, scopeKey);\n await tx.query(\n `INSERT INTO ${this.tables.errors} (\n memory_session_id,\n run_id,\n error,\n messages\n ) VALUES ($1, $2, $3::jsonb, $4::jsonb)`,\n [\n session.id,\n input.runId,\n JSON.stringify(serializeUnknownError(input.error)),\n JSON.stringify(input.messages),\n ],\n );\n });\n }\n\n private async transaction<T>(\n operation: (tx: PostgresMemoryClientLike) => Promise<T>,\n ): Promise<T> {\n const tx = await transactionClient(this.client);\n try {\n await tx.query(\"BEGIN\");\n const result = await operation(tx);\n await tx.query(\"COMMIT\");\n return result;\n } catch (error) {\n await tx.query(\"ROLLBACK\");\n throw error;\n } finally {\n if (isTransactionClient(tx)) {\n tx.release();\n }\n }\n }\n\n private async upsertSession(\n client: PostgresMemoryClientLike,\n context: MemoryContext,\n scopeKey: string,\n ): Promise<SessionRow> {\n const result = await client.query(\n `INSERT INTO ${this.tables.sessions} (\n scope_key,\n session_id,\n user_id,\n metadata\n ) VALUES ($1, $2, $3, $4::jsonb)\n ON CONFLICT (scope_key) DO UPDATE SET\n session_id = EXCLUDED.session_id,\n user_id = EXCLUDED.user_id,\n metadata = EXCLUDED.metadata,\n updated_at = now()\n RETURNING id`,\n [scopeKey, context.sessionId, context.userId ?? null, JSON.stringify(metadata(context))],\n );\n const session = result.rows[0] as SessionRow | undefined;\n if (session === undefined) {\n throw new Error(\"PostgresMemoryStore failed to upsert memory session.\");\n }\n return session;\n }\n\n private async insertMessages(\n client: PostgresMemoryClientLike,\n memorySessionId: string,\n input: MemoryAppendInput,\n start: number,\n ): Promise<void> {\n const values = input.messages.flatMap((message, index) => [\n memorySessionId,\n input.runId,\n input.turn,\n start + index,\n message.role,\n JSON.stringify(message),\n ]);\n const placeholders = input.messages.map((_, index) => {\n const offset = index * 6;\n return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${\n offset + 5\n }, $${offset + 6}::jsonb)`;\n });\n\n await client.query(\n `INSERT INTO ${this.tables.messages} (\n memory_session_id,\n run_id,\n turn,\n position,\n role,\n message\n ) VALUES ${placeholders.join(\", \")}`,\n values,\n );\n }\n\n private messageFromValue(value: unknown): Message {\n const parsed = typeof value === \"string\" ? (JSON.parse(value) as unknown) : value;\n return this.options.validateMessages ? parseMemoryMessage(parsed) : (parsed as Message);\n }\n\n private scopeKey(context: MemoryContext): string {\n if (typeof this.options.scope === \"function\") {\n return this.options.scope(context);\n }\n return createPostgresMemoryScopeKey(context, this.options.scope);\n }\n}\n\nfunction resolveOptions(options: PostgresMemoryStoreOptions): ResolvedPostgresMemoryStoreOptions {\n return {\n scope: options.scope,\n errors: options.errors ?? \"store\",\n validateMessages: options.validateMessages ?? true,\n createIfMissing: options.createIfMissing ?? true,\n lock: options.lock ?? \"advisory\",\n };\n}\n\nfunction resolveTables(options: PostgresMemorySchemaOptions): ResolvedPostgresMemoryTables {\n const prefix = options.tablePrefix ?? \"anvia_\";\n return {\n sessions: quoteQualifiedIdentifier(options.tableNames?.sessions ?? `${prefix}memory_sessions`),\n messages: quoteQualifiedIdentifier(options.tableNames?.messages ?? `${prefix}memory_messages`),\n errors: quoteQualifiedIdentifier(options.tableNames?.errors ?? `${prefix}memory_errors`),\n messagesPositionIndex: quoteIdentifier(`${prefix}memory_messages_session_position_idx`),\n };\n}\n\nfunction quoteQualifiedIdentifier(identifier: string): string {\n const parts = identifier.split(\".\");\n if (parts.length === 0 || parts.some((part) => part.length === 0)) {\n throw new Error(`Invalid Postgres identifier: ${identifier}`);\n }\n return parts.map(quoteIdentifier).join(\".\");\n}\n\nfunction quoteIdentifier(identifier: string): string {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {\n throw new Error(`Invalid Postgres identifier: ${identifier}`);\n }\n return `\"${identifier.replaceAll('\"', '\"\"')}\"`;\n}\n\nasync function transactionClient(\n client: PostgresMemoryClientLike,\n): Promise<PostgresMemoryClientLike | PostgresMemoryTransactionClientLike> {\n if (isPool(client)) {\n return client.connect();\n }\n return client;\n}\n\nfunction isPool(client: PostgresMemoryClientLike): client is PostgresMemoryPoolLike {\n return \"connect\" in client && typeof client.connect === \"function\";\n}\n\nfunction isTransactionClient(\n client: PostgresMemoryClientLike,\n): client is PostgresMemoryTransactionClientLike {\n return \"release\" in client && typeof client.release === \"function\";\n}\n\nasync function defaultPgClient(\n connectionString: string | undefined,\n): Promise<PostgresMemoryPoolLike> {\n const pg = await import(\"pg\");\n return new pg.Pool(connectionString === undefined ? {} : { connectionString });\n}\n\nfunction metadata(context: MemoryContext): JsonObject {\n return context.metadata ?? {};\n}\n\nfunction metadataValue(metadata: JsonObject | undefined, path: string): JsonValue | undefined {\n let current: JsonValue | undefined = metadata;\n for (const part of path.split(\".\")) {\n if (!isJsonObject(current)) {\n return undefined;\n }\n current = current[part];\n }\n return current;\n}\n\nfunction isJsonObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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","names":["metadata"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anvia/memory-postgres",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Postgres-backed durable session memory store for Anvia.",
|
|
5
|
+
"author": "anvia",
|
|
6
|
+
"maintainer": "Indra Zulfi",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/anvia-hq/anvia",
|
|
11
|
+
"directory": "packages/memory-postgres"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"pg": "^8.22.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^24.9.1",
|
|
33
|
+
"@types/pg": "^8.15.6",
|
|
34
|
+
"tsup": "^8.5.0",
|
|
35
|
+
"typescript": "^5.9.3",
|
|
36
|
+
"vitest": "^4.0.8",
|
|
37
|
+
"@anvia/core": "0.12.3"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@anvia/core": ">=0.12.0 <1.0.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup src/index.ts --format esm --dts --sourcemap --clean",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"typecheck": "tsc --noEmit"
|
|
46
|
+
}
|
|
47
|
+
}
|