wolbarg 0.5.5 → 0.5.7
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/CHANGELOG.md +36 -0
- package/README.md +73 -292
- package/dist/cli.js +515 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +532 -116
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -8
- package/dist/index.d.ts +145 -8
- package/dist/index.js +518 -119
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -4,9 +4,9 @@ var fs6 = require("node:fs");
|
|
|
4
4
|
var path7 = require("node:path");
|
|
5
5
|
var crypto$1 = require('crypto');
|
|
6
6
|
var fs = require('fs/promises');
|
|
7
|
+
var async_hooks = require('async_hooks');
|
|
7
8
|
var sqlite$1 = require("node:sqlite");
|
|
8
9
|
var sqliteVec = require('sqlite-vec');
|
|
9
|
-
var async_hooks = require('async_hooks');
|
|
10
10
|
var events = require('events');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -472,8 +472,8 @@ var AsyncMutex = class {
|
|
|
472
472
|
*/
|
|
473
473
|
async runExclusive(fn) {
|
|
474
474
|
let release;
|
|
475
|
-
const next = new Promise((
|
|
476
|
-
release =
|
|
475
|
+
const next = new Promise((resolve3) => {
|
|
476
|
+
release = resolve3;
|
|
477
477
|
});
|
|
478
478
|
const previous = this.chain;
|
|
479
479
|
this.chain = previous.then(() => next);
|
|
@@ -2265,19 +2265,35 @@ var DEFAULT_CONCURRENCY = {
|
|
|
2265
2265
|
maxRetries: 5,
|
|
2266
2266
|
baseBackoffMs: 50,
|
|
2267
2267
|
maxBackoffMs: 2e3,
|
|
2268
|
-
lockTimeoutMs: 5e3
|
|
2268
|
+
lockTimeoutMs: 5e3,
|
|
2269
|
+
lockDeadlineMs: 3e4
|
|
2270
|
+
};
|
|
2271
|
+
var MULTI_PROCESS_CONCURRENCY = {
|
|
2272
|
+
maxRetries: 12,
|
|
2273
|
+
baseBackoffMs: 40,
|
|
2274
|
+
maxBackoffMs: 3e3,
|
|
2275
|
+
lockTimeoutMs: 15e3,
|
|
2276
|
+
lockDeadlineMs: 9e4
|
|
2269
2277
|
};
|
|
2270
2278
|
function resolveConcurrencyConfig(input) {
|
|
2279
|
+
const base = input?.multiProcess ? MULTI_PROCESS_CONCURRENCY : DEFAULT_CONCURRENCY;
|
|
2280
|
+
const maxRetries = input?.maxRetries ?? base.maxRetries;
|
|
2281
|
+
const baseBackoffMs = input?.baseBackoffMs ?? base.baseBackoffMs;
|
|
2282
|
+
const maxBackoffMs = input?.maxBackoffMs ?? base.maxBackoffMs;
|
|
2283
|
+
const lockTimeoutMs = input?.lockTimeoutMs ?? base.lockTimeoutMs;
|
|
2284
|
+
const lockDeadlineMs = input?.lockDeadlineMs ?? Math.max(base.lockDeadlineMs, lockTimeoutMs * (maxRetries + 1));
|
|
2271
2285
|
const resolved = {
|
|
2272
|
-
maxRetries
|
|
2273
|
-
baseBackoffMs
|
|
2274
|
-
maxBackoffMs
|
|
2275
|
-
lockTimeoutMs
|
|
2286
|
+
maxRetries,
|
|
2287
|
+
baseBackoffMs,
|
|
2288
|
+
maxBackoffMs,
|
|
2289
|
+
lockTimeoutMs,
|
|
2290
|
+
lockDeadlineMs
|
|
2276
2291
|
};
|
|
2277
2292
|
assertPositiveInt(resolved.maxRetries, "concurrency.maxRetries");
|
|
2278
2293
|
assertPositiveNumber(resolved.baseBackoffMs, "concurrency.baseBackoffMs");
|
|
2279
2294
|
assertPositiveNumber(resolved.maxBackoffMs, "concurrency.maxBackoffMs");
|
|
2280
2295
|
assertPositiveInt(resolved.lockTimeoutMs, "concurrency.lockTimeoutMs");
|
|
2296
|
+
assertPositiveInt(resolved.lockDeadlineMs, "concurrency.lockDeadlineMs");
|
|
2281
2297
|
if (resolved.maxBackoffMs < resolved.baseBackoffMs) {
|
|
2282
2298
|
throw new ConfigurationError(
|
|
2283
2299
|
"concurrency.maxBackoffMs must be >= concurrency.baseBackoffMs"
|
|
@@ -2303,19 +2319,25 @@ function isSqliteBusyError(error) {
|
|
|
2303
2319
|
return lower.includes("database is locked") || lower.includes("sqlite_busy") || lower.includes("busy");
|
|
2304
2320
|
}
|
|
2305
2321
|
function sleep(ms) {
|
|
2306
|
-
return new Promise((
|
|
2322
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
2307
2323
|
}
|
|
2308
2324
|
function backoffDelay(attempt, config) {
|
|
2309
2325
|
const exp = Math.min(
|
|
2310
2326
|
config.maxBackoffMs,
|
|
2311
2327
|
config.baseBackoffMs * 2 ** attempt
|
|
2312
2328
|
);
|
|
2313
|
-
|
|
2314
|
-
|
|
2329
|
+
return Math.random() * exp;
|
|
2330
|
+
}
|
|
2331
|
+
function deadlineExceeded(startedAt, config) {
|
|
2332
|
+
return performance.now() - startedAt >= config.lockDeadlineMs;
|
|
2315
2333
|
}
|
|
2316
2334
|
async function withImmediateTransaction(db, config, fn, onRetry) {
|
|
2317
2335
|
let lastError;
|
|
2336
|
+
const startedAt = performance.now();
|
|
2318
2337
|
for (let attempt = 0; attempt <= config.maxRetries; attempt += 1) {
|
|
2338
|
+
if (attempt > 0 && deadlineExceeded(startedAt, config)) {
|
|
2339
|
+
break;
|
|
2340
|
+
}
|
|
2319
2341
|
try {
|
|
2320
2342
|
db.exec("BEGIN IMMEDIATE");
|
|
2321
2343
|
try {
|
|
@@ -2335,7 +2357,7 @@ async function withImmediateTransaction(db, config, fn, onRetry) {
|
|
|
2335
2357
|
if (!isBusy) {
|
|
2336
2358
|
throw error;
|
|
2337
2359
|
}
|
|
2338
|
-
if (attempt >= config.maxRetries) {
|
|
2360
|
+
if (attempt >= config.maxRetries || deadlineExceeded(startedAt, config)) {
|
|
2339
2361
|
break;
|
|
2340
2362
|
}
|
|
2341
2363
|
const delay = backoffDelay(attempt, config);
|
|
@@ -2348,7 +2370,7 @@ async function withImmediateTransaction(db, config, fn, onRetry) {
|
|
|
2348
2370
|
{
|
|
2349
2371
|
cause: lastError instanceof Error ? lastError : void 0,
|
|
2350
2372
|
reason: "SQLITE_BUSY exhausted retries",
|
|
2351
|
-
suggestion: "Increase concurrency.maxRetries
|
|
2373
|
+
suggestion: "Increase concurrency.maxRetries / concurrency.lockDeadlineMs, set concurrency.multiProcess: true for shared-file writers, or use the Postgres backend."
|
|
2352
2374
|
}
|
|
2353
2375
|
);
|
|
2354
2376
|
}
|
|
@@ -2406,6 +2428,20 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
2406
2428
|
transactionDepth = 0;
|
|
2407
2429
|
/** Incrementing counter for deterministic savepoint names. */
|
|
2408
2430
|
savepointCounter = 0;
|
|
2431
|
+
/**
|
|
2432
|
+
* Serializes top-level write transactions on the single SQLite connection.
|
|
2433
|
+
* SQLite is single-writer; serializing in-process avoids SQLITE_BUSY churn
|
|
2434
|
+
* AND prevents interleaved BEGIN/SAVEPOINT state corruption when many async
|
|
2435
|
+
* callers share one connection (see "no such savepoint" class of bugs).
|
|
2436
|
+
*/
|
|
2437
|
+
writeMutex = new AsyncMutex();
|
|
2438
|
+
/**
|
|
2439
|
+
* Async-context flag: true while executing inside a top-level write
|
|
2440
|
+
* transaction held by this provider. Used so writes issued from within an
|
|
2441
|
+
* ambient transaction (e.g. compress()) join that ACID unit, WITHOUT
|
|
2442
|
+
* mistaking the coalescer's own flush window for an ambient transaction.
|
|
2443
|
+
*/
|
|
2444
|
+
txContext = new async_hooks.AsyncLocalStorage();
|
|
2409
2445
|
/** Hot in-process ANN for blob backend (sqlite-vec unavailable platforms). */
|
|
2410
2446
|
memoryIndex = null;
|
|
2411
2447
|
memoryIndexDirty = false;
|
|
@@ -2448,62 +2484,85 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
2448
2484
|
}
|
|
2449
2485
|
/** Open the database, run migrations, and prepare statements. */
|
|
2450
2486
|
async open() {
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
this.sqliteVecLoaded = this.tryLoadSqliteVec(db);
|
|
2471
|
-
this.runMigrations(db);
|
|
2472
|
-
this.statements = this.prepareStatements(db);
|
|
2473
|
-
const backend = this.readMetaString(META_KEYS.vectorBackend);
|
|
2474
|
-
const dims = this.readMetaNumber(META_KEYS.embeddingDimensions);
|
|
2475
|
-
if (backend) {
|
|
2476
|
-
this.vectorBackend = backend;
|
|
2477
|
-
} else if (this.sqliteVecLoaded) {
|
|
2478
|
-
this.vectorBackend = "sqlite-vec";
|
|
2479
|
-
} else {
|
|
2480
|
-
if (!warnedSqliteVecFallback) {
|
|
2481
|
-
warnedSqliteVecFallback = true;
|
|
2482
|
-
warnLogger.warn(
|
|
2483
|
-
"sqlite-vec unavailable on this platform; using blob ANN fallback."
|
|
2487
|
+
const startedAt = performance.now();
|
|
2488
|
+
let attempt = 0;
|
|
2489
|
+
for (; ; ) {
|
|
2490
|
+
try {
|
|
2491
|
+
this.openOnce();
|
|
2492
|
+
return;
|
|
2493
|
+
} catch (error) {
|
|
2494
|
+
try {
|
|
2495
|
+
this.db?.close();
|
|
2496
|
+
} catch {
|
|
2497
|
+
}
|
|
2498
|
+
this.db = null;
|
|
2499
|
+
this.statements = null;
|
|
2500
|
+
const busy = isSqliteBusyError(error);
|
|
2501
|
+
const exhausted = attempt >= this.concurrency.maxRetries || performance.now() - startedAt >= this.concurrency.lockDeadlineMs;
|
|
2502
|
+
if (!busy || exhausted) {
|
|
2503
|
+
throw new InitializationError(
|
|
2504
|
+
`Failed to open SQLite database: ${this.describe(error)}`,
|
|
2505
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
2484
2506
|
);
|
|
2485
2507
|
}
|
|
2486
|
-
|
|
2508
|
+
const base = Math.min(
|
|
2509
|
+
this.concurrency.maxBackoffMs,
|
|
2510
|
+
this.concurrency.baseBackoffMs * 2 ** attempt
|
|
2511
|
+
);
|
|
2512
|
+
const delay = Math.random() * base;
|
|
2513
|
+
this.retryLog?.(
|
|
2514
|
+
`SQLITE_BUSY during open attempt=${attempt + 1} backoffMs=${Math.round(delay)}`
|
|
2515
|
+
);
|
|
2516
|
+
attempt += 1;
|
|
2517
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
2487
2518
|
}
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
/** Single open attempt — connect, apply pragmas, migrate, prepare. */
|
|
2522
|
+
openOnce() {
|
|
2523
|
+
const dbPath = this.resolvePath(this.connectionString);
|
|
2524
|
+
this.resolvedPath = dbPath;
|
|
2525
|
+
if (dbPath !== ":memory:") {
|
|
2526
|
+
fs6__default.default.mkdirSync(path7__default.default.dirname(dbPath), { recursive: true });
|
|
2527
|
+
}
|
|
2528
|
+
const db = new sqlite$1.DatabaseSync(dbPath, { allowExtension: true });
|
|
2529
|
+
this.db = db;
|
|
2530
|
+
db.exec(`PRAGMA busy_timeout = ${this.concurrency.lockTimeoutMs};`);
|
|
2531
|
+
db.exec("PRAGMA journal_mode = WAL;");
|
|
2532
|
+
db.exec(`
|
|
2533
|
+
PRAGMA synchronous = NORMAL;
|
|
2534
|
+
PRAGMA foreign_keys = ON;
|
|
2535
|
+
PRAGMA temp_store = MEMORY;
|
|
2536
|
+
PRAGMA cache_size = -32768;
|
|
2537
|
+
PRAGMA mmap_size = 134217728;
|
|
2538
|
+
PRAGMA wal_autocheckpoint = 2000;
|
|
2539
|
+
PRAGMA recursive_triggers = OFF;
|
|
2540
|
+
`);
|
|
2541
|
+
this.sqliteVecLoaded = this.tryLoadSqliteVec(db);
|
|
2542
|
+
this.runMigrations(db);
|
|
2543
|
+
this.statements = this.prepareStatements(db);
|
|
2544
|
+
const backend = this.readMetaString(META_KEYS.vectorBackend);
|
|
2545
|
+
const dims = this.readMetaNumber(META_KEYS.embeddingDimensions);
|
|
2546
|
+
if (backend) {
|
|
2547
|
+
this.vectorBackend = backend;
|
|
2548
|
+
} else if (this.sqliteVecLoaded) {
|
|
2549
|
+
this.vectorBackend = "sqlite-vec";
|
|
2550
|
+
} else {
|
|
2551
|
+
if (!warnedSqliteVecFallback) {
|
|
2552
|
+
warnedSqliteVecFallback = true;
|
|
2553
|
+
warnLogger.warn(
|
|
2554
|
+
"sqlite-vec unavailable on this platform; using blob ANN fallback."
|
|
2555
|
+
);
|
|
2495
2556
|
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2557
|
+
this.vectorBackend = "blob";
|
|
2558
|
+
}
|
|
2559
|
+
if (dims !== null) {
|
|
2560
|
+
this.vectorDimensions = dims;
|
|
2561
|
+
this.ensureVectorStorage(dims);
|
|
2562
|
+
this.reprepareVectorStatements();
|
|
2563
|
+
if (this.vectorBackend === "blob") {
|
|
2564
|
+
this.memoryIndexDirty = true;
|
|
2500
2565
|
}
|
|
2501
|
-
this.db = null;
|
|
2502
|
-
this.statements = null;
|
|
2503
|
-
throw new InitializationError(
|
|
2504
|
-
`Failed to open SQLite database: ${this.describe(error)}`,
|
|
2505
|
-
{ cause: error instanceof Error ? error : void 0 }
|
|
2506
|
-
);
|
|
2507
2566
|
}
|
|
2508
2567
|
}
|
|
2509
2568
|
/** Drain pending inserts, optimize, and close the SQLite connection. */
|
|
@@ -2576,8 +2635,11 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
2576
2635
|
/** Insert a single memory row (coalesced under concurrent writers). */
|
|
2577
2636
|
async insertMemory(input) {
|
|
2578
2637
|
this.requireVectorReady();
|
|
2579
|
-
|
|
2580
|
-
this.
|
|
2638
|
+
if (this.txContext.getStore() === true) {
|
|
2639
|
+
return this.insertMemoryImmediate(input);
|
|
2640
|
+
}
|
|
2641
|
+
return new Promise((resolve3, reject) => {
|
|
2642
|
+
this.insertQueue.push({ input, resolve: resolve3, reject });
|
|
2581
2643
|
if (this.insertQueue.length >= INSERT_COALESCE_THRESHOLD) {
|
|
2582
2644
|
this.insertFlushScheduled = false;
|
|
2583
2645
|
void this.flushInsertQueue();
|
|
@@ -2872,7 +2934,8 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
2872
2934
|
const stmts = this.requireStatements();
|
|
2873
2935
|
const archived = [];
|
|
2874
2936
|
return this.withTransaction(() => {
|
|
2875
|
-
|
|
2937
|
+
const orderedIds = [...new Set(ids)].sort();
|
|
2938
|
+
for (const id of orderedIds) {
|
|
2876
2939
|
const existing = stmts.getMemoryById.get(id, organization);
|
|
2877
2940
|
const result = stmts.archiveMemory.run(
|
|
2878
2941
|
compressedIntoId,
|
|
@@ -3013,7 +3076,7 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
3013
3076
|
}
|
|
3014
3077
|
async withTransaction(fn) {
|
|
3015
3078
|
const db = this.requireDb();
|
|
3016
|
-
if (this.
|
|
3079
|
+
if (this.txContext.getStore() === true) {
|
|
3017
3080
|
const savepointName = `wolbarg_sp_${this.savepointCounter++}`;
|
|
3018
3081
|
db.exec(`SAVEPOINT ${savepointName}`);
|
|
3019
3082
|
try {
|
|
@@ -3031,21 +3094,26 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
|
|
|
3031
3094
|
this.transactionDepth -= 1;
|
|
3032
3095
|
}
|
|
3033
3096
|
}
|
|
3034
|
-
this.
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3097
|
+
return this.writeMutex.runExclusive(
|
|
3098
|
+
() => this.txContext.run(true, async () => {
|
|
3099
|
+
this.transactionDepth = 1;
|
|
3100
|
+
this.savepointCounter = 0;
|
|
3101
|
+
try {
|
|
3102
|
+
return await withImmediateTransaction(
|
|
3103
|
+
db,
|
|
3104
|
+
this.concurrency,
|
|
3105
|
+
fn,
|
|
3106
|
+
(attempt, delayMs) => {
|
|
3107
|
+
this.retryLog?.(
|
|
3108
|
+
`SQLITE_BUSY retry attempt=${attempt} backoffMs=${Math.round(delayMs)}`
|
|
3109
|
+
);
|
|
3110
|
+
}
|
|
3043
3111
|
);
|
|
3112
|
+
} finally {
|
|
3113
|
+
this.transactionDepth = 0;
|
|
3044
3114
|
}
|
|
3045
|
-
)
|
|
3046
|
-
|
|
3047
|
-
this.transactionDepth = 0;
|
|
3048
|
-
}
|
|
3115
|
+
})
|
|
3116
|
+
);
|
|
3049
3117
|
}
|
|
3050
3118
|
// ─── internals ───────────────────────────────────────────────────────────
|
|
3051
3119
|
tryLoadSqliteVec(db) {
|
|
@@ -4212,8 +4280,20 @@ function createPostgresListenerFromPool(pool, onError) {
|
|
|
4212
4280
|
}
|
|
4213
4281
|
|
|
4214
4282
|
// src/storage/providers/postgres.ts
|
|
4215
|
-
var txStore = new async_hooks.AsyncLocalStorage();
|
|
4216
4283
|
var warnLogger2 = new WolbargLogger("warn");
|
|
4284
|
+
function isRetriablePgTxError(error) {
|
|
4285
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code ?? "") : "";
|
|
4286
|
+
if (code === "40P01" || code === "40001") {
|
|
4287
|
+
return true;
|
|
4288
|
+
}
|
|
4289
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
4290
|
+
return /deadlock detected|could not serialize access/i.test(msg);
|
|
4291
|
+
}
|
|
4292
|
+
function pgTxBackoffMs(attempt) {
|
|
4293
|
+
const base = 25 * 2 ** attempt;
|
|
4294
|
+
const jitter = Math.random() * 25;
|
|
4295
|
+
return Math.min(1e3, base + jitter);
|
|
4296
|
+
}
|
|
4217
4297
|
var warnedPgvectorFallback = false;
|
|
4218
4298
|
var warnedFtsKeywordSearch2 = false;
|
|
4219
4299
|
var warnedHnswSoftFail = false;
|
|
@@ -4258,7 +4338,11 @@ function withPoolStartupOptions(connectionString, durableWrites) {
|
|
|
4258
4338
|
"-c jit=off",
|
|
4259
4339
|
// Bake HNSW search GUCs into the connection — avoids per-recall set_config.
|
|
4260
4340
|
"-c hnsw.ef_search=40",
|
|
4261
|
-
"-c hnsw.iterative_scan=relaxed_order"
|
|
4341
|
+
"-c hnsw.iterative_scan=relaxed_order",
|
|
4342
|
+
// Bound waits so lock storms cannot hang agents indefinitely.
|
|
4343
|
+
"-c statement_timeout=30000",
|
|
4344
|
+
"-c lock_timeout=10000",
|
|
4345
|
+
"-c idle_in_transaction_session_timeout=60000"
|
|
4262
4346
|
];
|
|
4263
4347
|
if (!durableWrites) {
|
|
4264
4348
|
flags.unshift("-c synchronous_commit=off");
|
|
@@ -4339,6 +4423,8 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
4339
4423
|
insertFlushScheduled = false;
|
|
4340
4424
|
insertFlushTimer = null;
|
|
4341
4425
|
insertFlushInFlight = 0;
|
|
4426
|
+
/** Per-provider TX context — never share across PostgresStorageProvider instances. */
|
|
4427
|
+
txStore = new async_hooks.AsyncLocalStorage();
|
|
4342
4428
|
/**
|
|
4343
4429
|
* @param options - Connection string, pool size, and durability flags.
|
|
4344
4430
|
*/
|
|
@@ -4638,8 +4724,11 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
4638
4724
|
/** Insert a single memory row (coalesced under concurrent writers). */
|
|
4639
4725
|
async insertMemory(input) {
|
|
4640
4726
|
this.requireVectorReady();
|
|
4641
|
-
|
|
4642
|
-
this.
|
|
4727
|
+
if (this.txStore.getStore()) {
|
|
4728
|
+
return this.insertMemoryImmediate(input);
|
|
4729
|
+
}
|
|
4730
|
+
return new Promise((resolve3, reject) => {
|
|
4731
|
+
this.insertQueue.push({ input, resolve: resolve3, reject });
|
|
4643
4732
|
if (this.insertQueue.length >= COALESCE_FLUSH_THRESHOLD) {
|
|
4644
4733
|
this.clearInsertFlushTimer();
|
|
4645
4734
|
void this.flushInsertQueue();
|
|
@@ -4874,10 +4963,18 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
4874
4963
|
/** Update memory content, metadata, embedding, and content hash. */
|
|
4875
4964
|
async updateMemory(input) {
|
|
4876
4965
|
return this.withTransaction(async () => {
|
|
4877
|
-
const
|
|
4878
|
-
|
|
4966
|
+
const locked = await this.query(
|
|
4967
|
+
`SELECT id, organization, agent, content_text, metadata_json,
|
|
4968
|
+
archived::int AS archived, compressed_into, content_hash, created_at, updated_at
|
|
4969
|
+
FROM memories
|
|
4970
|
+
WHERE id = $1 AND organization = $2
|
|
4971
|
+
FOR UPDATE`,
|
|
4972
|
+
[input.id, input.organization]
|
|
4973
|
+
);
|
|
4974
|
+
if (locked.rows.length === 0) {
|
|
4879
4975
|
return null;
|
|
4880
4976
|
}
|
|
4977
|
+
const existing = this.mapRow(locked.rows[0]);
|
|
4881
4978
|
const contentHash = input.contentHash !== void 0 ? input.contentHash : input.contentText !== void 0 ? hashMemoryContent(input.contentText) : existing.content_hash ?? null;
|
|
4882
4979
|
await this.query(
|
|
4883
4980
|
`UPDATE memories SET
|
|
@@ -5195,23 +5292,38 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
5195
5292
|
if (ids.length === 0) {
|
|
5196
5293
|
return [];
|
|
5197
5294
|
}
|
|
5295
|
+
const orderedIds = [...new Set(ids)].sort();
|
|
5296
|
+
await this.query(
|
|
5297
|
+
`SELECT id FROM memories
|
|
5298
|
+
WHERE organization = $1 AND archived = false AND id = ANY($2::text[])
|
|
5299
|
+
ORDER BY id
|
|
5300
|
+
FOR UPDATE`,
|
|
5301
|
+
[organization, orderedIds]
|
|
5302
|
+
);
|
|
5198
5303
|
const result = await this.query(
|
|
5199
5304
|
`UPDATE memories
|
|
5200
5305
|
SET archived = true, compressed_into = $1, updated_at = $2
|
|
5201
5306
|
WHERE organization = $3 AND archived = false AND id = ANY($4::text[])
|
|
5202
5307
|
RETURNING id`,
|
|
5203
|
-
[compressedIntoId, archivedAt, organization,
|
|
5308
|
+
[compressedIntoId, archivedAt, organization, orderedIds]
|
|
5204
5309
|
);
|
|
5205
5310
|
const archived = result.rows.map((r) => String(r.id));
|
|
5206
5311
|
if (archived.length === 0) {
|
|
5207
5312
|
return [];
|
|
5208
5313
|
}
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5314
|
+
if (this.hasPgvector) {
|
|
5315
|
+
await this.query(
|
|
5316
|
+
`UPDATE memory_embeddings
|
|
5317
|
+
SET archived = true
|
|
5318
|
+
WHERE memory_id = ANY($1::text[])`,
|
|
5319
|
+
[archived]
|
|
5320
|
+
);
|
|
5321
|
+
} else {
|
|
5322
|
+
await this.query(
|
|
5323
|
+
`DELETE FROM memory_embeddings_blob WHERE memory_id = ANY($1::text[])`,
|
|
5324
|
+
[archived]
|
|
5325
|
+
);
|
|
5326
|
+
}
|
|
5215
5327
|
const histIds = [];
|
|
5216
5328
|
const memIds = [];
|
|
5217
5329
|
const types = [];
|
|
@@ -5314,27 +5426,40 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
5314
5426
|
return Number(result.rows[0]?.size ?? 0);
|
|
5315
5427
|
}
|
|
5316
5428
|
async withTransaction(fn) {
|
|
5317
|
-
const existing = txStore.getStore();
|
|
5429
|
+
const existing = this.txStore.getStore();
|
|
5318
5430
|
if (existing) {
|
|
5319
5431
|
return fn();
|
|
5320
5432
|
}
|
|
5321
|
-
const
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
const
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5433
|
+
const maxAttempts = 5;
|
|
5434
|
+
let lastError;
|
|
5435
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
5436
|
+
const client = await this.requirePool().connect();
|
|
5437
|
+
try {
|
|
5438
|
+
await client.query("BEGIN");
|
|
5439
|
+
const result = await this.txStore.run(client, fn);
|
|
5440
|
+
await client.query("COMMIT");
|
|
5441
|
+
return result;
|
|
5442
|
+
} catch (error) {
|
|
5443
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
5444
|
+
lastError = error;
|
|
5445
|
+
if (isRetriablePgTxError(error) && attempt < maxAttempts - 1) {
|
|
5446
|
+
await new Promise((r) => setTimeout(r, pgTxBackoffMs(attempt)));
|
|
5447
|
+
continue;
|
|
5448
|
+
}
|
|
5449
|
+
if (error instanceof DatabaseError || error instanceof InitializationError) {
|
|
5450
|
+
throw error;
|
|
5451
|
+
}
|
|
5452
|
+
throw new DatabaseError(`Transaction failed: ${this.describe(error)}`, {
|
|
5453
|
+
cause: error instanceof Error ? error : void 0
|
|
5454
|
+
});
|
|
5455
|
+
} finally {
|
|
5456
|
+
client.release();
|
|
5331
5457
|
}
|
|
5332
|
-
throw new DatabaseError(`Transaction failed: ${this.describe(error)}`, {
|
|
5333
|
-
cause: error instanceof Error ? error : void 0
|
|
5334
|
-
});
|
|
5335
|
-
} finally {
|
|
5336
|
-
client.release();
|
|
5337
5458
|
}
|
|
5459
|
+
throw new DatabaseError(
|
|
5460
|
+
`Transaction failed after retries: ${this.describe(lastError)}`,
|
|
5461
|
+
{ cause: lastError instanceof Error ? lastError : void 0 }
|
|
5462
|
+
);
|
|
5338
5463
|
}
|
|
5339
5464
|
async runMigrations() {
|
|
5340
5465
|
await this.query(`
|
|
@@ -5562,13 +5687,13 @@ var PostgresStorageProvider = class _PostgresStorageProvider {
|
|
|
5562
5687
|
await this.query(`DELETE FROM memory_embeddings_blob WHERE memory_id = $1`, [memoryId]).catch(() => void 0);
|
|
5563
5688
|
}
|
|
5564
5689
|
async query(text, params) {
|
|
5565
|
-
const tx = txStore.getStore();
|
|
5690
|
+
const tx = this.txStore.getStore();
|
|
5566
5691
|
const target = tx ?? this.requirePool();
|
|
5567
5692
|
return target.query(text, params);
|
|
5568
5693
|
}
|
|
5569
5694
|
/** Named prepared statement — parse/plan cached per pool connection. */
|
|
5570
5695
|
async queryNamed(name, text, params) {
|
|
5571
|
-
const tx = txStore.getStore();
|
|
5696
|
+
const tx = this.txStore.getStore();
|
|
5572
5697
|
const target = tx ?? this.requirePool();
|
|
5573
5698
|
return target.query({ name, text, values: params });
|
|
5574
5699
|
}
|
|
@@ -5654,7 +5779,7 @@ function createDatabaseProvider(config) {
|
|
|
5654
5779
|
}
|
|
5655
5780
|
|
|
5656
5781
|
// src/version.ts
|
|
5657
|
-
var SDK_VERSION = "0.5.
|
|
5782
|
+
var SDK_VERSION = "0.5.6";
|
|
5658
5783
|
|
|
5659
5784
|
// src/memory/transfer.ts
|
|
5660
5785
|
var warnedMissingExportManifest = false;
|
|
@@ -9610,12 +9735,18 @@ var Wolbarg = class {
|
|
|
9610
9735
|
createdAt: timestamp,
|
|
9611
9736
|
updatedAt: timestamp
|
|
9612
9737
|
});
|
|
9738
|
+
const sourceIds = [...records.map((r) => r.id)].sort();
|
|
9613
9739
|
const archivedIds = await storage.archiveMemories(
|
|
9614
|
-
|
|
9740
|
+
sourceIds,
|
|
9615
9741
|
organization,
|
|
9616
9742
|
summaryId,
|
|
9617
9743
|
timestamp
|
|
9618
9744
|
);
|
|
9745
|
+
if (archivedIds.length < 2) {
|
|
9746
|
+
throw new ValidationError(
|
|
9747
|
+
"compress lost a concurrency race: fewer than 2 source memories remained active"
|
|
9748
|
+
);
|
|
9749
|
+
}
|
|
9619
9750
|
return {
|
|
9620
9751
|
summary: toMemoryRecord(summaryRow),
|
|
9621
9752
|
archivedIds
|
|
@@ -10627,8 +10758,11 @@ var meta = {
|
|
|
10627
10758
|
};
|
|
10628
10759
|
|
|
10629
10760
|
// src/factories/index.ts
|
|
10630
|
-
function sqlite(connectionString) {
|
|
10631
|
-
return new SqliteStorageProvider({
|
|
10761
|
+
function sqlite(connectionString, options) {
|
|
10762
|
+
return new SqliteStorageProvider({
|
|
10763
|
+
connectionString,
|
|
10764
|
+
concurrency: options?.concurrency
|
|
10765
|
+
});
|
|
10632
10766
|
}
|
|
10633
10767
|
function sqliteConfig(connectionString) {
|
|
10634
10768
|
return {
|
|
@@ -11145,9 +11279,279 @@ function percentile(sorted, p) {
|
|
|
11145
11279
|
return sorted[idx];
|
|
11146
11280
|
}
|
|
11147
11281
|
|
|
11282
|
+
// src/config/providers.ts
|
|
11283
|
+
var EMBEDDING_PROVIDER_PRESETS = [
|
|
11284
|
+
{
|
|
11285
|
+
id: "openai",
|
|
11286
|
+
label: "OpenAI",
|
|
11287
|
+
defaultBaseUrl: "https://api.openai.com/v1",
|
|
11288
|
+
defaultModel: "text-embedding-3-small",
|
|
11289
|
+
apiKeyEnv: "OPENAI_API_KEY"
|
|
11290
|
+
},
|
|
11291
|
+
{
|
|
11292
|
+
id: "ollama",
|
|
11293
|
+
label: "Ollama (local)",
|
|
11294
|
+
defaultBaseUrl: "http://127.0.0.1:11434/v1",
|
|
11295
|
+
defaultModel: "nomic-embed-text",
|
|
11296
|
+
apiKeyEnv: "OLLAMA_API_KEY",
|
|
11297
|
+
apiKeyHint: "Any non-empty value works locally (e.g. ollama)"
|
|
11298
|
+
},
|
|
11299
|
+
{
|
|
11300
|
+
id: "openrouter",
|
|
11301
|
+
label: "OpenRouter",
|
|
11302
|
+
defaultBaseUrl: "https://openrouter.ai/api/v1",
|
|
11303
|
+
defaultModel: "openai/text-embedding-3-small",
|
|
11304
|
+
apiKeyEnv: "OPENROUTER_API_KEY"
|
|
11305
|
+
},
|
|
11306
|
+
{
|
|
11307
|
+
id: "lmstudio",
|
|
11308
|
+
label: "LM Studio (local)",
|
|
11309
|
+
defaultBaseUrl: "http://127.0.0.1:1234/v1",
|
|
11310
|
+
defaultModel: "text-embedding-nomic-embed-text-v1.5",
|
|
11311
|
+
apiKeyEnv: "LM_STUDIO_API_KEY",
|
|
11312
|
+
apiKeyHint: "Often unused locally \u2014 any non-empty value is fine"
|
|
11313
|
+
},
|
|
11314
|
+
{
|
|
11315
|
+
id: "gemini",
|
|
11316
|
+
label: "Google Gemini",
|
|
11317
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
11318
|
+
defaultModel: "text-embedding-004",
|
|
11319
|
+
apiKeyEnv: "GEMINI_API_KEY"
|
|
11320
|
+
},
|
|
11321
|
+
{
|
|
11322
|
+
id: "together",
|
|
11323
|
+
label: "Together AI",
|
|
11324
|
+
defaultBaseUrl: "https://api.together.xyz/v1",
|
|
11325
|
+
defaultModel: "togethercomputer/m2-bert-80M-8k-retrieval",
|
|
11326
|
+
apiKeyEnv: "TOGETHER_API_KEY"
|
|
11327
|
+
},
|
|
11328
|
+
{
|
|
11329
|
+
id: "vllm",
|
|
11330
|
+
label: "vLLM (local/server)",
|
|
11331
|
+
defaultBaseUrl: "http://127.0.0.1:8000/v1",
|
|
11332
|
+
defaultModel: "text-embedding-ada-002",
|
|
11333
|
+
apiKeyEnv: "VLLM_API_KEY",
|
|
11334
|
+
apiKeyHint: "Only if your server requires auth"
|
|
11335
|
+
},
|
|
11336
|
+
{
|
|
11337
|
+
id: "custom",
|
|
11338
|
+
label: "Custom OpenAI-compatible",
|
|
11339
|
+
defaultBaseUrl: "https://api.openai.com/v1",
|
|
11340
|
+
defaultModel: "text-embedding-3-small",
|
|
11341
|
+
apiKeyEnv: "WOLBARG_EMBEDDING_API_KEY"
|
|
11342
|
+
}
|
|
11343
|
+
];
|
|
11344
|
+
function getEmbeddingProviderPreset(id) {
|
|
11345
|
+
return EMBEDDING_PROVIDER_PRESETS.find((p) => p.id === id);
|
|
11346
|
+
}
|
|
11347
|
+
var DEFAULT_SQLITE_DB_PATH = ".wolbarg/shared-memory/memory.db";
|
|
11348
|
+
var DEFAULT_ORGANIZATION = "default";
|
|
11349
|
+
var DEFAULT_CONFIG_PATH = ".wolbarg/config.json";
|
|
11350
|
+
var DEFAULT_ENV_PATH = ".wolbarg/.env";
|
|
11351
|
+
function defaultProjectConfig() {
|
|
11352
|
+
return {
|
|
11353
|
+
version: 1,
|
|
11354
|
+
organization: DEFAULT_ORGANIZATION,
|
|
11355
|
+
database: {
|
|
11356
|
+
provider: "sqlite",
|
|
11357
|
+
url: DEFAULT_SQLITE_DB_PATH
|
|
11358
|
+
},
|
|
11359
|
+
paths: {
|
|
11360
|
+
config: DEFAULT_CONFIG_PATH
|
|
11361
|
+
}
|
|
11362
|
+
};
|
|
11363
|
+
}
|
|
11364
|
+
function resolveConfigPath(cwd = process.cwd(), configPath) {
|
|
11365
|
+
const rel = configPath ?? DEFAULT_CONFIG_PATH;
|
|
11366
|
+
return path7.isAbsolute(rel) ? rel : path7.resolve(cwd, rel);
|
|
11367
|
+
}
|
|
11368
|
+
function resolveEnvPath(cwd = process.cwd(), envPath) {
|
|
11369
|
+
const rel = envPath ?? DEFAULT_ENV_PATH;
|
|
11370
|
+
return path7.isAbsolute(rel) ? rel : path7.resolve(cwd, rel);
|
|
11371
|
+
}
|
|
11372
|
+
function loadProjectConfig(cwd = process.cwd(), configPath) {
|
|
11373
|
+
const full = resolveConfigPath(cwd, configPath);
|
|
11374
|
+
if (!fs6.existsSync(full)) return null;
|
|
11375
|
+
const raw = JSON.parse(fs6.readFileSync(full, "utf8"));
|
|
11376
|
+
if (!raw || raw.version !== 1 || !raw.database?.url) {
|
|
11377
|
+
throw new Error(`Invalid Wolbarg config at ${full}`);
|
|
11378
|
+
}
|
|
11379
|
+
return raw;
|
|
11380
|
+
}
|
|
11381
|
+
function saveProjectConfig(config, options = {}) {
|
|
11382
|
+
const cwd = options.cwd ?? process.cwd();
|
|
11383
|
+
const configPath = resolveConfigPath(cwd, options.configPath);
|
|
11384
|
+
const dir = path7.dirname(configPath);
|
|
11385
|
+
if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
|
|
11386
|
+
if (fs6.existsSync(configPath) && options.overwrite === false) {
|
|
11387
|
+
throw new Error(`Config already exists: ${configPath} (pass --force to overwrite)`);
|
|
11388
|
+
}
|
|
11389
|
+
const toWrite = {
|
|
11390
|
+
...config,
|
|
11391
|
+
paths: {
|
|
11392
|
+
config: options.configPath ?? DEFAULT_CONFIG_PATH,
|
|
11393
|
+
...options.envPath || options.apiKey ? { env: options.envPath ?? DEFAULT_ENV_PATH } : config.paths?.env ? { env: config.paths.env } : {}
|
|
11394
|
+
}
|
|
11395
|
+
};
|
|
11396
|
+
fs6.writeFileSync(configPath, `${JSON.stringify(toWrite, null, 2)}
|
|
11397
|
+
`, "utf8");
|
|
11398
|
+
let envPath;
|
|
11399
|
+
if (options.apiKey && config.embedding?.apiKeyEnv) {
|
|
11400
|
+
envPath = resolveEnvPath(cwd, options.envPath);
|
|
11401
|
+
ensureParent(envPath);
|
|
11402
|
+
upsertEnvVar(envPath, config.embedding.apiKeyEnv, options.apiKey);
|
|
11403
|
+
ensureGitignore(cwd, [DEFAULT_ENV_PATH, ".env"]);
|
|
11404
|
+
}
|
|
11405
|
+
if (config.database.provider === "sqlite" && !config.database.url.includes("://")) {
|
|
11406
|
+
const dbPath = path7.isAbsolute(config.database.url) ? config.database.url : path7.resolve(cwd, config.database.url);
|
|
11407
|
+
ensureParent(dbPath);
|
|
11408
|
+
}
|
|
11409
|
+
return { configPath, envPath };
|
|
11410
|
+
}
|
|
11411
|
+
function ensureParent(filePath) {
|
|
11412
|
+
const dir = path7.dirname(filePath);
|
|
11413
|
+
if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
|
|
11414
|
+
}
|
|
11415
|
+
function upsertEnvVar(envPath, key, value) {
|
|
11416
|
+
ensureParent(envPath);
|
|
11417
|
+
let text = fs6.existsSync(envPath) ? fs6.readFileSync(envPath, "utf8") : "";
|
|
11418
|
+
const line = `${key}=${shellQuoteEnv(value)}`;
|
|
11419
|
+
const re = new RegExp(`^${escapeRegExp(key)}=.*$`, "m");
|
|
11420
|
+
if (re.test(text)) {
|
|
11421
|
+
text = text.replace(re, line);
|
|
11422
|
+
} else {
|
|
11423
|
+
if (text && !text.endsWith("\n")) text += "\n";
|
|
11424
|
+
text += `${line}
|
|
11425
|
+
`;
|
|
11426
|
+
}
|
|
11427
|
+
fs6.writeFileSync(envPath, text, "utf8");
|
|
11428
|
+
}
|
|
11429
|
+
function shellQuoteEnv(value) {
|
|
11430
|
+
if (/[\s#"']/.test(value)) {
|
|
11431
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
11432
|
+
}
|
|
11433
|
+
return value;
|
|
11434
|
+
}
|
|
11435
|
+
function escapeRegExp(s) {
|
|
11436
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11437
|
+
}
|
|
11438
|
+
function ensureGitignore(cwd, entries) {
|
|
11439
|
+
const gi = path7.join(cwd, ".gitignore");
|
|
11440
|
+
let text = fs6.existsSync(gi) ? fs6.readFileSync(gi, "utf8") : "";
|
|
11441
|
+
let changed = false;
|
|
11442
|
+
for (const entry of entries) {
|
|
11443
|
+
if (text.split(/\r?\n/).some((l) => l.trim() === entry)) continue;
|
|
11444
|
+
if (text && !text.endsWith("\n")) text += "\n";
|
|
11445
|
+
text += `${entry}
|
|
11446
|
+
`;
|
|
11447
|
+
changed = true;
|
|
11448
|
+
}
|
|
11449
|
+
if (changed) fs6.writeFileSync(gi, text, "utf8");
|
|
11450
|
+
}
|
|
11451
|
+
function resolveEmbeddingApiKey(config, env = process.env) {
|
|
11452
|
+
const name = config.embedding?.apiKeyEnv;
|
|
11453
|
+
if (!name) return "";
|
|
11454
|
+
return env[name] ?? "";
|
|
11455
|
+
}
|
|
11456
|
+
function assertEmbeddingPreset(provider) {
|
|
11457
|
+
const preset = getEmbeddingProviderPreset(provider);
|
|
11458
|
+
if (!preset) {
|
|
11459
|
+
throw new Error(
|
|
11460
|
+
`Unknown embedding provider "${provider}". Choose one of: ${[
|
|
11461
|
+
"openai",
|
|
11462
|
+
"ollama",
|
|
11463
|
+
"openrouter",
|
|
11464
|
+
"lmstudio",
|
|
11465
|
+
"gemini",
|
|
11466
|
+
"together",
|
|
11467
|
+
"vllm",
|
|
11468
|
+
"custom"
|
|
11469
|
+
].join(", ")}`
|
|
11470
|
+
);
|
|
11471
|
+
}
|
|
11472
|
+
return preset.id;
|
|
11473
|
+
}
|
|
11474
|
+
function applyEnvFile(envPath, base = {}) {
|
|
11475
|
+
const out = { ...base };
|
|
11476
|
+
if (!fs6.existsSync(envPath)) return out;
|
|
11477
|
+
const text = fs6.readFileSync(envPath, "utf8");
|
|
11478
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
11479
|
+
const line = rawLine.trim();
|
|
11480
|
+
if (!line || line.startsWith("#")) continue;
|
|
11481
|
+
const eq = line.indexOf("=");
|
|
11482
|
+
if (eq <= 0) continue;
|
|
11483
|
+
const key = line.slice(0, eq).trim();
|
|
11484
|
+
let value = line.slice(eq + 1).trim();
|
|
11485
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
11486
|
+
value = value.slice(1, -1);
|
|
11487
|
+
}
|
|
11488
|
+
if (out[key] === void 0) out[key] = value;
|
|
11489
|
+
}
|
|
11490
|
+
return out;
|
|
11491
|
+
}
|
|
11492
|
+
function projectConfigToWolbargOptions(config, env = process.env) {
|
|
11493
|
+
if (!config.embedding) {
|
|
11494
|
+
throw new Error(
|
|
11495
|
+
"Project config has no embedding section. Re-run `wolbarg init` and configure an embedding provider, or pass embedding explicitly to wolbarg()."
|
|
11496
|
+
);
|
|
11497
|
+
}
|
|
11498
|
+
const apiKey = resolveEmbeddingApiKey(config, env);
|
|
11499
|
+
if (!apiKey) {
|
|
11500
|
+
throw new Error(
|
|
11501
|
+
`Missing API key. Set ${config.embedding.apiKeyEnv} in the environment or in .wolbarg/.env (from wolbarg init).`
|
|
11502
|
+
);
|
|
11503
|
+
}
|
|
11504
|
+
const dbUrl = config.database.url;
|
|
11505
|
+
return {
|
|
11506
|
+
organization: config.organization,
|
|
11507
|
+
database: {
|
|
11508
|
+
provider: config.database.provider,
|
|
11509
|
+
url: dbUrl,
|
|
11510
|
+
connectionString: dbUrl
|
|
11511
|
+
},
|
|
11512
|
+
embedding: {
|
|
11513
|
+
baseUrl: config.embedding.baseUrl,
|
|
11514
|
+
apiKey,
|
|
11515
|
+
model: config.embedding.model
|
|
11516
|
+
}
|
|
11517
|
+
};
|
|
11518
|
+
}
|
|
11519
|
+
function createWolbargFromProjectConfig(options = {}) {
|
|
11520
|
+
const cwd = options.cwd ?? process.cwd();
|
|
11521
|
+
const config = loadProjectConfig(cwd, options.configPath);
|
|
11522
|
+
if (!config) {
|
|
11523
|
+
throw new Error(
|
|
11524
|
+
`No Wolbarg config found. Run \`wolbarg init\` in ${cwd} (expected .wolbarg/config.json).`
|
|
11525
|
+
);
|
|
11526
|
+
}
|
|
11527
|
+
let env = options.env ?? { ...process.env };
|
|
11528
|
+
if (options.loadEnvFile !== false) {
|
|
11529
|
+
const envFile = resolveEnvPath(
|
|
11530
|
+
cwd,
|
|
11531
|
+
config.paths?.env ?? DEFAULT_ENV_PATH
|
|
11532
|
+
);
|
|
11533
|
+
env = applyEnvFile(envFile, env);
|
|
11534
|
+
}
|
|
11535
|
+
if (options.organization) {
|
|
11536
|
+
config.organization = options.organization;
|
|
11537
|
+
}
|
|
11538
|
+
if (config.database.provider === "sqlite" && !config.database.url.includes("://") && !path7.isAbsolute(config.database.url)) {
|
|
11539
|
+
config.database = {
|
|
11540
|
+
...config.database,
|
|
11541
|
+
url: path7.resolve(cwd, config.database.url)
|
|
11542
|
+
};
|
|
11543
|
+
}
|
|
11544
|
+
return wolbarg(projectConfigToWolbargOptions(config, env));
|
|
11545
|
+
}
|
|
11546
|
+
|
|
11148
11547
|
exports.CompressionError = CompressionError;
|
|
11149
11548
|
exports.ConfigurationError = ConfigurationError;
|
|
11549
|
+
exports.DEFAULT_CONFIG_PATH = DEFAULT_CONFIG_PATH;
|
|
11550
|
+
exports.DEFAULT_ENV_PATH = DEFAULT_ENV_PATH;
|
|
11551
|
+
exports.DEFAULT_ORGANIZATION = DEFAULT_ORGANIZATION;
|
|
11552
|
+
exports.DEFAULT_SQLITE_DB_PATH = DEFAULT_SQLITE_DB_PATH;
|
|
11150
11553
|
exports.DatabaseError = DatabaseError;
|
|
11554
|
+
exports.EMBEDDING_PROVIDER_PRESETS = EMBEDDING_PROVIDER_PRESETS;
|
|
11151
11555
|
exports.EmbeddingError = EmbeddingError;
|
|
11152
11556
|
exports.FixedChunkingStrategy = FixedChunkingStrategy;
|
|
11153
11557
|
exports.GraphCheckpointNotSupportedError = GraphCheckpointNotSupportedError;
|
|
@@ -11175,6 +11579,8 @@ exports.ValidationError = ValidationError;
|
|
|
11175
11579
|
exports.Wolbarg = Wolbarg;
|
|
11176
11580
|
exports.WolbargError = WolbargError;
|
|
11177
11581
|
exports.WolbargLogger = WolbargLogger;
|
|
11582
|
+
exports.applyEnvFile = applyEnvFile;
|
|
11583
|
+
exports.assertEmbeddingPreset = assertEmbeddingPreset;
|
|
11178
11584
|
exports.bgeReranker = bgeReranker;
|
|
11179
11585
|
exports.bm25 = bm25;
|
|
11180
11586
|
exports.cohereReranker = cohereReranker;
|
|
@@ -11186,11 +11592,15 @@ exports.createLlmProvider = createLlmProvider;
|
|
|
11186
11592
|
exports.createStorageProvider = createStorageProvider;
|
|
11187
11593
|
exports.createTelemetryProvider = createTelemetryProvider;
|
|
11188
11594
|
exports.createWolbarg = createWolbarg;
|
|
11595
|
+
exports.createWolbargFromProjectConfig = createWolbargFromProjectConfig;
|
|
11189
11596
|
exports.crossEncoder = crossEncoder;
|
|
11597
|
+
exports.defaultProjectConfig = defaultProjectConfig;
|
|
11190
11598
|
exports.geminiEmbedding = geminiEmbedding;
|
|
11191
11599
|
exports.geminiVision = geminiVision;
|
|
11600
|
+
exports.getEmbeddingProviderPreset = getEmbeddingProviderPreset;
|
|
11192
11601
|
exports.jinaReranker = jinaReranker;
|
|
11193
11602
|
exports.lmStudioEmbedding = lmStudioEmbedding;
|
|
11603
|
+
exports.loadProjectConfig = loadProjectConfig;
|
|
11194
11604
|
exports.meta = meta;
|
|
11195
11605
|
exports.neo4jGraph = neo4jGraph;
|
|
11196
11606
|
exports.ollamaEmbedding = ollamaEmbedding;
|
|
@@ -11205,7 +11615,12 @@ exports.openaiReranker = openaiReranker;
|
|
|
11205
11615
|
exports.openaiVision = openaiVision;
|
|
11206
11616
|
exports.postgres = postgres;
|
|
11207
11617
|
exports.postgresConfig = postgresConfig;
|
|
11618
|
+
exports.projectConfigToWolbargOptions = projectConfigToWolbargOptions;
|
|
11619
|
+
exports.resolveConfigPath = resolveConfigPath;
|
|
11620
|
+
exports.resolveEmbeddingApiKey = resolveEmbeddingApiKey;
|
|
11621
|
+
exports.resolveEnvPath = resolveEnvPath;
|
|
11208
11622
|
exports.runBenchmark = runBenchmark;
|
|
11623
|
+
exports.saveProjectConfig = saveProjectConfig;
|
|
11209
11624
|
exports.sqlite = sqlite;
|
|
11210
11625
|
exports.sqliteCheckpoint = sqliteCheckpoint;
|
|
11211
11626
|
exports.sqliteConfig = sqliteConfig;
|
|
@@ -11214,6 +11629,7 @@ exports.sqliteTelemetry = sqliteTelemetry;
|
|
|
11214
11629
|
exports.summarizeBenchmark = summarizeBenchmark;
|
|
11215
11630
|
exports.tesseract = tesseract;
|
|
11216
11631
|
exports.togetherEmbedding = togetherEmbedding;
|
|
11632
|
+
exports.upsertEnvVar = upsertEnvVar;
|
|
11217
11633
|
exports.vllmEmbedding = vllmEmbedding;
|
|
11218
11634
|
exports.wolbarg = wolbarg;
|
|
11219
11635
|
exports.wrapOperationError = wrapOperationError;
|